# Release builds for anwesen ([ANW-32], pattern from IT-86). # # Forgejo (carvers/anwesen on ap) is canonical for both code and releases. # GitHub is only the build farm -- it has the macOS runners. Publishing is a # single act on Forgejo: create a `v*` tag (or release) there, it mirrors to # the GitHub mirror, and that pushed tag triggers this workflow. For each # target the build job tests and builds the binary; a final publish job creates # the GitHub release with every binary, then mirrors them back onto the # matching Forgejo release. No manual "new release" step on GitHub. name: release on: push: tags: ['v*'] workflow_dispatch: inputs: tag: description: Existing tag to (re)build required: true # The publish job attaches binaries to the GitHub release it creates. permissions: contents: write env: # The Forgejo repo that receives the release assets (owner/name on ap). FORGEJO_REPO: carvers/anwesen FORGEJO_API: https://forge.crvrs.org/api/v1 jobs: build: name: ${{ matrix.label }} runs-on: ${{ matrix.runner }} strategy: # One target's failure should not cancel the others' builds. fail-fast: false matrix: include: # amd64 Linux -- the deploy target. Built natively on ubuntu-latest. - runner: ubuntu-latest label: x86_64-linux os: linux # arm64 Linux -- Graviton / Pi / ARM servers. Built natively. - runner: ubuntu-24.04-arm label: aarch64-linux os: linux # arm macOS -- aav's local machine. Built natively on Apple Silicon. - runner: macos-14 label: aarch64-macos os: macos steps: - name: Check out the release tag uses: actions/checkout@v4 with: ref: ${{ github.event.inputs.tag || github.ref_name }} # Stable channel; edition 2024 needs >= 1.85, and Cargo.toml pins the # MSRV at 1.95. Pin an explicit version here if a frozen release # toolchain is ever required. - name: Install the Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Cache cargo registry, index, and target uses: Swatinem/rust-cache@v2 # The HTTP contract harness (tests/run-hurl.sh, per ADR-008) boots # `anwesen serve` and runs hurl against it. The contract is # arch-independent, so it runs once on the deploy target; 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 coverage. - name: Install hurl if: matrix.label == 'x86_64-linux' run: | curl -fsSL -o /tmp/hurl.deb \ https://github.com/Orange-OpenSource/hurl/releases/download/8.0.0/hurl_8.0.0_amd64.deb sudo dpkg -i /tmp/hurl.deb # Test before building the artifact 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: cargo test --locked - name: Run the HTTP contract tests if: matrix.label == 'x86_64-linux' run: tests/run-hurl.sh - name: Build the release binary run: cargo build --release --locked # The runner is native to its target, so target/release/anwesen is the # target binary. Name it so the target is unambiguous on the release. - name: Name the asset for its target run: | install -m 0755 target/release/anwesen \ "anwesen-${{ github.event.inputs.tag || github.ref_name }}-${{ matrix.label }}" - name: Stash the binary for the publish job uses: actions/upload-artifact@v4 with: name: ${{ matrix.label }} path: anwesen-*-${{ matrix.label }} if-no-files-found: error publish: needs: build runs-on: ubuntu-latest steps: - name: Collect every target's binary uses: actions/download-artifact@v4 with: path: dist merge-multiple: true - name: Create the GitHub release with all binaries uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.event.inputs.tag || github.ref_name }} files: dist/* # Forgejo is canonical: push the same binaries onto the matching Forgejo # release. Find the release by tag; create it if the tag has no release # object yet; then upload each binary as an asset. - name: Mirror binaries to the Forgejo release env: TAG: ${{ github.event.inputs.tag || github.ref_name }} TOKEN: ${{ secrets.FORGEJO_RELEASE_TOKEN }} run: | set -euo pipefail auth="Authorization: token $TOKEN" base="$FORGEJO_API/repos/$FORGEJO_REPO/releases" id=$(curl -fsS -H "$auth" "$base/tags/$TAG" | jq -r '.id // empty') if [ -z "$id" ]; then id=$(curl -fsS -H "$auth" -H 'Content-Type: application/json' \ -X POST "$base" \ -d "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\"}" | jq -r '.id') fi for f in dist/*; do curl -fsS -H "$auth" \ -F "attachment=@$f;filename=$(basename "$f")" \ "$base/$id/assets?name=$(basename "$f")" >/dev/null echo "uploaded $(basename "$f")" done