Producer half of the Woodpecker CI cache work (Phase 1a)
This is the producer of a two-PR split. It adds only the image recipe:
Dockerfile.ci (new)
.woodpecker/ci-image.yml (new)
Why split (bootstrap problem)
ci.yml/publish.yml are being switched to pull git.mosaicstack.dev/mosaicstack/stack/ci-base:latest. But ci-image.yml can only build+push that image on a main push/manual event (kaniko from_secret is blocked on PR events). A single combined PR could never go green — its own CI would try to pull an image that does not exist yet. So we land the producer first, prime the image on main, then land the consumer.
Nothing in this PR references the ci-base image. Its own pipeline still runs on node:22-alpine, so this PR's CI is green on its own.
After merge
Prime ci-base:latest via a manual ci-image pipeline trigger on main (orchestrator does this).
Then land the consumer PR (#635), which flips ci.yml/publish.yml to the baked image.
Review fixes applied to Dockerfile.ci
N2: bake bash into the apk add toolchain — the sanitization step in ci.yml otherwise does a per-run apk add bash.
N1 (comment accuracy): the prior comment claimed native modules are "compiled ONCE at build time." That is false for pnpm fetch — fetch only populates the tarball store; native node-gyp builds still happen at pnpm install. Comments reworded: store/tarballs are fetched at build time, native compile still runs at install (which is why the toolchain stays baked). Commands unchanged.
## Producer half of the Woodpecker CI cache work (Phase 1a)
This is the **producer** of a two-PR split. It adds **only** the image recipe:
- `Dockerfile.ci` (new)
- `.woodpecker/ci-image.yml` (new)
### Why split (bootstrap problem)
`ci.yml`/`publish.yml` are being switched to pull `git.mosaicstack.dev/mosaicstack/stack/ci-base:latest`. But `ci-image.yml` can only build+push that image on a **main push/manual** event (kaniko `from_secret` is blocked on PR events). A single combined PR could never go green — its own CI would try to pull an image that does not exist yet. So we land the producer first, prime the image on main, then land the consumer.
**Nothing in this PR references the `ci-base` image.** Its own pipeline still runs on `node:22-alpine`, so this PR's CI is green on its own.
### After merge
1. Prime `ci-base:latest` via a **manual `ci-image` pipeline trigger on main** (orchestrator does this).
2. Then land the consumer PR (#635), which flips `ci.yml`/`publish.yml` to the baked image.
### Review fixes applied to `Dockerfile.ci`
- **N2:** bake `bash` into the `apk add` toolchain — the `sanitization` step in `ci.yml` otherwise does a per-run `apk add bash`.
- **N1 (comment accuracy):** the prior comment claimed native modules are "compiled ONCE at build time." That is false for `pnpm fetch` — `fetch` only populates the tarball store; native `node-gyp` builds still happen at `pnpm install`. Comments reworded: store/tarballs are fetched at build time, native compile still runs at install (which is why the toolchain stays baked). Commands unchanged.
Refs #634. Board report: `jarvis-brain/docs/reports/woodpecker-ci-cache-board-2026-06-22.md`.
No self-merge — needs review.
Producer half of the Woodpecker CI cache work (#634). Adds Dockerfile.ci
and .woodpecker/ci-image.yml only — nothing in this PR references the
ci-base image yet, so its own CI runs on the existing node:22-alpine and
stays green.
Review fixes applied:
- N2: bake `bash` into the apk toolchain (ci.yml's sanitization step
otherwise does a per-run `apk add bash`).
- N1: correct the Dockerfile comments — `pnpm fetch` only populates the
tarball store; native node-gyp modules still compile at `pnpm install`,
which is why the musl toolchain stays baked.
After merge, ci-base:latest is primed via a manual `ci-image` pipeline
trigger on main; the consumer PR (#635) then switches ci.yml/publish.yml
to pull it.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Producer half of the Woodpecker CI cache work (Phase 1a)
This is the producer of a two-PR split. It adds only the image recipe:
Dockerfile.ci(new).woodpecker/ci-image.yml(new)Why split (bootstrap problem)
ci.yml/publish.ymlare being switched to pullgit.mosaicstack.dev/mosaicstack/stack/ci-base:latest. Butci-image.ymlcan only build+push that image on a main push/manual event (kanikofrom_secretis blocked on PR events). A single combined PR could never go green — its own CI would try to pull an image that does not exist yet. So we land the producer first, prime the image on main, then land the consumer.Nothing in this PR references the
ci-baseimage. Its own pipeline still runs onnode:22-alpine, so this PR's CI is green on its own.After merge
ci-base:latestvia a manualci-imagepipeline trigger on main (orchestrator does this).ci.yml/publish.ymlto the baked image.Review fixes applied to
Dockerfile.cibashinto theapk addtoolchain — thesanitizationstep inci.ymlotherwise does a per-runapk add bash.pnpm fetch—fetchonly populates the tarball store; nativenode-gypbuilds still happen atpnpm install. Comments reworded: store/tarballs are fetched at build time, native compile still runs at install (which is why the toolchain stays baked). Commands unchanged.Refs #634. Board report:
jarvis-brain/docs/reports/woodpecker-ci-cache-board-2026-06-22.md.No self-merge — needs review.