diff --git a/.gitea/workflows/publish.yml b/.gitea/workflows/publish.yml index 43c4624..15cbb22 100644 --- a/.gitea/workflows/publish.yml +++ b/.gitea/workflows/publish.yml @@ -9,9 +9,9 @@ on: inputs: godot_version: description: >- - Godot version to (re)build, e.g. 4.7.1 — must exist as a - barichello/godot-ci tag (https://hub.docker.com/r/barichello/godot-ci/tags). - Leave empty to build the newest stable, same as the nightly run. + Godot version to (re)build, e.g. 4.7.1 — must exist as a stable release at + https://github.com/godotengine/godot-builds/releases. Leave empty to build + the newest stable, same as the nightly run. required: false type: string @@ -40,12 +40,16 @@ jobs: UPDATE_LATEST=true fi - if ! docker manifest inspect "barichello/godot-ci:${VERSION}" >/dev/null 2>&1; then + # This image no longer depends on barichello/godot-ci as a base — it downloads Godot + # directly from godot-builds' own GitHub releases (see Dockerfile), so the gate here + # is against *that* release existing, not a third party's Docker tag. + RELEASE_URL="https://github.com/godotengine/godot-builds/releases/download/${VERSION}-stable/Godot_v${VERSION}-stable_linux.x86_64.zip" + if ! curl -fsSL -o /dev/null -r 0-0 "$RELEASE_URL"; then if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "::error::No barichello/godot-ci tag for '${VERSION}'. Check https://hub.docker.com/r/barichello/godot-ci/tags" + echo "::error::No godot-builds stable release for '${VERSION}'. Check https://github.com/godotengine/godot-builds/releases" exit 1 fi - echo "::notice::Newest Godot stable is ${VERSION} but barichello/godot-ci has no matching tag yet — skipping, will retry tomorrow." + echo "::notice::Newest Godot stable is ${VERSION} but its godot-builds release isn't up yet — skipping, will retry tomorrow." echo "skip=true" >> "$GITHUB_OUTPUT" exit 0 fi diff --git a/Dockerfile b/Dockerfile index b649d10..782a9c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,25 @@ -# GODOT_VERSION selects the barichello/godot-ci base tag (Godot 4.0+ only — see -# docs/handoff/godot-ci-custom-image.md). BLENDER_URL is the tarball to bake in; +# GODOT_VERSION is a stable Godot release tag (e.g. "4.7.1", no "-stable" suffix — Godot 4.0+ +# only, see docs/handoff/godot-ci-custom-image.md). BLENDER_URL is the tarball to bake in. # .gitea/workflows/publish.yml always resolves both at build time via -# scripts/resolve-godot-version.sh and scripts/resolve-blender-url.sh. The -# defaults below are only a fallback for a plain local `docker build`. +# scripts/resolve-godot-version.sh and scripts/resolve-blender-url.sh. The defaults below are +# only a fallback for a plain local `docker build`. +# +# Godot itself is downloaded straight from its official GitHub releases (godot-builds), the same +# source barichello/godot-ci's own Dockerfile uses — this image no longer depends on that image +# as a base. Decided via wayfinder map https://git.arthurerlich.de/haylan/godot-ci/issues/2, +# ticket https://git.arthurerlich.de/haylan/godot-ci/issues/7: Alpine was considered and rejected +# (official Godot/Blender binaries are glibc-only, and Alpine's musl-native alternatives live +# only on its unpinned `edge` repo); a plain glibc-slim base doesn't cost the compatibility risk. ARG GODOT_VERSION=4.7.1 -FROM barichello/godot-ci:${GODOT_VERSION} +FROM debian:bookworm-slim +ARG GODOT_VERSION ARG BLENDER_URL=https://download.blender.org/release/Blender4.2/blender-4.2.3-linux-x64.tar.xz RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates curl unzip xz-utils \ libfontconfig1 \ - build-essential scons pkg-config xz-utils curl \ + build-essential scons pkg-config \ libx11-dev libxcursor-dev libxinerama-dev libgl1-mesa-dev \ libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev libwayland-dev \ mingw-w64 \ @@ -21,9 +30,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ && 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/* \ - # Blender is not bundled in barichello/godot-ci, and Ubuntu's apt package lags - # (stuck on 4.0.2 on noble) — install the resolved tarball straight from - # download.blender.org instead of `apt-get install blender`. + # Godot editor + export templates, straight from the official release (same URL shape + # barichello/godot-ci's own Dockerfile uses) — stable releases only, matching what + # scripts/resolve-godot-version.sh resolves. + && curl -fsSLO "https://github.com/godotengine/godot-builds/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \ + && curl -fsSLO "https://github.com/godotengine/godot-builds/releases/download/${GODOT_VERSION}-stable/Godot_v${GODOT_VERSION}-stable_export_templates.tpz" \ + && mkdir -p "/root/.local/share/godot/export_templates/${GODOT_VERSION}.stable" \ + && unzip -q "Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" \ + && mv "Godot_v${GODOT_VERSION}-stable_linux.x86_64" /usr/local/bin/godot \ + && unzip -q "Godot_v${GODOT_VERSION}-stable_export_templates.tpz" \ + && mv templates/* "/root/.local/share/godot/export_templates/${GODOT_VERSION}.stable/" \ + && rm -rf "Godot_v${GODOT_VERSION}-stable_linux.x86_64.zip" "Godot_v${GODOT_VERSION}-stable_export_templates.tpz" templates \ + # Blender is not bundled anywhere here — install the resolved tarball straight from + # download.blender.org instead of an apt package. && curl -fsSL "$BLENDER_URL" -o /tmp/blender.tar.xz \ && mkdir -p /opt/blender \ && tar -xJf /tmp/blender.tar.xz -C /opt/blender --strip-components=1 \ diff --git a/README.md b/README.md index 943f6a1..3555d86 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,17 @@ # godot-ci -Custom image extending `barichello/godot-ci` with the Godot export-template toolchain and Blender +A `debian:bookworm-slim`-based image with Godot, its export-template toolchain, and Blender pre-installed, so `Project4x`'s `export-template.yml` doesn't `apt-get install` them on every release run. +Godot is downloaded directly from its official [godot-builds +releases](https://github.com/godotengine/godot-builds/releases) rather than from a base image — +this repo previously extended `barichello/godot-ci` (Ubuntu-based) but moved off it to shed that +dependency's weight. Alpine was considered and rejected first: official Godot and Blender +binaries are glibc-only, and Alpine's musl-native alternatives for both live only on its unpinned +`edge` repo — not a safe bet for a nightly-rebuilding image. See [wayfinder map +#2](https://git.arthurerlich.de/haylan/godot-ci/issues/2) for the full research trail. + Built from the handoff spec at `Project4x`'s `docs/handoff/godot-ci-custom-image.md`; scope and versioning have since moved on from that spec — see below. @@ -22,13 +30,13 @@ this image's Blender toolchain). - **Nightly (midnight, `schedule:`)**: resolves the newest *stable* Godot release (`scripts/resolve-godot-version.sh`) and the newest stable Blender (`scripts/resolve-blender-url.sh`), and rebuilds+pushes `` + `latest` only if that - Godot version isn't already published. If `barichello/godot-ci` hasn't tagged the new Godot - version yet, the run skips (with a notice, not a failure) and retries the next night. + Godot version isn't already published. If godot-builds hasn't published that release's assets + yet, the run skips (with a notice, not a failure) and retries the next night. - **Manual (`workflow_dispatch`)**: type a Godot version (e.g. `4.6.3`) to (re)build and push that exact tag, always with whatever Blender is newest at build time. Overwrites the tag if it - already exists. Does **not** touch `latest`. Fails clearly if `barichello/godot-ci` has no - matching tag — check - [its tag list](https://hub.docker.com/r/barichello/godot-ci/tags) first. + already exists. Does **not** touch `latest`. Fails clearly if godot-builds has no matching + release — check its [releases list](https://github.com/godotengine/godot-builds/releases) + first. Blender has no official "latest stable" API — `resolve-blender-url.sh` scrapes `download.blender.org/release/`. `scripts/test-lib.sh` is an offline smoke test for the parsing diff --git a/docs/handoff/godot-ci-custom-image.md b/docs/handoff/godot-ci-custom-image.md deleted file mode 100644 index 34d06bb..0000000 --- a/docs/handoff/godot-ci-custom-image.md +++ /dev/null @@ -1,173 +0,0 @@ -# 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](https://git.arthurerlich.de/haylan/Project4x/issues/158), ticket -[#162](https://git.arthurerlich.de/haylan/Project4x/issues/162). - -## Problem - -`export-template.yml`'s `export` job runs in `barichello/godot-ci:4.7.1` and, on every single run, -`apt-get install`s 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 install`s, unconditionally (all of it — see [Decisions](#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/`. -- **Tag:** pin to the Godot version only, e.g. `git.arthurerlich.de/haylan/: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 `` 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 - -```dockerfile -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`: - -```yaml -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 --password-stdin - - - name: Build and push - run: | - docker build -t git.arthurerlich.de/haylan/:4.7.1 . - docker push git.arthurerlich.de/haylan/:4.7.1 -``` - -Fill in `` and `` once the repo exists. - -## How `Project4x` would then reference the new image - -One-line change in `.gitea/workflows/export-template.yml`: - -```diff -- container: barichello/godot-ci:4.7.1 -+ container: git.arthurerlich.de/haylan/: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.