出自flip the world 檢視Firmware CI/CD on GitHub Actions的原始碼 頁面討論 閱讀檢視原始碼檢視歷史 ←Firmware CI/CD on GitHub Actions 您沒有權限執行編輯此頁面,由於以下原因: 您請求的操作只有這個群組的使用者能使用:使用者 您可以檢視並複製此頁面的原始碼。 '''Firmware CI/CD on GitHub Actions''' — the golden procedure for building, testing, reviewing and releasing firmware on hosted runners, with flashing and on-device tests left to the bench. [[File:cicd_golden.png|1200px|thumb|center|Every change builds, tests, lints and simulates; every pull request is reviewed; every tag releases; the bench does what hosted runners cannot.]] {| class="wikitable" ! workflow !! trigger !! runs !! output |- | Build || push to main, pull request, manual || one job per variant; toolchain from a container built from the repo's Dockerfile with a layer cache, or a minimal SDK cached on the plain runner when the image does not fit the runner disk; a fan-in job gives the matrix one check name || run artefacts per variant named <code><variant>-<sha></code>, <code>retention-days</code> 14–30 (release artefacts 90); size report |- | Unit tests || push, pull request || host tests in their own test container, coverage, JUnit || JUnit published as a check, coverage artefact |- | Fast lints || push, pull request || scripts that read only the source tree (layering, dependency manifest), no container, no submodules, seconds; also dry-run any release-only generator here, so one broken since the last release fails on a pull request, not on tag day || pass/fail |- | Simulation regression || push, pull request || host build of the algorithm model, fixed scenarios; needs the submodule token only for the submodule it uses (<code>path:</code> input), not all of them || pass/fail |- | Automated review || pull request opened or updated, not drafts || agent reads the diff against the repo rules file || review comment; not a required check, because it skips drafts and doc-only changes |- | Release || tag <code>vX.Y.Z</code> (manual dry-run optional) || version from the tag into the build; all variants, bootloader package, update images signed with the release key; changelog since the previous tag; dependency manifest checked against the tree, then snapshotted || draft GitHub Release: images, update set, bootloader, manifest, changelog, snapshot, one zip |} {| class="wikitable" ! recipe !! how |- | private submodules || mint a token per run with <code>actions/create-github-app-token</code> (App client ID as a repository variable, private key as a secret); rewrite <code>https://github.com/</code> and <code>git@github.com:</code> to <code>https://x-access-token:${TOKEN}@github.com/</code> with <code>git config --global --add url.<token url>.insteadOf</code> (twice, <code>--add</code> so the second mapping does not replace the first); <code>git submodule sync</code>, then <code>git submodule update --init --depth 1</code>; a personal token works too but expires, and renewing it means <code>gh secret set</code>, not only the account |- | container || <code>docker/build-push-action</code> from the repo Dockerfile with <code>cache-from/cache-to: type=gha</code> and <code>load: true</code>, then <code>docker run --user $(id -u):$(id -g) -v $GITHUB_WORKSPACE:/work</code>; if the image does not fit the 14 GB runner disk, install a minimal toolchain on the plain runner and cache it with <code>actions/cache</code> keyed on its version |- | required check || a job is required only when branch protection or a ruleset lists its name; a matrix needs one fan-in job (<code>needs</code>, <code>if: always()</code>, fail unless every result is success); a required workflow must not use path filters or skip drafts, or such pull requests wait forever |- | test report || publish the JUnit XML with a test-reporter action (<code>java-junit</code>, fail on error) under job permission <code>checks: write</code>; upload coverage and the XML with <code>actions/upload-artifact</code>, retention 7–30 days |- | release || checkout with <code>fetch-depth: 0</code>; <code>VERSION=${GITHUB_REF#refs/tags/}</code>; changelog = <code>git log $(git describe --tags --abbrev=0 ${VERSION}^)..${VERSION} --pretty='- %s (%h)'</code>; artefacts <code><project>-<variant>-<version>.<ext></code> plus one zip; publish with a release action as a draft, prerelease when the version has a suffix, under <code>contents: write</code>; write the signing-key PEM from the secret to <code>$RUNNER_TEMP</code>, and without the secret sign with the dev key and emit a warning; the same key signs the images and is built into the bootloader package, or release bootloaders would accept dev-signed images; dry-run = <code>workflow_dispatch</code> with a <code>version</code> input, the version step takes the tag when <code>github.event_name == 'push'</code> else the input, and the draft-release step runs only <code>if: startsWith(github.ref, 'refs/tags/')</code> |- | automated review || <code>uses: anthropics/claude-code-action@<commit-sha></code> with <code>claude_code_oauth_token: ${{ secrets.<review token> }}</code> and <code>additional_permissions: actions: read</code> (the job permission alone does not let the agent read CI results); job permissions <code>contents: read, pull-requests: write, id-token: write, actions: read</code>; <code>prompt:</code> points at the rules file (CLAUDE.md / REVIEW.md); <code>claude_args</code> restricts the model and the allowed tools to pull-request reading commands; skip drafts; one concurrency group per pull request |} {| class="wikitable" ! secret or variable !! purpose !! rule |- | App client ID (variable) + App private key (secret) || mints the short-lived submodule token || preferred: nothing expires unnoticed |- | personal access token (secret) || same, when no App exists || expires; renew in the repo secret |- | release signing key (secret) || signs the update images || secret only; a device accepts only images signed with the key its bootloader carries |- | review-agent token (secret) || the automated review action || secret only; the action that reads it is pinned to a commit SHA, never a floating tag |- | <code>GITHUB_TOKEN</code> || creates the draft release || needs <code>permissions: contents: write</code> on that job |} Every workflow also sets <code>concurrency</code> per ref with cancel-in-progress, <code>timeout-minutes</code>, <code>permissions: contents: read</code> by default, and path filters on non-required workflows. Hosted runners build, test, lint, review and sign; flashing and on-device tests are done on the bench, or by a self-hosted runner on the bench machine. [[Category:Software and Tools]] 返回到「Firmware CI/CD on GitHub Actions」。