Files
godot-ci/docs/handoff/godot-ci-custom-image.md
T
haylanandClaude-Bot e1f3cba486 feat: auto-track newest Godot and Blender in publish workflow
Replace the fixed 4.7.1 Dockerfile/workflow pin with:
- a nightly schedule that resolves the newest stable Godot (4.0+) and
  newest stable Blender, and builds+pushes <version> plus a floating
  latest tag only when the Godot version actually changed
- a workflow_dispatch free-text version input to (re)build any specific
  Godot version on demand, always with newest-at-build-time Blender,
  overwriting that tag without touching latest
- scripts/resolve-godot-version.sh and scripts/resolve-blender-url.sh,
  with shared parsing logic in scripts/lib.sh and an offline smoke test
  in scripts/test-lib.sh
- Blender is now fetched directly from download.blender.org instead of
  apt (Ubuntu noble's apt package is stuck on 4.0.2)
- drop the push-to-main trigger; schedule + workflow_dispatch only

Scope is Godot 4.0+ only — .blend import is a Godot 4 feature, so 3.x
builds have no use for the Blender toolchain this image adds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-06 20:55:21 +02:00

7.9 KiB

Handoff spec: custom godot-ci image

Status: done, and superseded — the godot-ci repo this spec asked for exists and is built. Its versioning has since moved past what's written below: instead of one Dockerfile pinned to 4.7.1, it now auto-tracks the newest stable Godot (4.0+) and newest stable Blender on a nightly schedule, with a manual workflow_dispatch to (re)build any specific version. See that repo's README.md for the current behavior; this file is kept for the original problem statement and scope rationale, not as a source of truth on tags/versions. Decided via wayfinder map #158, ticket #162.

Problem

export-template.yml's export job runs in barichello/godot-ci:4.7.1 and, on every single run, apt-get installs a from-source Godot export-template toolchain before it can build anything. That install is pure dead time repeated on every release. A custom image extending barichello/godot-ci:4.7.1 with the toolchain pre-installed removes it.

What this spec is for

A fresh Gitea agent session, given only this file, must be able to:

  1. Create a new repo.
  2. Add a Dockerfile and a publish workflow to it.
  3. Get the image published to that repo's Gitea package (container) registry.
  4. Report back the final image reference so export-template.yml here can be pointed at it.

No other context from this repo should be required.

Scope: what goes in the image

Everything export-template.yml's "Update and install dependencies" step currently apt-get installs, unconditionally (all of it — see Decisions below for why the narrower alternative was rejected):

libfontconfig1
build-essential scons pkg-config xz-utils curl
# Linux leg:
libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev \
  libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libwayland-dev
# Windows leg:
mingw-w64
# + these two update-alternatives calls, baked in at image build time:
update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix
update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix
# conditionally, when ENABLE_BLENDER is on:
blender

Current source of truth for this list: .gitea/workflows/export-template.yml in haylan/Project4x, "Update and install dependencies" step. Re-check that step before building — it may have drifted since this spec was written.

What stays out of the image

  • The SCons object cache (.scons_cache, restored via actions/cache@v3 keyed on scons-${GODOT_VERSION}-${artifact_name}). This is build state, not a package — baking it into the image would pin it to image-build time instead of the actual release run, going stale immediately.
  • nsis / osslsigncode. These do NOT belong in this image. They run in release.yml's create-release job, which is a plain ubuntu-latest runner — it does not use barichello/godot-ci or any container at all. (Earlier drafts of this ticket assumed they were part of the export container's toolchain; that was wrong. The NSIS installer has since been removed entirely — see ADR 0001's superseded note — so only osslsigncode/zip remain in create-release, and neither is expensive enough to justify its own image.)

Registry path and versioning

  • Registry: this Gitea instance's container/package registry (git.arthurerlich.de), scoped to the new repo you create — Gitea packages are per-repo/owner, so the path is git.arthurerlich.de/haylan/<new-repo-name>.
  • Tag: pin to the Godot version only, e.g. git.arthurerlich.de/haylan/<new-repo-name>:4.7.1. This mirrors barichello/godot-ci's own tag scheme and Project4x's GODOT_VERSION env var. A Godot version bump in Project4x means building and pushing a new tag here too — that coupling is intentional, not an oversight.
  • Pick <new-repo-name> yourself (e.g. godot-ci-toolchain or similar); it isn't fixed by this spec.

Auth: PAT required

Confirmed for this Gitea instance: GITEA_TOKEN (the automatic per-run Actions token) cannot push to the package/container registry. The new repo's publish workflow needs a Personal Access Token stored as a repo secret (e.g. REGISTRY_PUSH_PAT).

  • Scope needed: write:package (add read:package too if the publish workflow ever needs to pull the image back, e.g. to test it before tagging latest).
  • Generate it from the account that should own the published packages, under Settings → Applications → Generate New Token, with only that scope checked.
  • Document the token's owner/scope in the new repo's README once created — this repo (Project4x) has no record of it and shouldn't need one; the coupling is one-way (Project4x only ever pulls the finished image, never pushes to it).

Dockerfile skeleton

FROM barichello/godot-ci:4.7.1

RUN apt-get update && apt-get install -y --no-install-recommends \
    libfontconfig1 \
    build-essential scons pkg-config xz-utils curl \
    libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev \
    libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libwayland-dev \
    mingw-w64 \
    blender \
  && update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix \
  && update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix \
  && rm -rf /var/lib/apt/lists/*

Notes for whoever builds this:

  • blender is baked in unconditionally here even though Project4x's ENABLE_BLENDER flag is currently "false" — the image can't cheaply branch on a flag it doesn't know about at build time, and the package is small next to the rest of this list. If that turns out to add meaningful image size/pull time for a project that never flips the flag on, split into a second -blender tagged variant instead.
  • Combine into one RUN (as above) so it's a single image layer — no benefit to splitting these across layers here.

Publish workflow skeleton

New repo, .gitea/workflows/publish.yml:

name: Publish godot-ci image

on:
  push:
    branches: [main]
    paths: [Dockerfile]
  workflow_dispatch:

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Log in to Gitea registry
        run: echo "${{ secrets.REGISTRY_PUSH_PAT }}" | docker login git.arthurerlich.de -u <owner-username> --password-stdin

      - name: Build and push
        run: |
          docker build -t git.arthurerlich.de/haylan/<new-repo-name>:4.7.1 .
          docker push git.arthurerlich.de/haylan/<new-repo-name>:4.7.1

Fill in <owner-username> and <new-repo-name> once the repo exists.

How Project4x would then reference the new image

One-line change in .gitea/workflows/export-template.yml:

- container: barichello/godot-ci:4.7.1
+ container: git.arthurerlich.de/haylan/<new-repo-name>:4.7.1

The "Update and install dependencies" step's apt-get install calls for the baked-in packages become redundant at that point (harmless no-ops — apt-get install on an already-installed package is a fast no-op, so removing them is a cleanup, not a correctness requirement) and can be trimmed in a follow-up ticket once the image is live and proven.

Decisions

  • Bake-in scope: everything in the current apt-get list, not a narrower "slow packages only" subset — keeps the image and export-template.yml's toolchain description in exact sync, so there's only one place (this spec + the Dockerfile) to update when the list changes, instead of maintaining a second smaller list that drifts from the first.
  • Tag scheme: pinned to GODOT_VERSION rather than tracking image/toolchain revisions independently — simpler to reason about, and this repo's own SCons cache is already keyed the same way, so a Godot bump already forces everything else to rebuild in lockstep.