Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 22 additions & 159 deletions .github/workflows/hw-matlab.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
name: Hardware Tests (labgrid)

# Bespoke MATLAB hardware-CI workflow. labgrid (adi-labgrid-plugins) boots
# the board for a coordinator place, hands MATLAB the booted board's libIIO
# URI via the IIO_URI env var, and runs runHWTests against it.
# Thin consumer of the labgrid-plugins reusable workflow matlab-hw-request.yml.
# That workflow handles board_map discovery, adi-lg request reservation, board
# boot, and runHWTests — the bespoke adi-lg-matlab launcher is gone.
#
# Two job stages:
# discoveron a coordinator-adjacent runner, intersect live coordinator
# places with test/hw_ci/board_map.yaml -> matrix of places.
# hw — one shard per place, pinned to its hw-<place> self-hosted
# runner (which must have MATLAB + libiio installed), boots the
# board and runs MATLAB.
# Requires:
# vars.ADI_LG_COORDINATORgRPC coordinator address (host:20408).
# NOTE: must be the gRPC port (:20408), NOT the
# REST API port (:8000); adi-lg request uses gRPC.
# vars.MATLAB_BIN — path to the matlab binary on hw-lab runners
# (e.g. /opt/MATLAB/R2025b/bin/matlab).
#
# Requires a coordinator reachable at vars.ADI_LG_COORDINATOR and self-hosted
# runners labeled [self-hosted, hw-coordinator] and [self-hosted, hw-<place>]
# per the adi-labgrid-plugins HW-CI runner contract.
# Self-hosted runner labels expected by the reusable workflow defaults:
# [self-hosted, hw-coordinator] (preflight/discover — default: hw-coordinator)
# [self-hosted, hw-lab] (per-board shards — default: hw-lab)
# Override with vars.HW_REQUEST_RUNNER / vars.HW_PREFLIGHT_RUNNER once the lab
# sets those repo variables; omitting them here uses the reusable workflow's
# built-in defaults.

on:
workflow_dispatch:
Expand All @@ -22,157 +25,17 @@ on:
pull_request:
types: [labeled, opened, synchronize, reopened]

# A pinned reference to adi-labgrid-plugins. Bump alongside the coordinator.
env:
ADI_LG_PLUGINS_REF: "v2"
VENV_DIR: "${{ github.workspace }}/.hw-ci-venv"
# MATLAB binary path on the hw-<place> runner. Override per-repo with
# vars.MATLAB_BIN — lab MATLAB installs vary (/opt vs /mnt vs /usr/local).
MATLAB_BIN: "${{ vars.MATLAB_BIN || '/opt/MATLAB/R2025b/bin/matlab' }}"

# Minimal default token permissions; the publish job widens its own below.
# Minimal default token permissions; the reusable workflow widens its own below.
permissions:
contents: read

jobs:
discover:
# Only on PRs that opt in with the `hw-test` label; always on dispatch/cron.
hw-matlab:
if: >-
github.event_name != 'pull_request' ||
contains(github.event.pull_request.labels.*.name, 'hw-test')
runs-on: [self-hosted, hw-coordinator]
outputs:
matrix: ${{ steps.discover.outputs.matrix }}
count: ${{ steps.discover.outputs.count }}
steps:
- uses: actions/checkout@v4

- name: Setup venv (adi-labgrid-plugins)
uses: tfcollins/labgrid-plugins/.github/actions/setup-uv-venv@v2
with:
venv_dir: ${{ env.VENV_DIR }}
install_cmd: >-
uv pip install --python "$VENV_DIR/bin/python"
"adi-labgrid-plugins @ git+https://github.com/tfcollins/labgrid-plugins.git@${{ env.ADI_LG_PLUGINS_REF }}"

- name: Discover places
id: discover
env:
LG_COORDINATOR: ${{ vars.ADI_LG_COORDINATOR }}
run: |
"$VENV_DIR/bin/adi-lg-matlab" discover \
--coord "$LG_COORDINATOR" \
--board-map test/hw_ci/board_map.yaml \
--github-output

hw:
needs: discover
if: ${{ needs.discover.outputs.count != '0' }}
strategy:
fail-fast: false
matrix:
include: ${{ fromJSON(needs.discover.outputs.matrix).include }}
runs-on: [self-hosted, "hw-${{ matrix.place }}"]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
# +adi/+common is a git submodule (ToolboxCommon shared across ADI
# MATLAB toolboxes). Without it MATLAB can't resolve adi.common.RxTx
# superclass and every test fails to instantiate.
submodules: recursive

- name: Setup venv (adi-labgrid-plugins)
uses: tfcollins/labgrid-plugins/.github/actions/setup-uv-venv@v2
with:
venv_dir: ${{ env.VENV_DIR }}
# [kuiper] extra pulls in pytsk3 — KuiperDLDriver needs it to
# extract uImage / devicetree.dtb from the Kuiper SD image.
install_cmd: >-
uv pip install --python "$VENV_DIR/bin/python"
"adi-labgrid-plugins[kuiper] @ git+https://github.com/tfcollins/labgrid-plugins.git@${{ env.ADI_LG_PLUGINS_REF }}"

- name: Acquire place
uses: tfcollins/labgrid-plugins/.github/actions/acquire-place@v2
with:
coordinator: ${{ vars.ADI_LG_COORDINATOR }}
place: ${{ matrix.place }}
labgrid_client: ${{ env.VENV_DIR }}/bin/labgrid-client

- name: Boot board + run MATLAB HW tests
env:
LG_COORDINATOR: ${{ vars.ADI_LG_COORDINATOR }}
run: |
# Place is already acquired by the composite action above, so do
# NOT pass --acquire here (avoids double-acquire).
#
# --boot-strategy BootFPGASoCTFTP overrides the place's tag
# (currently BootZynq7000JTAGRecovery, which is a recovery
# strategy that doesn't load the IIO HDL). BootFPGASoCTFTP
# JTAG-bootstraps U-Boot, has KuiperDLDriver TFTP the kernel +
# devicetree from the cached Kuiper image, and boots Linux
# with the daughter-board's real HDL design active — so the
# toolbox's MATLAB tests can actually reach the IIO devices
# over libIIO instead of skipping via CheckDevice.
#
# runHWTests exit codes (see test/runHWTests.m):
# 0 = all passed
# 2 = one or more failed
# 3 = one or more Incomplete (e.g. CheckDevice assumeFail).
# On a real boot, 0 is the happy path; 2 propagates as failure.
# We still tolerate exit 3 (some boards may be unreachable for
# transient reasons; JUnit reflects skip status and publish
# aggregates).
set +e
"$VENV_DIR/bin/adi-lg-matlab" run \
--coord "$LG_COORDINATOR" \
--place "${{ matrix.place }}" \
--board-map test/hw_ci/board_map.yaml \
--repo-dir "$GITHUB_WORKSPACE" \
--matlab "$MATLAB_BIN" \
--boot-strategy BootFPGASoCTFTP \
--junit "junit-${{ matrix.place }}.xml"
rc=$?
if [ "$rc" = "3" ]; then
echo "::notice::Tests reported Incomplete (CheckDevice assumeFail) — JUnit has details."
exit 0
fi
exit "$rc"

- name: Release place
if: always()
run: |
"$VENV_DIR/bin/labgrid-client" -x "${{ vars.ADI_LG_COORDINATOR }}" \
-p "${{ matrix.place }}" release || true

- name: Upload JUnit + MATLAB logs
if: always()
uses: actions/upload-artifact@v4
with:
name: hw-results-${{ matrix.place }}
path: |
junit-${{ matrix.place }}.xml
${{ matrix.matlab_board }}_HWTestResults.xml
failures.txt
if-no-files-found: ignore

publish:
needs: hw
# Run only when the hw matrix actually ran (i.e. the hw-test path was
# taken). When hw is skipped, there is nothing to publish — skip too,
# so this job never sits pending on a PR that has no HW runner.
if: ${{ always() && needs.hw.result != 'skipped' }}
runs-on: [self-hosted, hw-coordinator]
# The test-result action posts a check run and a PR comment.
permissions:
contents: read
checks: write
pull-requests: write
steps:
- uses: actions/download-artifact@v4
with:
path: hw-results
- name: Publish test summary
uses: EnricoMi/publish-unit-test-result-action@v2
with:
junit_files: "hw-results/**/junit-*.xml"
uses: tfcollins/labgrid-plugins/.github/workflows/matlab-hw-request.yml@main
with:
coordinator: ${{ vars.ADI_LG_COORDINATOR }}
board-map: "test/hw_ci/board_map.yaml"
matlab-bin: ${{ vars.MATLAB_BIN }}
Loading