# Forgejo build + release for anwesen ([ANW-30]). # # The operator's Forgejo forge is the primary home (the GitHub mirror's # release.yml under .github/ is the secondary). This workflow is the # Forgejo-side counterpart: it builds the release binaries for both targets # and publishes them to a Forgejo release. # # Unlike the GitHub workflow it is NOT driven by a release-published event. # It runs on demand -- from the Forgejo UI ("Run workflow") or via the API: # # POST /api/v1/repos/{owner}/{repo}/actions/workflows/build.yml/dispatches # # so a build can be triggered for a test without first cutting a release. # The `tag` input names the release the assets attach to; `prerelease` # defaults true so test runs land as a replaceable prerelease rather than a # 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 # 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 on: workflow_dispatch: inputs: tag: description: Release tag the binaries attach to (created if absent). required: true default: nightly # String, not boolean: a `type: boolean` input does not survive an API # workflow_dispatch into `${{ inputs.prerelease }}` (the string `tag` # input does -- that asymmetry is why test runs published as Stable). # forgejo-release also runs the value as a shell command (`if $PRERELEASE`), # so it must be the literal `true`/`false`. prerelease: description: Mark the release as a prerelease ('true' or 'false'). type: string default: 'true' # forgejo-release uploads assets to a release in this repository. permissions: contents: write jobs: release: name: build and publish runs-on: linux-amd64 env: # cargo picks the linker for the aarch64 target from this; the host # already provides aarch64-linux-gnu-gcc. CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc steps: - name: Check out the workflow ref uses: actions/checkout@v4 # The :host runner runs steps in a minimal /bin/sh without the host's # cargo on PATH, and this act version propagates neither GITHUB_PATH nor # an in-step `export` to the command that needs it -- and $HOME is not # reliably set inside a run step. So each toolchain command carries an # absolute cargo path as a one-shot PATH prefix: no persistence, no $HOME. # The path is the ws-brn host's cargo home; if the runner host changes, # update it (or set the toolchain on PATH in the runner's own env). # Test before building so a release never ships a red build. The debug # build here is what run-hurl.sh exercises. - name: Run the Rust test suite run: PATH="/home/agents/brn/.cargo/bin:$PATH" 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 run: PATH="/home/agents/brn/.cargo/bin:$PATH" tests/run-hurl.sh # x86_64 is native; aarch64 std is needed for the cross build. Both are # idempotent if already present. - name: Add the Rust targets run: | PATH="/home/agents/brn/.cargo/bin:$PATH" rustup target add x86_64-unknown-linux-gnu PATH="/home/agents/brn/.cargo/bin:$PATH" rustup target add aarch64-unknown-linux-gnu - name: Build the release binaries run: | PATH="/home/agents/brn/.cargo/bin:$PATH" cargo build --release --locked --target x86_64-unknown-linux-gnu PATH="/home/agents/brn/.cargo/bin:$PATH" 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: | mkdir -p dist/release install -m 0755 target/x86_64-unknown-linux-gnu/release/anwesen \ "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 binaries to the Forgejo release uses: https://code.forgejo.org/actions/forgejo-release@v2 with: direction: upload url: ${{ env.GITHUB_SERVER_URL }} repo: ${{ github.repository }} token: ${{ secrets.RELEASE_TOKEN }} tag: ${{ inputs.tag }} sha: ${{ github.sha }} release-dir: dist/release prerelease: ${{ inputs.prerelease }} # A re-run for the same tag replaces the assets rather than failing. override: true