blob: 0ff29cdda9de1953d682495ced1a1f3d6a69cd00 [file]
name: Build
on:
workflow_dispatch:
push:
branches: [master]
pull_request:
release:
types: [ published ]
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.sha || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/master' }}
jobs:
# Check if the code changes and we need to run ci build
# Cannot use paths filter in the on-event since we want this workflow to run even when there are no code changes, to register the commit chain
check-paths:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
code_changed: ${{ steps.filter.outputs.code }}
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 2 # Needed for push commit comparison
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
code:
- 'src/**'
- 'examples/**'
- 'lib/**'
- 'hw/**'
- 'test/hil/**'
- 'tools/build.py'
- 'tools/get_deps.py'
- '.github/actions/**'
- '.github/workflows/build.yml'
- '.github/workflows/build_util.yml'
- '.github/workflows/ci_set_matrix.py'
set-matrix:
runs-on: ubuntu-latest
outputs:
json: ${{ steps.set-matrix-json.outputs.matrix }}
hil_json: ${{ steps.set-matrix-json.outputs.hil_matrix }}
steps:
- name: Checkout TinyUSB
uses: actions/checkout@v6
- name: Generate matrix json
id: set-matrix-json
run: |
# build matrix
MATRIX_JSON=$(python .github/workflows/ci_set_matrix.py)
echo "matrix=$MATRIX_JSON"
echo "matrix=$MATRIX_JSON" >> $GITHUB_OUTPUT
# HIL matrix (merged from tinyusb + hifiphile configs)
HIL_MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py test/hil/tinyusb.json test/hil/hfp.json)
echo "hil_matrix=$HIL_MATRIX_JSON"
echo "hil_matrix=$HIL_MATRIX_JSON" >> $GITHUB_OUTPUT
# ------------------------------------------------------------------------------
# CMake build: only one board per family (first alphabetically). Full build is done by CircleCI in PR
# Note:
# For Make and IAR build: will be done on CircleCI only (one random per family as well)
# ------------------------------------------------------------------------------
cmake:
needs: [ check-paths, set-matrix ]
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
matrix:
toolchain:
- 'aarch64-gcc'
#- 'arm-clang'
- 'arm-gcc'
#- 'esp-idf'
- 'ft9xx-gcc'
- 'msp430-gcc'
- 'riscv-gcc'
with:
build-system: 'cmake'
toolchain: ${{ matrix.toolchain }}
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }}
build-options: '--one-first'
upload-metrics: true
upload-artifacts: false
upload-membrowse: true
code-changed: ${{ needs.check-paths.outputs.code_changed == 'true' }}
secrets: inherit
code-metrics:
needs: [ check-paths, cmake ]
if: needs.check-paths.outputs.code_changed == 'true'
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: write
steps:
- name: Checkout TinyUSB
uses: actions/checkout@v6
with:
fetch-tags: ${{ github.event_name == 'release' }}
- name: Download Artifacts
uses: actions/download-artifact@v5
with:
pattern: metrics-*
path: cmake-build
merge-multiple: true
- name: Aggregate Code Metrics
run: |
python tools/get_deps.py
python tools/metrics.py combine -j -m -f tinyusb/src cmake-build/*/metrics.json
- name: Upload Metrics Artifact
if: github.event_name == 'push' || github.event_name == 'release'
uses: actions/upload-artifact@v7
with:
name: metrics-tinyusb
path: metrics.json
- name: Download Base Branch Metrics
if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch'
uses: dawidd6/action-download-artifact@v11
with:
workflow: build.yml
workflow_conclusion: ''
branch: ${{ github.base_ref }}
name: metrics-tinyusb
path: base-metrics
continue-on-error: true
- name: Download Previous Release Asset
if: github.event_name == 'release'
env:
GH_TOKEN: ${{ github.token }}
run: |
PREV_TAG=$(git tag --sort=-creatordate | head -n 2 | tail -n 1)
echo "Previous Release: $PREV_TAG"
echo "PREV_TAG=$PREV_TAG" >> $GITHUB_ENV
mkdir -p base-metrics
gh release download $PREV_TAG -p metrics.json -D base-metrics || echo "No metrics.json found in $PREV_TAG release"
- name: Compare with Base Branch
if: github.event_name != 'push'
run: |
if [ -f base-metrics/metrics.json ]; then
python tools/metrics.py compare -m -f tinyusb/src base-metrics/metrics.json metrics.json
cat metrics_compare.md
else
echo "No base metrics found, skipping comparison"
cp metrics.md metrics_compare.md
fi
- name: Upload Release Assets
if: github.event_name == 'release'
env:
GH_TOKEN: ${{ github.token }}
run: |
CURR_TAG=${{ github.event.release.tag_name }}
COMPARE_FILE="metrics_compare_${CURR_TAG}-${PREV_TAG}.md"
mv metrics_compare.md $COMPARE_FILE
gh release upload $CURR_TAG metrics.json $COMPARE_FILE
- name: Save PR number
if: github.event_name == 'pull_request'
run: echo ${{ github.event.number }} > pr_number.txt
- name: Upload Metrics Comment Artifact
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v7
with:
name: metrics-comment
path: |
metrics_compare.md
metrics.json
pr_number.txt
- name: Post Code Metrics as PR Comment
if: (github.event_name == 'workflow_dispatch') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false)
uses: marocchino/sticky-pull-request-comment@v2
with:
header: code-metrics
path: metrics_compare.md
# ---------------------------------------
# Keep the metrics baseline available on no-code-change pushes
# The code-metrics job only runs (and uploads metrics-tinyusb) when code changed, so a
# workflow/docs-only push to master would leave the latest run without a baseline for PRs
# to compare against. Carry the previous artifact forward so the baseline is never missing.
# ---------------------------------------
metrics-carry-forward:
needs: [ check-paths ]
if: github.event_name == 'push' && needs.check-paths.outputs.code_changed != 'true'
runs-on: ubuntu-latest
steps:
- name: Download previous metrics baseline from this branch
uses: dawidd6/action-download-artifact@v11
with:
workflow: build.yml
workflow_conclusion: '' # any conclusion, matching the PR-side baseline download
search_artifacts: true # scan back past runs that lack the artifact (e.g. earlier no-code pushes)
branch: ${{ github.ref_name }}
name: metrics-tinyusb
path: .
if_no_artifact_found: warn
continue-on-error: true # best-effort: never make a no-code push red
- name: Re-publish baseline so the latest run keeps it
if: hashFiles('metrics.json') != ''
uses: actions/upload-artifact@v7
with:
name: metrics-tinyusb
path: metrics.json
# ---------------------------------------
# Build Make/CMake on Windows/MacOS
# ---------------------------------------
build-os:
needs: [ check-paths ]
if: needs.check-paths.outputs.code_changed == 'true'
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
matrix:
os: [ windows-latest, macos-latest ]
build-system: [ 'make', 'cmake' ]
with:
os: ${{ matrix.os }}
build-system: ${{ matrix.build-system }}
toolchain: 'arm-gcc-${{ matrix.os }}'
build-args: '["stm32h7rs"]'
build-options: '--one-random'
# ---------------------------------------
# Zephyr
# ---------------------------------------
zephyr:
needs: [ check-paths ]
# skip zephyr build due to failed build, fix later
if: false
#if: needs.check-paths.outputs.code_changed == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout TinyUSB
uses: actions/checkout@v6
- name: Setup Zephyr project
uses: zephyrproject-rtos/action-zephyr-setup@v1
with:
app-path: examples
toolchains: arm-zephyr-eabi
- name: Build
run: |
west build -b nrf52840dk -d examples/device/cdc_msc/build examples/device/cdc_msc -- -DRTOS=zephyr
west build -b nrf52840dk -d examples/device/msc_dual_lun/build examples/device/msc_dual_lun -- -DRTOS=zephyr
# ---------------------------------------
# Hardware in the loop (HIL)
# Run on PR only (hil-tinyusb), hil-hfp-iar only run on non-forked PR
# ---------------------------------------
hil-build:
needs: [ check-paths, set-matrix ]
if: needs.check-paths.outputs.code_changed == 'true' && github.repository_owner == 'hathach'
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
matrix:
toolchain:
- 'arm-gcc'
- 'esp-idf'
with:
build-system: 'cmake'
toolchain: ${{ matrix.toolchain }}
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.hil_json)[matrix.toolchain]) }}
upload-artifacts: true
# ---------------------------------------
# Hardware in the loop (HIL)
# self-hosted on local VM, for attached hardware checkout HIL_JSON
# ---------------------------------------
hil-tinyusb:
needs: hil-build
name: hil-tinyusb (${{ matrix.display }})
strategy:
fail-fast: false
matrix:
include:
- display: tinyusb.json
runner: [ self-hosted, X64, hathach, hardware-in-the-loop ]
hil_json: test/hil/tinyusb.json
- display: hfp.json
runner: [ self-hosted, Linux, X64, hifiphile ]
hil_json: test/hil/hfp.json
runs-on: ${{ matrix.runner }}
env:
HIL_JSON: ${{ matrix.hil_json }}
steps:
- name: Set HIL report dir (sibling of workspace; persists across run attempts)
run: echo "HIL_REPORT_DIR=$(dirname "$GITHUB_WORKSPACE")/hil-report" >> "$GITHUB_ENV"
- name: Get Skip Boards from previous run
if: github.run_attempt != '1'
run: |
if [ -f "${{ env.HIL_JSON }}.skip" ]; then
SKIP_BOARDS=$(cat "${{ env.HIL_JSON }}.skip")
else
SKIP_BOARDS=""
fi
echo "SKIP_BOARDS=$SKIP_BOARDS"
echo "SKIP_BOARDS=$SKIP_BOARDS" >> $GITHUB_ENV
- name: Clean workspace
run: |
echo "Cleaning up for the first run"
rm -rf "${{ github.workspace }}"
mkdir -p "${{ github.workspace }}"
- name: Checkout TinyUSB
uses: actions/checkout@v6
- name: Download Artifacts
uses: actions/download-artifact@v5
with:
pattern: binaries-*
path: cmake-build
merge-multiple: true
- name: Test on actual hardware
run: |
python3 test/hil/hil_test.py ${{ env.HIL_JSON }} $SKIP_BOARDS || \
(if [ -f "${{ env.HIL_JSON }}.skip" ]; then
SKIP_BOARDS=$(cat "${{ env.HIL_JSON }}.skip")
echo "Re-running with SKIP_BOARDS=$SKIP_BOARDS"
python3 test/hil/hil_test.py ${{ env.HIL_JSON }} $SKIP_BOARDS
else
exit 1
fi)
- name: Upload HIL report
if: always() && github.event_name == 'pull_request'
uses: actions/upload-artifact@v7
with:
name: hil-report-${{ matrix.display }}
path: ${{ env.HIL_REPORT_DIR }}/hil_report.md
if-no-files-found: ignore
overwrite: true
# ---------------------------------------
# Hardware in the loop (HIL)
# self-hosted by HFP, build with IAR toolchain, for attached hardware checkout test/hil/hfp.json
# Since IAR Token secret is not passed to forked PR, only build non-forked PR
# ---------------------------------------
hil-hfp-iar:
needs: [ check-paths ]
if: |
needs.check-paths.outputs.code_changed == 'true' &&
github.repository_owner == 'hathach' &&
!(github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true)
runs-on: [ self-hosted, Linux, X64, hifiphile ]
timeout-minutes: 30
env:
IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
PYTHONUNBUFFERED: '1'
steps:
- name: Clean workspace
run: |
echo "Cleaning up previous run"
rm -rf "${{ github.workspace }}"
mkdir -p "${{ github.workspace }}"
- name: Toolchain version
run: |
iccarm --version
- name: Checkout TinyUSB
uses: actions/checkout@v6
- name: Get build boards
run: |
MATRIX_JSON=$(python test/hil/hil_ci_set_matrix.py test/hil/hfp.json)
BUILD_ARGS=$(echo $MATRIX_JSON | jq -r '.["arm-gcc"] | join(" ")')
echo "BUILD_ARGS=$BUILD_ARGS"
echo "BUILD_ARGS=$BUILD_ARGS" >> $GITHUB_ENV
- name: Get Dependencies
run: python3 tools/get_deps.py $BUILD_ARGS
- name: Build
run: python3 tools/build.py --toolchain iar $BUILD_ARGS
- name: Test on actual hardware (hardware in the loop)
run: |
python3 test/hil/hil_test.py hfp.json
# ---------------------------------------
# Combine HIL results from the rigs into a single sticky PR comment (one table per rig)
# ---------------------------------------
hil-report:
needs: hil-tinyusb
if: |
always() &&
needs.hil-tinyusb.result != 'skipped' &&
github.event_name == 'pull_request' &&
github.repository_owner == 'hathach' &&
github.event.pull_request.head.repo.fork == false
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Download HIL reports
uses: actions/download-artifact@v5
with:
pattern: hil-report-*
path: hil-reports
- name: Combine rig reports (one table per rig)
run: |
{
echo "## HIL test results"
echo
for d in hil-reports/hil-report-*; do
[ -d "$d" ] || continue
echo "### ${d#hil-reports/hil-report-}"
echo
cat "$d/hil_report.md" 2>/dev/null || echo "_no report produced_"
echo
done
} > hil_combined.md
cat hil_combined.md
- name: Post HIL report as sticky PR comment
uses: marocchino/sticky-pull-request-comment@v2
with:
header: hil-report
path: hil_combined.md