Skip to content

Merge pull request #15 from ngrok/joelhans/persistent-oled #22

Merge pull request #15 from ngrok/joelhans/persistent-oled

Merge pull request #15 from ngrok/joelhans/persistent-oled #22

Workflow file for this run

name: Build node image
# Builds the little-internet Raspberry Pi OS image with pi-gen and publishes the
# compressed .img.xz — as a downloadable workflow artifact for every run, and as
# a GitHub Release asset when you push a version tag (e.g. v1.0.0).
#
# Run it manually from the Actions tab (workflow_dispatch) to test, or push a
# tag to cut a release.
on:
workflow_dispatch:
push:
tags:
- 'v*'
# Build on PRs, but only when the image itself changes — these builds are long,
# so we don't want to fire one on every PR push across the repo.
pull_request:
paths:
- 'image/**'
- '.github/workflows/build-image.yml'
# ...but a docs-only change to the image shouldn't trigger a ~37-min build.
# A later '!' pattern overrides an earlier match, so a PR touching only
# Markdown under image/ is excluded; one touching real image files still
# builds.
- '!image/**/*.md'
# pi-gen builds are long and disk-heavy; don't run two at once for the same ref.
# On a PR, cancel an in-flight build when a newer commit is pushed so rapid
# pushes don't stack hour-long runs; leave tag/release builds to finish.
concurrency:
group: build-image-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: write # needed to attach the image to a Release on tag pushes
jobs:
build:
# Native arm64 runner — free for public repos and builds the arm64 image
# without QEMU emulation (the QEMU step below is a harmless no-op here).
runs-on: ubuntu-24.04-arm
timeout-minutes: 180
steps:
- name: Check out the repo
uses: actions/checkout@v6
with:
# Full history + tags so build.sh's `git describe` can resolve the
# image version label (a clean tag like v0.3.1 on a release build,
# otherwise <tag>-<n>-g<sha>). A shallow checkout has no tags.
fetch-depth: 0
# pi-gen's Lite build plus the xz output needs a few GB of scratch space.
# GitHub's runners ship with a lot of preinstalled SDKs we don't use;
# reclaim that headroom so a long build never dies on a full disk.
- name: Free up disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache/CodeQL || true
df -h /
# On this native arm64 runner pi-gen builds without emulation, so QEMU
# isn't strictly needed and this install is effectively a no-op. We keep
# it as belt-and-suspenders: qemu-user-static provides the
# qemu-aarch64-static *binary* and registers the binfmt handlers with the
# fix-binary (F) flag, which is what pi-gen's preflight requires (plain
# binfmt registration via docker/setup-qemu-action isn't enough) should
# the workflow ever fall back to an x86 cross-build.
- name: Install QEMU for arm64 emulation
run: |
sudo apt-get update
sudo apt-get install -y qemu-user-static binfmt-support
# Build inside pi-gen's own Debian container. That sidesteps the
# debootstrap keyring trap you hit building Bookworm on a non-Debian host
# (the runner is Ubuntu), and means we don't need the native build deps.
- name: Build the image
working-directory: image
env:
USE_DOCKER: '1'
run: ./build.sh
- name: Locate the built image
id: image
run: |
img="$(ls image/build/pi-gen/deploy/*.img.xz | head -n1)"
echo "Found image: $img"
echo "path=$img" >> "$GITHUB_OUTPUT"
echo "name=$(basename "$img")" >> "$GITHUB_OUTPUT"
- name: Upload image as a workflow artifact
uses: actions/upload-artifact@v7
with:
name: ${{ steps.image.outputs.name }}
path: ${{ steps.image.outputs.path }}
if-no-files-found: error
# The image is already xz-compressed; don't waste time re-zipping it.
compression-level: 0
- name: Attach image to the Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v3
with:
files: ${{ steps.image.outputs.path }}
fail_on_unmatched_files: true