# CI job image for the Gitea act_runner: the runner's default job image with # Node pre-planted where actions/setup-node looks first. # # Why this layout: setup-node ignores `node` on PATH; its only fast path is a # probe of /opt/hostedtoolcache/node//. Without an entry there # it downloads the ~50 MB distribution on EVERY job (the runner's job # containers are ephemeral, so its tool cache never survives a job). The # official node images keep exactly the layout setup-node expects under # /usr/local, so this layer is a pure file overlay — no scripts, no env. # # Why not a host bind of /opt/hostedtoolcache: binds never self-prune. Docker # images are content-addressed: the base layers dedupe against the act image # the host already has, and `docker image prune` / re-pulls are the cleanup # story. # # NODE_VERSION must match `.node-version` exactly. setup-node resolves a float # like `26` to the latest known patch at runtime, so a bump silently busts the # baked entry; `.node-version` is pinned to x.y.z and scripts/runner-image.sh # guards the coupling. Rebuild + repoint `container.image` in # .gitea/workflows/ci.yml on every bump. # # The extra `nodebase` stage is load-bearing: `COPY --from=` resolves its value # as a *stage name* at parse time, before build args exist, so # `COPY --from=node:${NODE_VERSION}` collapses to the invalid `node:` on # frontends that do not expand args there. ARGs declared before the first FROM # *are* expanded in FROM, so routing through a named stage works everywhere. # Global scope: only visible to FROM lines, but that is exactly where we need it. ARG NODE_VERSION=26.8.2 FROM node:${NODE_VERSION} AS nodebase FROM catthehacker/ubuntu:act-latest # ARGs do not cross stage boundaries; redeclare (with the same default, so a # bare `docker build -f docker/Dockerfile .` still works) for the paths below. # Keep this default in sync with the global one above. ARG NODE_VERSION=26.8.2 # node image: bin/ + lib/ under /usr/local → tool cache: bin/ + lib/ under /x64. COPY --from=nodebase /usr/local /opt/hostedtoolcache/node/${NODE_VERSION}/x64 # Fail the build (not CI) if the overlay or the version arg were wrong. # Shell form on purpose: exec form (`RUN [...]`) does not expand ARG values. RUN "/opt/hostedtoolcache/node/${NODE_VERSION}/x64/bin/node" --version