ci: no quick check on master after a merge (#119); the runner image's recipe (#120)

Captain Bob, 2026-11-06: a small server, a little sluggish. Each change
cost about an hour of runner time; the gate itself is about 15 minutes.

#119 -- build.yml runs on pushes to the working branch only. What
reaches master arrives through a PR whose content just passed
acceptance; checking it again cost ~23 minutes after every merge.

#120, first step -- ci/runner-image/Dockerfile: gitea/runner-images'
Ubuntu 24.04 (with Node, for the actions) plus what
make ARCH=amd64,aarch64,riscv64 init INIT_DOCS=0 installs -- run from
the Makefile itself, not a copied list -- and Maven for publishing.
.gitea/workflows/runner-image.yml builds it and publishes it to the
package registry as lithosananke-runner:<commit>. The workflows switch
to it in a later change, once it is published and has passed
acceptance. It needs the runner to lend jobs its Docker daemon
(container.docker_host: automount) and a PACKAGES_TOKEN secret, unless
the Actions token may publish packages.

make init does git lfs install --local only inside a checkout: the
image build is not one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
This commit is contained in:
rajames
2026-11-06 20:43:42 +00:00
co-authored by Claude Opus 5.5
parent 4f6a267be4
commit 672d275f5c
4 changed files with 69 additions and 4 deletions
+4 -3
View File
@@ -1,5 +1,6 @@
# The quick check on every push: each board's image builds, and the v4 tests pass. A pull
# request into master is gated by acceptance.yml, the full acceptance protocol.
# The quick check on every push to the working branch: each board's image builds, and the v4
# tests pass. A pull request into master is gated by acceptance.yml, the full acceptance protocol;
# master itself is not checked again after a merge -- its content is what acceptance just passed.
# Nothing is published here. The nightlies own the rest: nightly.yml (the QEMU acceptance boots,
# the 32-bit build, the Isabelle/HOL proofs, the images to Nexus) and nightly-docs.yml (the
# documents to Nexus).
@@ -7,7 +8,7 @@ name: Build
on:
push:
branches: [master, StarForth-v4.0.0]
branches: [StarForth-v4.0.0] # not master: what reaches it has just passed acceptance (#119)
workflow_dispatch:
jobs:
+49
View File
@@ -0,0 +1,49 @@
# Builds the CI runner image (ci/runner-image/Dockerfile, #120) and publishes it to this
# repository's package registry, tagged with the commit it was built from:
#
# gitea.starshipos-f18.org/rajames/lithosananke-runner:<commit>
#
# The workflows name that tag as their container once it is published and has passed acceptance.
#
# Needs the runner to give jobs its Docker daemon (act_runner config.yaml, container.docker_host:
# automount), and a secret PACKAGES_TOKEN -- a token with write:package -- unless the Actions
# token may publish packages here.
name: Runner image
on:
push:
branches: [master]
paths: ['ci/runner-image/**', 'Makefile']
workflow_dispatch:
jobs:
image:
name: Build and publish the runner image
runs-on: ubuntu-latest
container:
image: gitea/runner-images:ubuntu-24.04-v26.11.03
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
lfs: false
- name: Docker is reachable
run: |
docker info >/dev/null 2>&1 || {
echo "::error::No Docker daemon in this job. Set container.docker_host: automount in the runner's config.yaml, or build the image on the server: see this file's header."
exit 1; }
- name: Build and publish
env:
TOKEN: ${{ secrets.PACKAGES_TOKEN || secrets.GITEA_TOKEN }}
run: |
set -e
img=gitea.starshipos-f18.org/rajames/lithosananke-runner
tag=$(git rev-parse --short=12 HEAD)
ctx=$(mktemp -d) # not the repository: 7 GB of context
cp -r Makefile boards ci/runner-image/Dockerfile "$ctx/"
docker build -t "$img:$tag" "$ctx"
echo "$TOKEN" | docker login gitea.starshipos-f18.org -u rajames --password-stdin
docker push "$img:$tag"
echo "Published $img:$tag"
+2 -1
View File
@@ -314,7 +314,8 @@ init:
$(SUDO) env DEBIAN_FRONTEND=noninteractive apt-get update -qq
$(SUDO) env DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
$(INIT_COMMON) $(if $(filter 0,$(INIT_DOCS)),,$(INIT_DOCPKGS)) $(foreach a,$(INIT_ARCHES),$(INIT_$(a)))
git lfs install --local
@# the LFS hook for this checkout -- none when init runs outside one (the CI image, ci/runner-image)
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then git lfs install --local; fi
$(call fetch,$(SYFT_TGZ),$(SYFT_URL),$(SYFT_SHA_$(SYFT_ARCH)))
@mkdir -p $(INIT_TOOLS)/syft-$(SYFT_VERSION)
tar -xzf $(INIT_DL)/$(SYFT_TGZ) -C $(INIT_TOOLS)/syft-$(SYFT_VERSION) syft
+14
View File
@@ -0,0 +1,14 @@
# The CI runner image (#120): gitea/runner-images' Ubuntu 24.04 with Node -- which
# actions/checkout and upload-artifact run on -- plus everything the jobs install at their start:
# what `make ARCH=amd64,aarch64,riscv64 init INIT_DOCS=0` installs (taken from the Makefile
# itself, not copied, so the two cannot drift), and Maven and a JRE for the publish steps.
#
# Built by .gitea/workflows/runner-image.yml, from a context of the Makefile, boards/ and this file.
FROM gitea/runner-images:ubuntu-24.04-v26.11.03
COPY Makefile /opt/starship-init/Makefile
COPY boards /opt/starship-init/boards
WORKDIR /opt/starship-init
RUN make --no-print-directory ARCH=amd64,aarch64,riscv64 init INIT_DOCS=0 \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y -qq maven default-jre-headless \
&& rm -rf /var/lib/apt/lists/* /opt/starship-init/build/cache/downloads
WORKDIR /