name: build image on: push: branches: [main] tags: ['v*'] pull_request: workflow_dispatch: inputs: variant: description: which variant to build type: choice default: minimal options: [minimal, workstation, both] jobs: # Which variants to build. Pushes and PRs build minimal only — it is the fast # one and it exercises the entire pipeline. Tags build everything. prepare: runs-on: metal outputs: variants: ${{ steps.pick.outputs.variants }} steps: - id: pick run: | if [ "${{ startsWith(github.ref, 'refs/tags/') }}" = "true" ]; then variants='["minimal","workstation"]' else case "${{ inputs.variant }}" in both) variants='["minimal","workstation"]' ;; workstation) variants='["workstation"]' ;; *) variants='["minimal"]' ;; esac fi echo "variants=$variants" | tee -a "$GITHUB_OUTPUT" build: needs: prepare runs-on: metal timeout-minutes: 600 strategy: fail-fast: false matrix: variant: ${{ fromJSON(needs.prepare.outputs.variants) }} steps: - uses: actions/checkout@v4 - name: Report runner run: | echo "host arch : $(uname -m)" echo "kernel : $(uname -r)" echo "user : $(id -un) (uid $(id -u))" echo "podman : $(podman --version 2>/dev/null || echo MISSING)" df -h . # Building an aarch64 root filesystem means executing aarch64 rpm # scriptlets, which needs a binfmt_misc handler in the host kernel. A # container cannot register one for itself. - name: Ensure aarch64 emulation run: | handler=/proc/sys/fs/binfmt_misc/qemu-aarch64 if [ ! -e "$handler" ]; then echo "no aarch64 binfmt handler, attempting to install one" sudo dnf install -y qemu-user-static-aarch64 sudo systemctl restart systemd-binfmt fi if [ ! -e "$handler" ]; then echo "::error::aarch64 emulation is unavailable on this runner." \ "See docs/runner-setup.md for the one-time host setup." exit 1 fi cat "$handler" # Both of these live outside the job workspace, which is wiped between # runs. On metal runners a host path persists for free and avoids # shuttling multi-gigabyte caches through Gitea's cache store — the # tradeoff being that they are per-runner, so a job landing on a runner # that has not built before starts cold. - name: Prepare persistent build state run: | echo "CACHE_DIR=/var/tmp/c630-build/dnf" >> "$GITHUB_ENV" echo "WORK_DIR=/var/tmp/c630-build/work" >> "$GITHUB_ENV" mkdir -p /var/tmp/c630-build/{dnf,work} # Keep it bounded: drop cached rpms nothing has touched in a month. find /var/tmp/c630-build/dnf -type f -atime +30 -delete 2>/dev/null || true du -sh /var/tmp/c630-build/* 2>/dev/null || true - name: Build run: | case "${{ matrix.variant }}" in workstation) size=16384 ;; *) size=8192 ;; esac # No --fresh: the stamp in stage2.sh hashes the package lists, so a # change there invalidates the staged base on its own. Checkout is # shallow here anyway, so diffing against HEAD~1 would not be reliable. ./build/build-image.sh \ --variant "${{ matrix.variant }}" \ --size "$size" \ --cache "$CACHE_DIR" \ --work "$WORK_DIR" - name: Checksums run: cat output/*.sha256 - uses: actions/upload-artifact@v4 with: name: fedora-${{ matrix.variant }}-lenovo-yoga-c630 path: | output/*.img.zst output/*.sha256 retention-days: 14 compression-level: 0 # already zstd - name: Attach to release if: startsWith(github.ref, 'refs/tags/') env: TOKEN: ${{ github.token }} SERVER: ${{ github.server_url }} REPO: ${{ github.repository }} TAG: ${{ github.ref_name }} run: | set -euo pipefail api="$SERVER/api/v1/repos/$REPO" auth="Authorization: token $TOKEN" # python3 rather than jq — jq is not guaranteed on a Fedora Server runner. field() { python3 -c 'import json,sys; print(json.load(sys.stdin).get(sys.argv[1],""))' "$1"; } id=$(curl -sf -H "$auth" "$api/releases/tags/$TAG" | field id || true) if [ -z "${id:-}" ]; then id=$(curl -sf -X POST -H "$auth" -H 'Content-Type: application/json' \ -d "{\"tag_name\":\"$TAG\",\"name\":\"$TAG\"}" \ "$api/releases" | field id) fi echo "release id: $id" for f in output/*.img.zst output/*.sha256; do echo "uploading $(basename "$f")" curl -sf -X POST -H "$auth" \ -F "attachment=@${f}" \ "$api/releases/$id/assets?name=$(basename "$f")" >/dev/null done