All checks were successful
Build kernel module / build (1:6.18.34-1+rpt1, trixie) (pull_request) Successful in 1m10s
Build kernel module / build (1:6.12.93-1+rpt1, bookworm) (pull_request) Successful in 1m10s
Build kernel module / package (pull_request) Successful in 21s
Build kernel module / release (pull_request) Has been skipped
189 lines
8.4 KiB
YAML
189 lines
8.4 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).
|
|
# Runs on BOTH triggers and uploads the assembled FOLDER as an artifact: on a PR
|
|
# this lets you download and smoke-test the exact tree a release would ship; on a
|
|
# tag the release job below zips this same tree and attaches it.
|
|
#
|
|
# We intentionally upload the folder, not a pre-made .zip: artifacts are always
|
|
# transported as a zip by the platform, so uploading a .zip would nest one zip
|
|
# inside another. Uploading the tree makes the platform's wrapper zip *be* the
|
|
# package archive (a single, clean layer).
|
|
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 tree
|
|
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 {} +
|
|
|
|
- name: Upload package
|
|
uses: https://github.com/christopherHX/gitea-upload-artifact@v4
|
|
with:
|
|
name: ${{ github.event.repository.name }}-${{ steps.ver.outputs.ver }}
|
|
# Upload the contents of package/, so the artifact zip contains the
|
|
# single top folder package/<repo>/ -> <repo>/...
|
|
path: package
|
|
if-no-files-found: error
|
|
|
|
# Release flow only: download the assembled tree the package job uploaded, zip it
|
|
# into the named release asset and attach it to the Gitea release for the pushed
|
|
# tag. No re-assembly here (the tree is taken as-is). Skipped on PRs.
|
|
release:
|
|
needs: package
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Download package
|
|
uses: https://github.com/christopherHX/gitea-download-artifact@v4
|
|
with:
|
|
# The single artifact the package job produced for this tag; extracts to
|
|
# dist/<repo>/...
|
|
name: ${{ github.event.repository.name }}-${{ github.ref_name }}
|
|
path: dist
|
|
|
|
- name: Zip release asset
|
|
run: |
|
|
repo="${{ github.event.repository.name }}"
|
|
chmod +x "dist/$repo/launch.sh" "dist/$repo/selftest.sh"
|
|
(cd dist && zip -r "../${repo}-${{ github.ref_name }}.zip" "$repo")
|
|
|
|
- name: Publish to Gitea release
|
|
uses: https://gitea.com/actions/gitea-release-action@v1.3.6
|
|
with:
|
|
api_key: ${{ secrets.GITEA_TOKEN }}
|
|
files: |-
|
|
${{ github.event.repository.name }}-${{ github.ref_name }}.zip
|