mirror of
https://github.com/BetterCorp/BetterFrame.git
synced 2026-05-26 19:06:34 +00:00
feat(release): pi-gen image build pipeline (flashable .img.xz on tag push)
New workflow .github/workflows/release-image.yml takes a tagged kiosk
release binary, layers it onto Raspberry Pi OS Trixie Lite via a custom
pi-gen stage, and publishes the resulting .img.xz back to the GitHub
Release.
Custom stage deploy/pi-gen/stage-betterframe-client/:
- 00-install-packages: cage, seatd, plymouth, gtk4 runtime, gstreamer,
libwebkitgtk-6.0, wlr-randr, ca-certificates
- 01-install-kiosk: drops the prebuilt kiosk binary, systemd unit,
cage PAM stack, firmware-rollback hook, plymouth theme. Creates
bfkiosk user, sets multi-user.target, masks all display managers,
purges piwiz, edits cmdline/config for the BF splash. Mirrors
setup-pi-kiosk.sh but baked into the image.
End state: rpi-imager → SD → boot → pairing screen on the HDMI display,
no operator setup steps. Kiosk auto-discovers server via discover_server()
(localhost → mDNS → frame-eu.betterportal.net).
Heavy build (~30-60 min on GH-hosted Ubuntu) so tag-push triggered, not
master. Workflow_dispatch also supports baking an existing release tag's
binary into a fresh image without re-tagging.
This commit is contained in:
parent
093f4947a1
commit
9699036bb2
3 changed files with 199 additions and 0 deletions
104
.github/workflows/release-image.yml
vendored
Normal file
104
.github/workflows/release-image.yml
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
# Build burnable Raspberry Pi OS images for the BetterFrame kiosk on tag push.
|
||||||
|
#
|
||||||
|
# Output: betterframe-client-<version>-aarch64.img.xz attached to the GitHub
|
||||||
|
# Release. Burn with rpi-imager / dd, boot the Pi, kiosk discovers a BF server
|
||||||
|
# on the LAN or falls through to the cloud (frame-eu.betterportal.net).
|
||||||
|
#
|
||||||
|
# Image source: official Raspberry Pi OS Trixie (Lite) base with a custom
|
||||||
|
# pi-gen stage (`deploy/pi-gen/stage-betterframe-client/`) layered on top.
|
||||||
|
#
|
||||||
|
# Heavy build (~30-60 min). Tag-push only — too slow for every master commit.
|
||||||
|
|
||||||
|
name: release-image
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
kiosk_artifact_tag:
|
||||||
|
description: "Existing release tag whose kiosk binary to bake in (e.g. v0.4.2). Empty = same tag as this run."
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
image:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Resolve kiosk binary source
|
||||||
|
id: src
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref_type }}" == "tag" ]]; then
|
||||||
|
tag="${GITHUB_REF#refs/tags/}"
|
||||||
|
else
|
||||||
|
tag="${{ inputs.kiosk_artifact_tag }}"
|
||||||
|
[ -z "$tag" ] && { echo "kiosk_artifact_tag input required for workflow_dispatch"; exit 1; }
|
||||||
|
fi
|
||||||
|
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "version=${tag#v}" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Download kiosk aarch64 binary from release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
TAG: ${{ steps.src.outputs.tag }}
|
||||||
|
run: |
|
||||||
|
mkdir -p staging
|
||||||
|
gh release download "$TAG" \
|
||||||
|
--pattern "betterframe-kiosk-*-aarch64-unknown-linux-gnu" \
|
||||||
|
--output staging/betterframe-kiosk \
|
||||||
|
--repo "$GITHUB_REPOSITORY"
|
||||||
|
chmod +x staging/betterframe-kiosk
|
||||||
|
# Render BF logo for plymouth (rsvg-convert is in the runner).
|
||||||
|
sudo apt-get -y update
|
||||||
|
sudo apt-get -y install --no-install-recommends librsvg2-bin
|
||||||
|
rsvg-convert -w 480 server/src/web-static/betterframe-logo.svg -o staging/logo.png
|
||||||
|
|
||||||
|
- name: Stage files for pi-gen
|
||||||
|
run: |
|
||||||
|
mkdir -p deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files
|
||||||
|
cp staging/betterframe-kiosk \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
|
cp staging/logo.png \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
|
cp deploy/systemd/betterframe-kiosk.service \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
|
cp deploy/systemd/betterframe-firmware-rollback.sh \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
|
cp deploy/pam.d/cage \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/cage.pam
|
||||||
|
cp deploy/plymouth/betterframe/betterframe.plymouth \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
|
cp deploy/plymouth/betterframe/betterframe.script \
|
||||||
|
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/files/
|
||||||
|
chmod +x deploy/pi-gen/stage-betterframe-client/01-install-kiosk/00-run-chroot.sh
|
||||||
|
|
||||||
|
- name: Build Pi image (pi-gen)
|
||||||
|
uses: usimd/pi-gen-action@v1
|
||||||
|
with:
|
||||||
|
image-name: betterframe-client-${{ steps.src.outputs.version }}
|
||||||
|
# Lite base, no desktop. Plus our custom stage.
|
||||||
|
stage-list: stage0 stage1 stage2 ./deploy/pi-gen/stage-betterframe-client
|
||||||
|
release: trixie
|
||||||
|
enable-ssh: 1
|
||||||
|
# Bake a default user — operator can change later. Pi-imager-style
|
||||||
|
# first-run wizard is purged inside our stage anyway.
|
||||||
|
username: bfadmin
|
||||||
|
password: betterframe
|
||||||
|
locale: en_US.UTF-8
|
||||||
|
timezone: Etc/UTC
|
||||||
|
hostname: betterframe-kiosk
|
||||||
|
compression: xz
|
||||||
|
|
||||||
|
- name: Upload image to GitHub Release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
uses: softprops/action-gh-release@v2
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
deploy/image-betterframe-client-${{ steps.src.outputs.version }}-lite.img.xz
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
cage
|
||||||
|
seatd
|
||||||
|
plymouth
|
||||||
|
plymouth-themes
|
||||||
|
librsvg2-bin
|
||||||
|
libgtk-4-1
|
||||||
|
libgstreamer1.0-0
|
||||||
|
libgstreamer-plugins-base1.0-0
|
||||||
|
libwebkitgtk-6.0-4
|
||||||
|
gstreamer1.0-plugins-base
|
||||||
|
gstreamer1.0-plugins-good
|
||||||
|
gstreamer1.0-plugins-bad
|
||||||
|
gstreamer1.0-libav
|
||||||
|
v4l-utils
|
||||||
|
wlr-randr
|
||||||
|
ca-certificates
|
||||||
79
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/00-run-chroot.sh
Executable file
79
deploy/pi-gen/stage-betterframe-client/01-install-kiosk/00-run-chroot.sh
Executable file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#!/bin/bash -e
|
||||||
|
# Runs inside the pi-gen chroot. Installs the BetterFrame kiosk binary +
|
||||||
|
# systemd unit + cage PAM + plymouth theme. Mirrors setup-pi-kiosk.sh but
|
||||||
|
# baked into the image so first boot is fully provisioned.
|
||||||
|
|
||||||
|
# --- bfkiosk user ---
|
||||||
|
if ! id -u bfkiosk >/dev/null 2>&1; then
|
||||||
|
useradd -m -s /usr/sbin/nologin bfkiosk
|
||||||
|
fi
|
||||||
|
for grp in video render input audio; do
|
||||||
|
if getent group "$grp" >/dev/null; then
|
||||||
|
usermod -a -G "$grp" bfkiosk
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# --- Binary ---
|
||||||
|
install -d -m 755 /opt/betterframe/kiosk
|
||||||
|
install -m 755 /tmp/bf-files/betterframe-kiosk /opt/betterframe/kiosk/betterframe-kiosk
|
||||||
|
|
||||||
|
# --- Systemd unit + PAM + rollback hook ---
|
||||||
|
install -m 644 /tmp/bf-files/betterframe-kiosk.service /etc/systemd/system/betterframe-kiosk.service
|
||||||
|
install -m 644 /tmp/bf-files/cage.pam /etc/pam.d/cage
|
||||||
|
install -m 755 /tmp/bf-files/betterframe-firmware-rollback.sh \
|
||||||
|
/usr/local/sbin/betterframe-firmware-rollback.sh
|
||||||
|
|
||||||
|
# Default env file — operator may edit on first boot to point at their server.
|
||||||
|
cat > /etc/default/betterframe-kiosk <<'EOF'
|
||||||
|
# Runtime env for betterframe-kiosk. Edit and `systemctl restart betterframe-kiosk`.
|
||||||
|
# Override the BF server discovery (default tries localhost → betterframe.local
|
||||||
|
# → frame-eu.betterportal.net):
|
||||||
|
# BETTERFRAME_SERVER=https://frame.example.com
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Plymouth boot splash
|
||||||
|
install -d -m 755 /usr/share/plymouth/themes/betterframe
|
||||||
|
install -m 644 /tmp/bf-files/betterframe.plymouth /usr/share/plymouth/themes/betterframe/betterframe.plymouth
|
||||||
|
install -m 644 /tmp/bf-files/betterframe.script /usr/share/plymouth/themes/betterframe/betterframe.script
|
||||||
|
install -m 644 /tmp/bf-files/logo.png /usr/share/plymouth/themes/betterframe/logo.png
|
||||||
|
plymouth-set-default-theme betterframe || true
|
||||||
|
|
||||||
|
# --- Enable services, disable noise ---
|
||||||
|
systemctl enable seatd
|
||||||
|
systemctl enable betterframe-kiosk.service
|
||||||
|
|
||||||
|
# Boot to multi-user, no display manager, no welcome wizard, no getty on tty1.
|
||||||
|
systemctl set-default multi-user.target
|
||||||
|
for dm in lightdm gdm gdm3 sddm; do
|
||||||
|
systemctl disable "${dm}.service" 2>/dev/null || true
|
||||||
|
systemctl mask "${dm}.service" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
systemctl disable getty@tty1.service 2>/dev/null || true
|
||||||
|
|
||||||
|
# piwiz first-run wizard + userconf-pi → out.
|
||||||
|
apt-get -y purge piwiz userconf-pi 2>/dev/null || true
|
||||||
|
rm -f /etc/xdg/autostart/piwiz.desktop
|
||||||
|
|
||||||
|
# Suppress console motd / issue.
|
||||||
|
: > /etc/motd
|
||||||
|
printf 'BetterFrame Kiosk\n\n' > /etc/issue
|
||||||
|
rm -f /etc/update-motd.d/* 2>/dev/null || true
|
||||||
|
|
||||||
|
# Boot config: quiet splash + no rainbow.
|
||||||
|
if [ -f /boot/firmware/cmdline.txt ]; then BOOT_DIR=/boot/firmware
|
||||||
|
else BOOT_DIR=/boot; fi
|
||||||
|
CMDLINE="${BOOT_DIR}/cmdline.txt"
|
||||||
|
CONFIG="${BOOT_DIR}/config.txt"
|
||||||
|
if [ -f "$CMDLINE" ]; then
|
||||||
|
for flag in quiet splash plymouth.ignore-serial-consoles loglevel=0 vt.global_cursor_default=0 logo.nologo; do
|
||||||
|
if ! grep -qw -- "$flag" "$CMDLINE"; then
|
||||||
|
sed -i "s|\$| $flag|" "$CMDLINE"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ -f "$CONFIG" ] && ! grep -q '^disable_splash=1' "$CONFIG"; then
|
||||||
|
printf '\n# BetterFrame: disable firmware rainbow splash\ndisable_splash=1\n' >> "$CONFIG"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf /tmp/bf-files
|
||||||
|
echo "BetterFrame kiosk stage complete."
|
||||||
Loading…
Reference in a new issue