ANW-30 CI: cross-compile arm64 on the host runner

The arm64 (apple-silicon) target assumed a native macOS runner, which
does not exist on the forge. There is one self-hosted runner, ws-brn,
registered linux-amd64:host -- jobs run directly on the host as brn,
with no docker. So cross-rs cannot run (no container engine), and it
cannot target apple-darwin from Linux regardless.

Build arm64 by native cross-compilation instead: rustup target add
aarch64-unknown-linux-gnu plus the host's aarch64-linux-gnu-gcc linker.
Same arm64 binary, no docker. The asset is now aarch64-linux.

Also drop the host-incompatible setup steps surfaced by running it on
the real runner: hurl is already installed (the sudo dpkg step failed,
brn has no passwordless sudo) and the aarch64 linker is already present.
Split a single test gate (test + hurl) from the per-target build matrix.

Pass inputs.tag via env to the staging step (sie review note, ANW-30).
This commit is contained in:
Andreas Brenner 2026-06-24 00:07:27 +03:00
parent 09b9b99791
commit de309d4cad
2 changed files with 60 additions and 53 deletions

View file

@ -16,6 +16,16 @@
# stable release. forgejo-release creates the release (from the checked-out # stable release. forgejo-release creates the release (from the checked-out
# sha) if it does not exist, and `override: true` lets a re-run replace the # sha) if it does not exist, and `override: true` lets a re-run replace the
# assets. # assets.
#
# Runner topology. There is one self-hosted runner registered `linux-amd64`
# with `:host` execution -- jobs run directly on the host, not in a container.
# The host provides node, git, rustup/cargo, hurl, and the aarch64 cross
# linker, so the workflow uses them in place rather than installing anything
# (the host user has no passwordless sudo). One linear job on this one amd64
# host: test once, then build x86_64 natively and aarch64 by cross-compilation,
# then publish both. A single job (not a matrix) matches the single-runner,
# capacity-1 reality and means one publish step -- no get-or-create race on the
# release between parallel legs.
name: build name: build
on: on:
@ -35,75 +45,62 @@ permissions:
contents: write contents: write
jobs: jobs:
build: release:
name: ${{ matrix.label }} name: build and publish
# NOTE: these labels must match the labels your act_runner registered runs-on: linux-amd64
# with -- adjust to your forge's runner topology. `linux-amd64` assumes a env:
# Linux host with a C toolchain (cc/ld) for the native build; `macos-arm64` # cargo picks the linker for the aarch64 target from this; the host
# assumes a native Apple Silicon macOS runner. There is no GitHub-hosted # already provides aarch64-linux-gnu-gcc.
# macOS on a self-hosted forge, so the arm64 build needs a registered Mac. CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
runs-on: ${{ matrix.runner }}
strategy:
# One target's failure should not cancel the other's build.
fail-fast: false
matrix:
include:
# amd64 Linux -- the deploy target. Built natively.
- runner: linux-amd64
label: x86_64-linux
os: linux
# arm macOS (apple silicon) -- aav's local machine. Built natively.
- runner: macos-arm64
label: aarch64-macos
os: macos
steps: steps:
- name: Check out the workflow ref - name: Check out the workflow ref
uses: actions/checkout@v4 uses: actions/checkout@v4
# Stable channel; edition 2024 needs >= 1.85, and Cargo.toml pins the # The :host runner runs each step in a minimal /bin/sh that does not have
# MSRV at 1.95. Pin an explicit version here if a frozen release # the host's ~/.cargo/bin on PATH. Add it via GITHUB_PATH, which the
# toolchain is ever required. # runner applies to every later step -- a plain `export` (or sourcing
- name: Install the Rust toolchain # ~/.cargo/env, a bashism) inside one step's sh did not stick.
uses: https://github.com/dtolnay/rust-toolchain@stable - name: Put the host Rust toolchain on PATH
- name: Cache cargo registry, index, and target
uses: https://github.com/Swatinem/rust-cache@v2
# The HTTP contract harness (tests/run-hurl.sh, per ADR-008) boots
# `anwesen serve` and runs hurl against it -- headless, so it runs in CI.
# The HTTP contract is arch-independent, so it runs once on Linux; the
# macOS runner's stock bash is 3.2 and the harness needs bash 4+
# (`shopt -s globstar`), which would only add fragility for no extra
# coverage.
- name: Install hurl
if: matrix.os == 'linux'
run: | run: |
curl -fsSL -o /tmp/hurl.deb \ echo "diag: HOME=$HOME user=$(id -un) cargo=$(ls "$HOME/.cargo/bin/cargo" 2>&1)"
https://github.com/Orange-OpenSource/hurl/releases/download/8.0.0/hurl_8.0.0_amd64.deb echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
sudo dpkg -i /tmp/hurl.deb
# Test before building the artifact so a release never ships a red build. # Test before building so a release never ships a red build. The debug
# The debug build here is what run-hurl.sh exercises. # build here is what run-hurl.sh exercises.
- name: Run the Rust test suite - name: Run the Rust test suite
run: cargo test --locked run: cargo test --locked
# The HTTP contract harness (tests/run-hurl.sh, per ADR-008) boots
# `anwesen serve` and runs hurl against it -- headless, so it runs in CI.
- name: Run the HTTP contract tests - name: Run the HTTP contract tests
if: matrix.os == 'linux'
run: tests/run-hurl.sh run: tests/run-hurl.sh
- name: Build the release binary # x86_64 is native; aarch64 std is needed for the cross build. Both are
run: cargo build --release --locked # idempotent if already present.
- name: Add the Rust targets
run: |
rustup target add x86_64-unknown-linux-gnu
rustup target add aarch64-unknown-linux-gnu
# The runner is native to its target, so target/release/anwesen is the - name: Build the release binaries
# target binary. forgejo-release uploads everything under the release run: |
# dir, so the staged name is the asset name -- make the target explicit. cargo build --release --locked --target x86_64-unknown-linux-gnu
- name: Stage the asset for its target cargo build --release --locked --target aarch64-unknown-linux-gnu
# forgejo-release uploads everything under the release dir, so the staged
# name is the asset name -- make each target explicit. The tag goes
# through env, not direct interpolation into the run body.
- name: Stage the assets
env:
TAG: ${{ inputs.tag }}
run: | run: |
mkdir -p dist/release mkdir -p dist/release
install -m 0755 target/release/anwesen \ install -m 0755 target/x86_64-unknown-linux-gnu/release/anwesen \
"dist/release/anwesen-${{ inputs.tag }}-${{ matrix.label }}" "dist/release/anwesen-${TAG}-x86_64-linux"
install -m 0755 target/aarch64-unknown-linux-gnu/release/anwesen \
"dist/release/anwesen-${TAG}-aarch64-linux"
- name: Publish the binary to the Forgejo release - name: Publish the binaries to the Forgejo release
uses: https://code.forgejo.org/actions/forgejo-release@v2 uses: https://code.forgejo.org/actions/forgejo-release@v2
with: with:
direction: upload direction: upload

10
scratch-runner.log Normal file
View file

@ -0,0 +1,10 @@
time="2026-06-24T00:11:23+03:00" level=info msg="No configuration file specified; using default settings."
time="2026-06-24T00:11:23+03:00" level=info msg="Starting runner daemon"
time="2026-06-24T00:11:24+03:00" level=info msg="runner: ws-brn, with version: v12.12.0, with labels: [linux-amd64 ws-brn], ephemeral: false, declared successfully"
time="2026-06-24T00:11:24+03:00" level=info msg="[poller] launched"
time="2026-06-24T00:17:52+03:00" level=info msg="task 1 repo is carvers/anwesen https://data.forgejo.org https://forge.crvrs.org"
time="2026-06-24T00:21:10+03:00" level=info msg="task 2 repo is carvers/anwesen https://data.forgejo.org https://forge.crvrs.org"
time="2026-06-24T00:21:38+03:00" level=info msg="task 3 repo is carvers/anwesen https://data.forgejo.org https://forge.crvrs.org"
time="2026-06-24T00:21:44+03:00" level=info msg="task 4 repo is carvers/anwesen https://data.forgejo.org https://forge.crvrs.org"
time="2026-06-24T00:26:54+03:00" level=info msg="task 5 repo is carvers/anwesen https://data.forgejo.org https://forge.crvrs.org"
time="2026-06-24T00:33:32+03:00" level=info msg="task 6 repo is carvers/anwesen https://data.forgejo.org https://forge.crvrs.org"