app-build/README.md
Philip Peterson 8c5362376a Build each architecture on its own runner, from the app's matrix
runner-arm64-linux builds arm64 natively. archs still defaults to both, on
one runner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 21:50:10 -09:00

2.8 KiB

app-build

A Forgejo action for our in-house apps (layer-wizard, dnf-package-store, swap-watchdog, …): on every push to an app's main,

  1. build it as an RPM for x86_64 and aarch64, packaged by the app's own packaging/<name>.spec, in a Fedora container per architecture: each natively on its own runner (runner-x86-linux, runner-arm64-linux), from a matrix in the app's workflow;
  2. upload the RPMs to the forge's quine RPM group, https://forge.quinefoundation.com/api/packages/quine-global-labs/rpm/quine, which quine-linux's image installs them from.

The build itself lives here, so a fix (a new Flutter release, another architecture) lands in every app at once.

Using it

In the app's repo, .forgejo/workflows/rpm.yml:

name: RPM

on:
  push:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: rpm-${{ github.ref }}
  cancel-in-progress: true

jobs:
  rpm:
    strategy:
      matrix:
        include:
          - arch: amd64
            runner: runner-x86-linux
          - arch: arm64
            runner: runner-arm64-linux
    runs-on: ${{ matrix.runner }}
    steps:
      - uses: https://forge.quinefoundation.com/quine-global-labs/mirror-actions-checkout@v4
        with:
          fetch-depth: 0
      - uses: https://forge.quinefoundation.com/quine-global/app-build@v1
        with:
          name: swap-watchdog
          kind: go
          archs: ${{ matrix.arch }}
          go-packages: ./cmd/swap-watchdog ./cmd/force-quit-gui
          dnf-packages: gtk3-devel
          registry-username: ${{ vars.REGISTRY_USER || github.actor }}
          registry-password: ${{ secrets.REGISTRY_TOKEN }}

fetch-depth: 0 isn't needed for the build, but the release number uses the commit's short hash.

Inputs (action.yml has them all):

Input
name Package name; the spec is packaging/<name>.spec
kind flutter or go
go-packages Go only: packages built into bin/
dnf-packages Extra Fedora packages for the build (e.g. gtk3-devel for cgo GTK)
archs What to build here; default amd64 arm64, both on one runner (the other one under QEMU emulation, slow). With the matrix above, each job builds its runner's own
fedora Default 44

What the spec gets

rpmbuild defines version_, release_ (<UTC timestamp>.git<hash>) and srcdir (the checkout). Specs install from what the build left there instead of building in %build:

  • go: the binaries in %{srcdir}/bin/; version 0.
  • flutter: %{bundle}, the release bundle (build/linux/<x64|arm64>/release/bundle); the version is pubspec.yaml's.

The spec needs ExclusiveArch: x86_64 aarch64 (or whatever archs builds).

Versions

@v1 follows compatible changes; a change that needs apps to change (an input renamed, the spec contract) gets v2.