Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions .github/workflows/build-aarch64.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
name: Build aarch64 Packages

# Builds the aarch64 half of the repository on GitHub's native ARM64 runners,
# which are free for public repositories. The build system already supports
# aarch64 end to end -- bin/build, bin/sign, bin/update-repo and bin/sync-repo
# all take --arch -- but it has only ever been driven by hand, and the README
# tells you to emulate ARM64 on an x86_64 host with QEMU. Running it on a
# native runner removes the emulation entirely.
#
# This builds and uploads packages as artifacts; it deliberately does not
# publish. Publishing needs the repository signing key and the pkgs.omarchy.org
# credentials, so promoting these artifacts stays a maintainer step. Download
# the artifact into build-output/<mirror>/aarch64, then, with <mirror> matching
# the mirror the artifact was built against:
#
# bin/repo sign --arch aarch64 --mirror <mirror>
# bin/repo promote --arch aarch64 --mirror <mirror>
# bin/repo update --arch aarch64 --mirror <mirror>
# bin/repo sync --arch aarch64 --mirror <mirror>
#
# The update step is not optional. bin/promote-build moves package files into
# the published tree but deliberately skips omarchy-build.db*, and bin/repo
# update is the only thing that runs the repo-add that builds omarchy.db.
# Without it bin/sync-repo uploads packages and no database, and pacman clients
# pointed at the aarch64 tree resolve nothing. --mirror matters for the same
# reason: helpers/paths.sh defaults MIRROR to edge, so omitting it while
# promoting a stable artifact reads and writes the wrong tree.
#
# Packages whose PKGBUILD arch=() excludes aarch64 are skipped by
# should_build_for_arch() in build/build.sh, so hardware-specific x86 packages
# (nvidia, asusctl, intel-*) cost nothing here.

on:
workflow_dispatch:
inputs:
packages:
description: 'Specific packages to build (space-separated, leave empty for all)'
required: false
default: ''
mirror:
description: 'Mirror to build against'
required: false
default: edge
type: choice
options:
- edge
- stable

jobs:
build:
runs-on: ubuntu-24.04-arm
# A full unscoped build compiles every aarch64-capable package from source.
# GitHub caps a job at 6 hours. If the full set ever outgrows that, note
# that the packages input is not a general answer: build/build.sh builds
# only the names given and resolves inter-package dependencies solely
# within that set, and it configures the production [omarchy] repo only
# when a database already exists -- which on a clean runner it does not. So
# a batch has to be dependency-closed to succeed. pkgbuilds/omarchy, for
# instance, pins omarchy-settings=${pkgver} and fails at makepkg -s without
# it. The input is for targeted rebuilds; splitting a full build needs the
# batches chosen with that in mind.
timeout-minutes: 360
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false

- name: Confirm the runner is natively aarch64
# bin/build falls back to QEMU when it finds an x86_64 host. That still
# produces correct packages, but takes many times longer -- long enough
# to hit the job timeout. If this ever runs somewhere else, fail loudly
# rather than silently emulating.
run: |
set -euo pipefail
arch=$(uname -m)
echo "Runner architecture: $arch"
if [[ $arch != "aarch64" ]]; then
echo "::error::Expected a native aarch64 runner, got $arch." \
"Building aarch64 under emulation here would exceed the job timeout."
exit 1
fi

- name: Prepare the bind-mounted build directories
# bin/build bind-mounts build-output/ and pkgs.omarchy.org/ into the
# builder container, which works as the image's "builder" user (uid
# 1000, from the useradd in build/Dockerfile). A GitHub runner is uid
# 1001, and make_dir_writable() chowns these directories to the host
# user -- so the container cannot write its incremental
# omarchy-build.db, and pacman then fails to resolve any makedepends.
# This is invisible on a workstation where the developer is also uid
# 1000. chown preserves the mode, so opening the mode first leaves both
# users able to write.
env:
MIRROR: ${{ inputs.mirror }}
run: |
set -euo pipefail
echo "Runner uid: $(id -u)"
for dir in "build-output/$MIRROR/aarch64" "pkgs.omarchy.org/$MIRROR/aarch64"; do
mkdir -p "$dir"
chmod -R 777 "$dir"
done

- name: Build packages
env:
PACKAGES: ${{ inputs.packages }}
MIRROR: ${{ inputs.mirror }}
run: |
set -euo pipefail
if [[ -n $PACKAGES ]]; then
bin/build --arch aarch64 --mirror "$MIRROR" --package "$PACKAGES"
else
bin/build --arch aarch64 --mirror "$MIRROR"
fi

- name: Summarize what was built
if: always()
env:
MIRROR: ${{ inputs.mirror }}
run: |
set -euo pipefail
output="build-output/$MIRROR/aarch64"
{
echo "## aarch64 packages ($MIRROR)"
echo
if compgen -G "$output/*.pkg.tar.*" >/dev/null; then
echo '```'
(cd "$output" && ls -1 ./*.pkg.tar.*)
echo '```'
else
echo "No packages were produced."
fi
} >>"$GITHUB_STEP_SUMMARY"

- name: Upload packages
if: always()
uses: actions/upload-artifact@v4
with:
name: omarchy-aarch64-${{ inputs.mirror }}-${{ github.run_id }}
path: build-output/${{ inputs.mirror }}/aarch64
if-no-files-found: warn
retention-days: 14

- name: Notify Basecamp on failure
if: failure() && env.BASECAMP_CHATBOT_URL != ''
env:
BASECAMP_CHATBOT_URL: ${{ secrets.BASECAMP_CHATBOT_URL }}
run: |
curl -s -o /dev/null \
-H "Content-Type: application/json" \
-d "$(jq -n --arg content \
"🔴 <strong>aarch64 build failed</strong><br><a href=\"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\">View run</a>" \
'{content: $content}')" \
"$BASECAMP_CHATBOT_URL"
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ docker run --rm --platform linux/arm64 alpine:latest uname -m
# Should output: aarch64
```

**Note**: aarch64 builds use QEMU and slower than native x86_64 builds.
**Note**: aarch64 builds use QEMU and slower than native x86_64 builds. To avoid the
emulation entirely, run the **Build aarch64 Packages** workflow, which builds on native
ARM64 runners.

## Quick Start

Expand Down Expand Up @@ -536,6 +538,9 @@ bin/repo release --package my-package
- Uses Arch Linux ARM repositories
- Additional repos: `[alarm]`, `[aur]`
- Same workflow, just add `--arch aarch64`
- Or build natively in CI: the **Build aarch64 Packages** workflow runs on GitHub's
ARM64 runners, which need no emulation. Trigger it from the Actions tab; it uploads
the packages as an artifact and leaves signing and publishing to a maintainer.

### Building for Both Architectures

Expand Down
Loading