Skip to content

CI integration

Run the same labwired test command on your laptop and in GitHub Actions, GitLab, or Azure Pipelines. Pin a CLI release so firmware changes are judged by a fixed simulator version.

Default pin used in examples: v0.23.0.


Local first

curl -fsSL https://labwired.com/install.sh | LABWIRED_VERSION=v0.23.0 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@64ed5d9723e2d9f5f4a851a81a3468025671d94e
        with:
          script: tests/firmware-test.yaml
          version: v0.23.0
          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 64ed5d9723e2d9f5f4a851a81a3468025671d94e. Inputs: script (required), version (default v0.23.0), 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.23.0 \
  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.23.0
    entrypoint: [""]
  script:
    - labwired test --script tests/firmware-test.yaml --output-dir out/labwired --no-uart-stdout

Azure Pipelines

Install the pinned release on the agent, then publish the CLI's JUnit into the Tests tab:

- script: |
    curl -fsSL https://github.com/w1ne/labwired-core/releases/download/v0.23.0/labwired-v0.23.0-linux-x86_64.tar.gz \
      | tar -xz -C "$AGENT_TEMPDIRECTORY"
    echo "##vso[task.prependpath]$AGENT_TEMPDIRECTORY"
  displayName: Install LabWired CLI

- script: labwired test --script tests/firmware-test.yaml --output-dir out/labwired --junit out/labwired/junit.xml --no-uart-stdout
  displayName: Run LabWired tests
  continueOnError: true

- task: PublishTestResults@2
  displayName: Publish LabWired results
  condition: succeededOrFailed()
  inputs:
    testResultsFormat: JUnit
    testResultsFiles: '**/junit.xml'
    searchFolder: out/labwired
    failTaskOnFailedTests: false

For the full example — build summary, build tag, one upserted pull request comment, and the unproven gate — copy the azure/ directory from LabWired/firmware-test.


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, …