From 5ec79c448bf0e31b3730cf1233c867fbe3449326 Mon Sep 17 00:00:00 2001 From: gabriel Date: Mon, 27 Jul 2026 12:21:29 +0200 Subject: [PATCH] ci: adopt release-please for firmware releases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Releases are cut by merging a release PR: release-please maintains the version manifest and CHANGELOG.md from conventional commits and creates the GitHub release, tagged bare (1.2.0 — not v1.2.0, not Firmware_NRF54-1.2.0) to match the existing 1.1.1 tag. A release created with GITHUB_TOKEN does not emit release:published, so release.yml gains a workflow_call trigger and release-please.yml invokes it gated on release_created; the calling job grants contents:write, since a called workflow cannot hold more permissions than its caller. The checkout is pinned to the tag, because under workflow_call the default ref is the caller's (main). workflow_dispatch gives a recovery path for re-running a failed build against an existing tag. Also skips the nrfutil self-upgrade and sdk-manager install on an NCS cache hit — they write into ~/.nrfutil, which the cache restores, and self-upgrade would pull a newer nrfutil than the cached SDK was installed with. The binary download stays unconditional, since /usr/local/bin is not cached. --- .github/workflows/release-please.yml | 47 ++++++++++++++++++++++++++++ .github/workflows/release.yml | 36 +++++++++++++++++++-- .release-please-config.json | 19 +++++++++++ .release-please-manifest.json | 3 ++ 4 files changed, 102 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/release-please.yml create mode 100644 .release-please-config.json create mode 100644 .release-please-manifest.json diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..520a01d --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,47 @@ +name: Release Please + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: {} + +concurrency: + group: release + cancel-in-progress: false + +jobs: + release-please: + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: write + pull-requests: write + outputs: + release_created: ${{ steps.release.outputs.release_created }} + tag_name: ${{ steps.release.outputs.tag_name }} + steps: + - uses: googleapis/release-please-action@v5 + id: release + with: + # Passed explicitly: the action's config-file default is + # `release-please-config.json` (no leading dot), so relying on the + # default would silently ignore this repo's dotted config. + config-file: .release-please-config.json + manifest-file: .release-please-manifest.json + + # A release created with GITHUB_TOKEN does not emit `release: published`, so + # the build has to be called directly rather than left to trigger itself. + build: + needs: release-please + if: ${{ needs.release-please.outputs.release_created == 'true' }} + # A called workflow cannot hold more permissions than its caller, and this + # one attaches release assets. Without this the whole run fails at startup, + # because the top-level `permissions: {}` would cap it at nothing. + permissions: + contents: write + uses: ./.github/workflows/release.yml + with: + tag: ${{ needs.release-please.outputs.tag_name }} + secrets: inherit diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 43724a9..3bac260 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,24 @@ name: Release Firmware on: + # Called by release-please.yml once it has created a release. Needed because a + # release created with GITHUB_TOKEN does not emit `release: published`. + workflow_call: + inputs: + tag: + description: "Tag to build" + required: true + type: string + # Kept for releases published by hand in the GitHub UI. release: types: [published] + # Recovery path: re-run the build for an existing tag without republishing it. + workflow_dispatch: + inputs: + tag: + description: "Tag to build" + required: true + type: string permissions: contents: write @@ -15,16 +31,21 @@ jobs: build-and-upload: name: Build & Upload Firmware runs-on: ubuntu-latest + timeout-minutes: 60 steps: - name: Checkout Code uses: actions/checkout@v4 + with: + # Under workflow_call the default ref is the caller's (main), not the + # tag being released. + ref: ${{ inputs.tag || github.event.release.tag_name }} - name: Parse release tag id: ver run: | set -euo pipefail - TAG="${{ github.event.release.tag_name }}" + TAG="${{ inputs.tag || github.event.release.tag_name }}" VERSION="${TAG#v}" if ! [[ "${VERSION}" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]]; then echo "Tag must look like MAJOR.MINOR or MAJOR.MINOR.PATCH (optional leading v). Got: ${TAG}" @@ -52,12 +73,21 @@ jobs: /home/runner/.nrfutil key: ncs-${{ env.NCS_VERSION }}-${{ runner.os }}-v2 - - name: Install nrfutil + # The binary itself lives in /usr/local/bin, which is not part of the + # cache, so it has to be fetched on every run. + - name: Install nrfutil binary run: | curl -L -o nrfutil \ https://files.nordicsemi.com/artifactory/swtools/external/nrfutil/executables/x86_64-unknown-linux-gnu/nrfutil chmod +x nrfutil sudo mv nrfutil /usr/local/bin/ + + # These all write into ~/.nrfutil, which the cache above restores — so on a + # hit they are redundant work (and `self-upgrade` would pull a newer + # nrfutil than the cached SDK was installed with). + - name: Install sdk-manager + if: steps.cache-ncs.outputs.cache-hit != 'true' + run: | nrfutil self-upgrade nrfutil install sdk-manager nrfutil sdk-manager config install-dir set "${NCS_INSTALL_DIR}" @@ -108,6 +138,6 @@ jobs: with: repo_token: ${{ secrets.GITHUB_TOKEN }} file: firmware_output/* - tag: ${{ github.ref }} + tag: ${{ steps.ver.outputs.tag }} file_glob: true overwrite: true diff --git a/.release-please-config.json b/.release-please-config.json new file mode 100644 index 0000000..16acb13 --- /dev/null +++ b/.release-please-config.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "include-v-in-tag": false, + "include-component-in-tag": false, + "packages": { + ".": { + "release-type": "simple", + "package-name": "Firmware_NRF54", + "changelog-sections": [ + { "type": "feat", "section": "Features" }, + { "type": "fix", "section": "Bug Fixes" }, + { "type": "perf", "section": "Performance Improvements" }, + { "type": "docs", "section": "Documentation" }, + { "type": "refactor", "section": "Code Refactoring" }, + { "type": "ci", "section": "Continuous Integration" } + ] + } + } +} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..c4ddc74 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "1.1.1" +}