All checks were successful
Build kernel module / build (1:6.18.34-1+rpt1, trixie) (pull_request) Successful in 49s
Build kernel module / build (1:6.12.93-1+rpt1, bookworm) (pull_request) Successful in 1m9s
Build kernel module / package (pull_request) Successful in 18s
Build kernel module / release (pull_request) Has been skipped
Enable packaging and artifact upload for pull requests to facilitate testing. Package job generates a zip archive identical to release artifacts, allowing smoke tests before final releases. Adjusted naming for zip files to include PR reference or SHA for traceability.
175 lines
7.7 KiB
YAML
175 lines
7.7 KiB
YAML
name: Build kernel module
|
|
|
|
on:
|
|
# Release flow: triggered when a version tag is pushed (tag a commit on master).
|
|
# Builds every target and publishes the modules to a Gitea release.
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
# Compile-check flow: every PR that targets master. Builds only, no release.
|
|
pull_request:
|
|
branches:
|
|
- master
|
|
|
|
jobs:
|
|
# Build (and thereby compile-check) the module for each pinned kernel version.
|
|
# Runs on both triggers — on a PR this is the whole story; on a tag the
|
|
# `release` job below consumes the artifacts.
|
|
#
|
|
# HEADERS_PKG is fixed to linux-headers-rpi-v8 (64-bit, Pi Zero 2 W): the -v6/-v7
|
|
# headers are 32-bit (armhf) and aren't carried by the arm64 raspberrypi archive
|
|
# this arm64 builder uses.
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HEADERS_PKG: linux-headers-rpi-v8
|
|
strategy:
|
|
# Don't cancel the other versions if one fails to build.
|
|
fail-fast: false
|
|
matrix:
|
|
# Each raspberrypi archive suite only carries its own latest kernel, so
|
|
# the Debian base suite is paired with the kernel version it can install:
|
|
# bookworm -> 6.12.x, trixie -> 6.18.x.
|
|
include:
|
|
- kernel_version: "1:6.12.93-1+rpt1"
|
|
suite: bookworm
|
|
- kernel_version: "1:6.18.34-1+rpt1"
|
|
suite: trixie
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Build module (${{ matrix.kernel_version }})
|
|
working-directory: kernel
|
|
env:
|
|
HEADERS_PKG: ${{ env.HEADERS_PKG }}
|
|
KERNEL_VERSION: ${{ matrix.kernel_version }}
|
|
DEBIAN_SUITE: ${{ matrix.suite }}
|
|
run: |
|
|
set -eux
|
|
# arm64 emulation for the builder image (no-op if already registered).
|
|
if [ ! -e /proc/sys/fs/binfmt_misc/qemu-aarch64 ]; then
|
|
docker run --privileged --rm tonistiigi/binfmt --install arm64
|
|
fi
|
|
# Per-version image tag. The matrix entries can run concurrently on a
|
|
# single runner sharing one Docker daemon; a fixed tag (e.g. iec-kbuild)
|
|
# is then a shared mutable name and the builds race — whichever `docker
|
|
# build` finishes last wins the tag, so both `docker create` calls
|
|
# resolve to the same image and every job emits the same vermagic.
|
|
# A unique tag per kernel version isolates them. Docker tags allow only
|
|
# [a-zA-Z0-9._-], so map ':' '/' '+' (all present in 1:6.12.93-1+rpt1)
|
|
# to '-'; the tag just needs to be unique and valid, not reversible.
|
|
img="iec-kbuild:${KERNEL_VERSION//[:\/+]/-}"
|
|
# Builder image: toolchain + matching raspberrypi kernel headers.
|
|
docker build --platform linux/arm64 \
|
|
--build-arg DEBIAN_SUITE="$DEBIAN_SUITE" \
|
|
--build-arg HEADERS_PKG="$HEADERS_PKG" \
|
|
--build-arg KERNEL_VERSION="$KERNEL_VERSION" \
|
|
-t "$img" .
|
|
# Compile inside the container. We use `docker cp` instead of the bind
|
|
# mount that build-in-docker.sh uses for local builds: under the runner's
|
|
# docker-in-docker, /workspace is a volume the host daemon can't see, so
|
|
# `-v "$PWD:/build"` mounts an empty dir and make finds no Makefile.
|
|
cid=$(docker create --platform linux/arm64 --entrypoint sleep "$img" infinity)
|
|
docker start "$cid"
|
|
docker cp ./. "$cid:/build"
|
|
docker exec "$cid" /usr/local/bin/docker-entrypoint.sh clean
|
|
docker exec "$cid" /usr/local/bin/docker-entrypoint.sh
|
|
docker cp "$cid:/build/iec_listener.ko" ./iec_listener.ko
|
|
docker rm -f "$cid"
|
|
docker rmi "$img" || true
|
|
|
|
- name: Stage build output (modules/iec_listener_<kernel_version>.ko)
|
|
working-directory: kernel
|
|
run: |
|
|
ver="${{ matrix.kernel_version }}"
|
|
safe="${ver//[:\/]/-}" # path-friendly: 1:6.12.93-1+rpt1 -> 1-6.12.93-1+rpt1
|
|
echo "kernel version $ver -> file modules/iec_listener_${safe}.ko"
|
|
mkdir -p out/modules
|
|
mv iec_listener.ko "out/modules/iec_listener_${safe}.ko"
|
|
# Expose the path-friendly name for the (colon-rejecting) artifact name.
|
|
echo "SAFE_VER=$safe" >> "$GITHUB_ENV"
|
|
|
|
- name: Upload build output
|
|
uses: https://github.com/christopherHX/gitea-upload-artifact@v4
|
|
with:
|
|
# Name by the path-friendly version so artifact names stay unique; all
|
|
# of them merge back into the single modules/ folder at download time.
|
|
name: ${{ env.SAFE_VER }}
|
|
path: kernel/out
|
|
if-no-files-found: error
|
|
|
|
# Merge all built modules into one modules/ folder, wrap it in a single
|
|
# repo-named top folder alongside the helper scripts (selftest.sh, launch.sh)
|
|
# and the iecpoc Python frontend (so launch.sh can pip-install it on the Pi),
|
|
# and zip it. Runs on BOTH triggers and uploads the zip as an artifact: on a PR
|
|
# this lets you download and smoke-test the exact archive a release would ship;
|
|
# on a tag the release job below republishes this same artifact unchanged.
|
|
package:
|
|
needs: build
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Download all build output
|
|
uses: https://github.com/christopherHX/gitea-download-artifact@v4
|
|
with:
|
|
path: dist
|
|
# Merge every per-kernel artifact back into the shared modules/ folder.
|
|
merge-multiple: true
|
|
|
|
- name: Determine version label
|
|
id: ver
|
|
run: |
|
|
# Tags ship under the tag name; PR builds get a traceable pr<n>-<sha>.
|
|
case "${{ github.ref }}" in
|
|
refs/tags/*) v="${{ github.ref_name }}" ;;
|
|
*) v="pr${{ github.event.pull_request.number }}-$(echo "${{ github.sha }}" | cut -c1-7)" ;;
|
|
esac
|
|
echo "ver=$v" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Assemble package zip
|
|
run: |
|
|
repo="${{ github.event.repository.name }}"
|
|
root="package/$repo"
|
|
mkdir -p "$root"
|
|
cp -r dist/modules "$root"/ # modules/iec_listener_<kernel_version>.ko
|
|
cp kernel/selftest.sh "$root"/ # one-shot hardware self-test
|
|
cp launch.sh "$root"/ # load module -> run frontend -> unload
|
|
# iecpoc Python frontend + its packaging metadata. launch.sh pip-installs
|
|
# this on the Pi; the build reads pyproject.toml's readme = "README.md",
|
|
# so README.md must travel with it. __pycache__ is stripped to stay clean.
|
|
cp pyproject.toml README.md "$root"/
|
|
cp -r iecpoc "$root"/
|
|
find "$root/iecpoc" -name __pycache__ -type d -prune -exec rm -rf {} +
|
|
(cd package && zip -r "../${repo}-${{ steps.ver.outputs.ver }}.zip" "$repo")
|
|
|
|
- name: Upload package zip
|
|
uses: https://github.com/christopherHX/gitea-upload-artifact@v4
|
|
with:
|
|
name: ${{ github.event.repository.name }}-${{ steps.ver.outputs.ver }}
|
|
path: ${{ github.event.repository.name }}-*.zip
|
|
if-no-files-found: error
|
|
|
|
# Release flow only: takes the zip the package job already built and attaches it
|
|
# to the Gitea release for the pushed tag. No re-assembly here. Skipped on PRs.
|
|
release:
|
|
needs: package
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Download package zip
|
|
uses: https://github.com/christopherHX/gitea-download-artifact@v4
|
|
with:
|
|
# The single artifact the package job produced for this tag.
|
|
name: ${{ github.event.repository.name }}-${{ github.ref_name }}
|
|
path: dist
|
|
|
|
- name: Publish to Gitea release
|
|
uses: https://gitea.com/actions/gitea-release-action@v1.3.6
|
|
with:
|
|
api_key: ${{ secrets.GITEA_TOKEN }}
|
|
files: |-
|
|
dist/*.zip
|