Replace pre-commit.sh with the pre-commit framework and drop the test harness
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful

The hand-rolled pre-commit.sh reimplemented what upstream hooks already do.
Move to pre-commit.com with the estate's usual pre-commit-hooks set plus
hadolint and shellcheck, and keep the one check with no upstream equivalent
(distros/ vs the Woodpecker matrices) as a repo: local hook.

The test harness goes; tests will be reintroduced differently.

- add .pre-commit-config.yaml and ci/check-distros.sh
- delete pre-commit.sh, test.sh and .woodpecker/test.yaml
- run uvx pre-commit run --all-files from .woodpecker/pre-commit.yaml and make pre-commit
- drop the Dockerfile test stage and the make test targets
This commit is contained in:
2026-09-27 20:17:04 +10:00
parent 03ab698efa
commit 63cf28c90e
9 changed files with 63 additions and 119 deletions
+30
View File
@@ -0,0 +1,30 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-merge-conflict
- id: mixed-line-ending
args: [--fix=lf]
- repo: https://github.com/AleksaC/hadolint-py
rev: v2.15.1
hooks:
- id: hadolint
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.11.0.1
hooks:
- id: shellcheck
# No upstream equivalent: a distro added under distros/ but left out of a
# Woodpecker matrix silently never gets built.
- repo: local
hooks:
- id: check-distros
name: distros match the woodpecker matrices
entry: ci/check-distros.sh
language: system
pass_filenames: false
+2 -2
View File
@@ -3,9 +3,9 @@ when:
steps:
- name: pre-commit
image: "docker.io/almalinux:9"
image: "git.unkin.net/unkin/almalinux9-gobuilder:20260606"
commands:
- ./pre-commit.sh
- uvx pre-commit run --all-files
backend_options:
kubernetes:
serviceAccountName: default
-35
View File
@@ -1,35 +0,0 @@
when:
- event: pull_request
matrix:
include:
# One entry per distro. Adding a distro: add distros/<name>/ and one entry here.
- DISTRO: alma9
IMAGE: almalinux9
BASE_IMAGE: "docker.io/almalinux:9"
steps:
# The test stage runs test.sh inside the freshly built image, so a failed assertion
# fails the build. No docker daemon required.
- name: test
image: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/plugin-docker-buildx:latest"
settings:
repo: "artifactapi.k8s.syd1.au.unkin.net/docker-internal/${IMAGE}"
target: test
dry_run: true
build_args:
BASE_IMAGE: "${BASE_IMAGE}"
DISTRO: "${DISTRO}"
buildkit_config: |
[registry."artifactapi.k8s.syd1.au.unkin.net"]
ca = ["/etc/docker/certs.d/artifactapi.k8s.syd1.au.unkin.net/ca.crt"]
backend_options:
kubernetes:
serviceAccountName: default
resources:
requests:
memory: 1Gi
cpu: 1
limits:
memory: 4Gi
cpu: 2
+4 -9
View File
@@ -3,6 +3,10 @@ ARG BASE_IMAGE=artifactapi.k8s.syd1.au.unkin.net/dockerhub/library/almalinux:9
FROM ${BASE_IMAGE} AS image
ARG DISTRO=alma9
COPY distros/${DISTRO}/ /tmp/distro/
# DL3041: versions are pinned by the estate dnf repos, not here. SC2086: $PACKAGES is a
# word list on purpose. DL4006: the only pipe ends in sha256sum, whose status is the
# pipeline's, and set -e catches it.
# hadolint ignore=DL3041,DL4006,SC2086
RUN set -eux; \
. /tmp/distro/distro.env; \
rm -f /etc/yum.repos.d/*.repo; \
@@ -16,12 +20,3 @@ RUN set -eux; \
dnf clean all; \
rm -rf /var/cache/dnf /tmp/ca.rpm /tmp/distro
CMD ["/bin/bash"]
# Built only via `--target test`; assertions run as a build step so a broken image
# fails the build, with no docker daemon needed in CI.
FROM image AS test
ARG DISTRO=alma9
COPY distros/${DISTRO}/distro.env test.sh /tmp/test/
RUN cd /tmp/test && ./test.sh
FROM image AS final
+4 -7
View File
@@ -2,11 +2,13 @@ REGISTRY := artifactapi.k8s.syd1.au.unkin.net/docker-internal
DISTROS := $(notdir $(wildcard distros/*))
VERSION ?= $(patsubst v%,%,$(or $(shell git describe --tags --exact-match 2>/dev/null),0.1.0-dev))
.PHONY: build test clean patch minor major
.PHONY: build clean pre-commit patch minor major
build: $(addprefix build-,$(DISTROS))
test: $(addprefix test-,$(DISTROS))
clean: $(addprefix clean-,$(DISTROS))
pre-commit:
@uvx pre-commit run --all-files
# Not .PHONY: GNU make skips implicit-rule search for phony targets.
build-%:
@@ -14,11 +16,6 @@ build-%:
docker build --build-arg "BASE_IMAGE=$$BASE_IMAGE" --build-arg "DISTRO=$*" \
-t "$(REGISTRY)/$$IMAGE:$(VERSION)" .
test-%:
@set -eu; . ./distros/$*/distro.env; \
docker build --target test --progress plain \
--build-arg "BASE_IMAGE=$$BASE_IMAGE" --build-arg "DISTRO=$*" .
clean-%:
@set -eu; . ./distros/$*/distro.env; \
docker rmi "$(REGISTRY)/$$IMAGE:$(VERSION)" 2>/dev/null || true
+3 -3
View File
@@ -15,9 +15,9 @@ configuration pointed at artifactapi, and installs the base package set.
1. `distros/<name>/distro.env` — `BASE_IMAGE`, `IMAGE`, `CA_RPM_URL`, `CA_RPM_SHA256`, `PACKAGES`.
2. `distros/<name>/yum.repos.d/*.repo` — repository configuration for that distro.
3. One `include` entry in each of `.woodpecker/{build,test,docker}.yaml`.
3. One `include` entry in each of `.woodpecker/{build,docker}.yaml`.
`pre-commit.sh` fails if step 3 is forgotten.
The `check-distros` pre-commit hook fails if step 1 or 3 is incomplete.
## CA bootstrap
@@ -30,6 +30,6 @@ pinned hash is the `pkgid` checksum recorded for the file in the repo's own repo
## Make
make build # build every distro
make test # build the test stage of every distro (assertions run in-image)
make pre-commit # uvx pre-commit run --all-files
make build-alma9 # one distro
make patch|minor|major
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# Every distros/<name>/ needs a complete distro.env and an entry in every Woodpecker
# matrix, or a newly added distro silently never gets built.
set -uo pipefail
KEYS="BASE_IMAGE IMAGE CA_RPM_URL CA_RPM_SHA256 ESTATE_REPO PACKAGES"
WORKFLOWS=(.woodpecker/build.yaml .woodpecker/docker.yaml)
fail=0
for d in distros/*/; do
n=$(basename "$d")
for k in $KEYS; do
grep -q "^${k}=" "${d}distro.env" || { echo "${d}distro.env: missing ${k}"; fail=1; }
done
for wf in "${WORKFLOWS[@]}"; do
grep -q "DISTRO: ${n}\$" "$wf" || { echo "${wf}: distro ${n} missing from matrix"; fail=1; }
done
done
exit "$fail"
-23
View File
@@ -1,23 +0,0 @@
#!/usr/bin/env bash
# Guards the one mistake this layout invites: a distro added under distros/ but left
# out of a .woodpecker matrix, so it silently never gets built.
set -uo pipefail
REQUIRED_KEYS="BASE_IMAGE IMAGE CA_RPM_URL CA_RPM_SHA256 ESTATE_REPO PACKAGES"
WORKFLOWS=".woodpecker/build.yaml .woodpecker/test.yaml .woodpecker/docker.yaml"
fail=0
for d in distros/*/; do
n=${d#distros/}; n=${n%/}
for k in $REQUIRED_KEYS; do
grep -q "^${k}=" "${d}distro.env" || { echo "${d}distro.env: missing ${k}"; fail=1; }
done
for wf in $WORKFLOWS; do
grep -q "DISTRO: ${n}\$" "$wf" || { echo "${wf}: distro ${n} missing from matrix"; fail=1; }
done
done
for s in ./*.sh; do bash -n "$s" || fail=1; done
[ "$fail" -eq 0 ] || { echo "FAILED"; exit 1; }
echo "PASS"
-40
View File
@@ -1,40 +0,0 @@
#!/usr/bin/env bash
# In-image assertions for the base image. Run via `docker build --target test`.
set -uo pipefail
ARTIFACTAPI=https://artifactapi.k8s.syd1.au.unkin.net
. ./distro.env
fail=0
check() {
local name=$1; shift
if out=$("$@" 2>&1); then
echo "ok $name"
else
echo "NOT OK $name"
printf '%s\n' "$out" | sed 's/^/ /'
fail=1
fi
}
# No -k and no --cacert: fails unless the bootstrapped internal CA is in the trust store.
check "internal CA trusted (artifactapi)" \
curl -fsS -o /dev/null "$ARTIFACTAPI/api/v1/local/$ESTATE_REPO/repodata/repomd.xml"
check "unkin-ca-certificates installed" rpm -q unkin-ca-certificates
# Every configured repo must refresh, and a package that exists only in the estate's
# local repos must resolve.
check "dnf refreshes every estate repo" dnf -q makecache --refresh
check "dnf resolves an estate-only package" \
dnf -q --disablerepo='*' --enablerepo="$ESTATE_REPO" list --available nfpm
for p in $PACKAGES; do
check "package $p installed" rpm -q "$p"
done
for c in git jq make wget uv python3.11 python3.12; do
check "$c runs" "$c" --version
done
[ "$fail" -eq 0 ] || { echo "FAILED"; exit 1; }
echo "PASS"