CI integration
Run the same labwired test command on your laptop and in GitHub Actions or GitLab. Pin a CLI release so firmware changes are judged by a fixed simulator version.
Default pin used in examples: v0.22.2.
Local first
curl -fsSL https://labwired.com/install.sh | LABWIRED_VERSION=v0.22.2 sh
labwired test \
--script tests/firmware-test.yaml \
--output-dir out/labwired \
--junit out/labwired/junit.xml
Exit 0 = pass. Non-zero = fail. Typical artifacts: result.json, uart.log, JUnit XML.
Product page: labwired.com/ci.
GitHub Actions
Use the public action from w1ne/labwired-core. Pin both the action commit and the CLI version.
name: Firmware simulation
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build firmware
run: # your normal firmware build; produce an ELF or flash image
- id: labwired
name: Run LabWired
uses: w1ne/labwired-core/.github/actions/labwired-test@75a3d9e906bab90fc0281d1dd786fe479a910d48
with:
script: tests/firmware-test.yaml
version: v0.22.2
output-dir: out/labwired
args: --no-uart-stdout
- name: Link the automatic LabWired artifact
if: always()
run: echo "${{ steps.labwired.outputs.artifact-url }}" >> "$GITHUB_STEP_SUMMARY"
The public action reference is an immutable action-source pin to
75a3d9e906bab90fc0281d1dd786fe479a910d48. Inputs: script (required), version
(default v0.22.2), output-dir, and args. The action downloads that CLI
release, writes JUnit to output-dir/junit.xml, appends summary.md to the job
summary, and always uploads the output directory (including on failure).
Outputs: status, summary-md, report-html, artifact-url, exit-code
(via the labwired step id).
Container runner
The release image uses labwired as the entrypoint. Pass test after the image
name — do not repeat labwired in the container command:
docker run --rm \
--user "$(id -u):$(id -g)" \
--volume "$PWD:/workspace" \
--workdir /workspace \
ghcr.io/w1ne/labwired:v0.22.2 \
test --script tests/firmware-test.yaml \
--output-dir out/labwired \
--no-uart-stdout
When you bind-mount a workspace, pass the caller UID/GID so generated artifacts stay writable on the host.
GitLab CI
Clear the image entrypoint so GitLab can start its job shell. See integration-templates/gitlab-ci.yml:
test:firmware:
image:
name: ghcr.io/w1ne/labwired:v0.22.2
entrypoint: [""]
script:
- labwired test --script tests/firmware-test.yaml --output-dir out/labwired --no-uart-stdout
Artifacts
Use --output-dir everywhere. A run writes result.json, uart.log, and JUnit
under that directory. The GitHub action always uploads the directory; other CI
systems should retain it on failure.
Advanced: build from source
cargo build --release -p labwired-cli
./target/release/labwired test \
--script tests/firmware-test.yaml \
--output-dir out/labwired
More templates: integration templates.
What to assert
Use the test script schema: UART substrings, register values, stop reasons, step limits. Prefer checks that match product behavior — not only “boot completed.”
Next
| Run firmware (CLI) | Local install and run / test |
| Test script schema | YAML fields |
| Fidelity | What pass means |
| Troubleshooting | Max steps, empty UART, … |