Build Bluefin dakota (aarch64) #137
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Bluefin dakota (aarch64) | |
| # Standalone aarch64 build — completely decoupled from x86_64. | |
| # | |
| # Design invariants: | |
| # - ARM NEVER blocks an x86_64 build, publish, promote, or release. | |
| # - No job in publish.yml, promote-testing-to-main.yml, or execute-release.yml | |
| # depends on this workflow. Decoupling is structural, not just continue-on-error. | |
| # - No remote execution (no RE service for ARM); enable-push: true so artifacts | |
| # land in the remote CAS for subsequent builds and warm-cache runs. | |
| # | |
| # Triggers: | |
| # - workflow_run: fires after x86_64 publish completes on testing — ARM builds | |
| # after x86 CAS writes are done, avoiding CAS write contention | |
| # - workflow_dispatch: manual recovery / on-demand | |
| # | |
| # Published tags (when qualifying event on testing/main): | |
| # :aarch64 — latest successful aarch64 build from testing | |
| # :aarch64-<sha> — immutable per-commit tag | |
| on: | |
| # Triggered after x86_64 publish completes — ARM builds after x86 CAS writes | |
| # are done, avoiding CAS write contention. | |
| workflow_run: | |
| workflows: ["Publish Bluefin dakota"] | |
| types: [completed] | |
| branches: [testing] | |
| workflow_dispatch: | |
| permissions: read-all | |
| env: | |
| IMAGE_NAME: dakota | |
| IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} | |
| # All BuildStream cache writers share one CAS serialization group. ARM remains | |
| # decoupled from x86 publication and release, but cannot contend for CAS writes. | |
| concurrency: | |
| group: dakota-bst-build-global | |
| cancel-in-progress: false | |
| jobs: | |
| build-aarch64: | |
| name: Build OCI image (aarch64) | |
| runs-on: ubuntu-24.04-arm | |
| # Skip if triggered by workflow_run but the upstream publish failed. | |
| if: > | |
| github.event_name != 'workflow_run' || | |
| github.event.workflow_run.conclusion == 'success' | |
| # ARM failures are non-blocking and never affect x86_64 publication. | |
| continue-on-error: true | |
| timeout-minutes: 420 | |
| outputs: | |
| pushed: ${{ steps.push.outputs.pushed }} | |
| sha: ${{ steps.context.outputs.sha }} | |
| aarch64_digest: ${{ steps.push.outputs.digest }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| steps: | |
| - name: Resolve build context | |
| id: context | |
| run: | | |
| echo "sha=${{ github.sha }}" >> "$GITHUB_OUTPUT" | |
| - name: Checkout repository | |
| uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 | |
| - name: Setup runner | |
| uses: projectbluefin/actions/bootc-build/setup-runner@v1 | |
| with: | |
| storage-backend: btrfs | |
| update-podman: true | |
| install-tools: '["just"]' | |
| - name: Capture build timestamp | |
| id: timestamp | |
| run: echo "created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT" | |
| - name: Restore BST workspace cache (aarch64) | |
| uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 | |
| with: | |
| path: ~/.cache/buildstream | |
| key: bst-aarch64-${{ github.ref_name }}-${{ hashFiles('elements/gnome-build-meta.bst', 'elements/freedesktop-sdk.bst', 'Justfile') }} | |
| restore-keys: | | |
| bst-aarch64-${{ github.ref_name }}- | |
| bst-aarch64- | |
| bst-warm-aarch64- | |
| # No remote execution for ARM yet; enable-push so artifacts land in CAS | |
| # for subsequent builds and warm-cache runs. | |
| - name: Generate BuildStream CI config | |
| env: | |
| CASD_CLIENT_CERT: ${{ vars.CASD_CLIENT_CERT }} | |
| CASD_CLIENT_KEY: ${{ secrets.CASD_CLIENT_KEY }} | |
| uses: ./.github/actions/generate-bst-ci-config | |
| with: | |
| enable-push: 'true' | |
| - name: Build OCI image with BuildStream (aarch64) | |
| env: | |
| BST_FLAGS: --no-interactive --config /src/buildstream-ci.conf --option arch aarch64 | |
| run: just bst build oci/bluefin.bst | |
| timeout-minutes: 390 | |
| - name: Export OCI image from BuildStream | |
| id: export | |
| env: | |
| BST_FLAGS: --no-interactive --config /src/buildstream-ci.conf --option arch aarch64 | |
| BUILD_IMAGE_NAME: ${{ env.IMAGE_NAME }} | |
| OCI_IMAGE_CREATED: ${{ steps.timestamp.outputs.created }} | |
| OCI_IMAGE_REVISION: ${{ github.sha }} | |
| OCI_IMAGE_VERSION: aarch64 | |
| run: | | |
| just export | |
| echo "image_ref=${{ env.IMAGE_NAME }}:aarch64" >> "$GITHUB_OUTPUT" | |
| - name: Validate with bootc container lint | |
| run: just lint | |
| - name: Upload build logs | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: buildstream-logs-aarch64-${{ github.sha }} | |
| path: logs/ | |
| retention-days: 7 | |
| if-no-files-found: ignore | |
| - name: Login to GHCR | |
| if: >- | |
| github.event_name == 'push' || | |
| github.event_name == 'workflow_run' || | |
| github.event_name == 'workflow_dispatch' | |
| env: | |
| GH_ACTOR: ${{ github.actor }} | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| echo "$GH_TOKEN" | sudo podman login ghcr.io --username "$GH_ACTOR" --password-stdin | |
| mkdir -p ~/.docker | |
| echo "$GH_TOKEN" | podman login ghcr.io --username "$GH_ACTOR" --password-stdin \ | |
| --compat-auth-file ~/.docker/config.json | |
| - name: Push to GHCR | |
| id: push | |
| if: >- | |
| github.event_name == 'push' || | |
| github.event_name == 'workflow_run' || | |
| github.event_name == 'workflow_dispatch' | |
| env: | |
| BUILD_SHA: ${{ github.sha }} | |
| run: | | |
| IMAGE="${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}" | |
| LOCAL="localhost/${{ steps.export.outputs.image_ref }}" | |
| # Tag the immutable SHA-pinned ref first; push it with --digestfile so | |
| # the captured digest matches exactly what was uploaded. The floating | |
| # :aarch64 tag is pushed afterwards and points at the same manifest. | |
| sudo podman tag "${LOCAL}" "${IMAGE}:aarch64-${BUILD_SHA}" | |
| sudo podman tag "${LOCAL}" "${IMAGE}:aarch64" | |
| PUSH_OK=false | |
| for attempt in 1 2 3; do | |
| sudo podman push --compression-format=zstd \ | |
| --digestfile "${RUNNER_TEMP}/digest.txt" \ | |
| "${IMAGE}:aarch64-${BUILD_SHA}" && { PUSH_OK=true; break; } | |
| echo "Push attempt ${attempt} failed for :aarch64-${BUILD_SHA}, retrying in 5s..." | |
| [ "$attempt" -lt 3 ] && sleep 5 | |
| done | |
| if [ "$PUSH_OK" != "true" ]; then | |
| echo "ERROR: all push attempts failed for :aarch64-${BUILD_SHA} — aarch64 build not signed/published" | |
| echo "pushed=false" >> "$GITHUB_OUTPUT" | |
| exit 1 | |
| fi | |
| DIGEST="$(cat "${RUNNER_TEMP}/digest.txt")" | |
| echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT" | |
| # Floating :aarch64 — best-effort, never blocks signing of the pinned tag. | |
| for attempt in 1 2 3; do | |
| sudo podman push --compression-format=zstd \ | |
| "${IMAGE}:aarch64" && break | |
| echo "Push attempt ${attempt} failed for :aarch64, retrying in 5s..." | |
| [ "$attempt" -lt 3 ] && sleep 5 | |
| done | |
| echo "pushed=true" >> "$GITHUB_OUTPUT" | |
| - name: Install oras | |
| if: steps.push.outputs.pushed == 'true' | |
| uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 | |
| - name: Sign image and create attestation | |
| # Mirrors publish.yml exactly. generate-sbom: false — dakota uses BST-native | |
| # provenance (just sbom) handled separately; Syft post-build scan is less | |
| # accurate for BST builds. | |
| if: steps.push.outputs.pushed == 'true' | |
| uses: projectbluefin/actions/bootc-build/sign-and-publish@v1 | |
| with: | |
| image: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }} | |
| digest: ${{ steps.push.outputs.digest }} | |
| generate-sbom: false | |
| github-token: ${{ secrets.GITHUB_TOKEN }} |