From 7d06c1c761a0747609c2c81e181af7a525ad63c3 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Mon, 22 Jun 2026 03:28:55 -0500 Subject: [PATCH] ci(publish): gate kaniko image builds + publish on changed paths (CI throughput) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every main merge runs publish.yml, which unconditionally rebuilds the three kaniko images (gateway/appservice/web, ~25 min) — and each Dockerfile's `COPY . .` busts kaniko's cache on any change. But none of those apps depend on @mosaicstack/mosaic, so the entire constitution + fleet PR stream (all packages/mosaic/** + docs/**) rebuilds all three images for nothing, saturating the runners. Gate the heavy steps with step-level `when: path`: - build-gateway/appservice/web: skip when a main push touches ONLY non-image paths (packages/mosaic/**, docs/**, **/*.md, .woodpecker/**); always build on tag. Exclude-list keeps the default SAFE — any non-excluded change still builds, so no transitive dep can silently go stale (chosen over per-image include-lists, which risked under-including an app's transitive closure). - publish-npm: run only when packages/** changed (or on tag) — a pure-docs merge now runs no publish. Woodpecker semantics (docs-confirmed): `when` entries are OR'd; `path` applies to push/PR only (hence the separate `event: tag` entry); step-level `when` governs the step independently of the file-level `when`. install/build remain ungated (deferred: scoping the build + tightening the Dockerfile COPY are follow-ups). Skip-validation lands on the next real merge (a docs-only merge should show 0 image builds); skipping is safe — prior :latest/:sha images remain. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01EsgTQzV5YUGk1JtCLP4B83 --- .woodpecker/publish.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.woodpecker/publish.yml b/.woodpecker/publish.yml index 187e600..8eb4685 100644 --- a/.woodpecker/publish.yml +++ b/.woodpecker/publish.yml @@ -4,6 +4,23 @@ variables: - &node_image 'node:22-alpine' - &enable_pnpm 'corepack enable' + # Heavy kaniko image builds (~25 min) — gate them so a merge that only touches + # the npm-only CLI (@mosaicstack/mosaic) or docs does NOT rebuild the platform + # images (gateway/appservice/web do not depend on @mosaicstack/mosaic). Releases + # (tags) always build everything. Exclude-list keeps the default SAFE: any + # non-excluded change still builds, so no transitive dep can silently go stale. + # (Woodpecker: `when` entries are OR'd; `path` applies to push/PR only — hence + # the separate `event: tag` entry.) + - &image_build_when + - event: tag + - event: [push, manual] + branch: main + path: + exclude: + - 'packages/mosaic/**' + - 'docs/**' + - '**/*.md' + - '.woodpecker/**' when: - branch: [main] @@ -26,6 +43,15 @@ steps: publish-npm: image: *node_image + # Publish only when a publishable package changed (or on a release tag); a + # pure-docs merge runs no publish. Cheap step, but gated for cleanliness. + when: + - event: tag + - event: [push, manual] + branch: main + path: + include: + - 'packages/**' environment: NPM_TOKEN: from_secret: gitea_token @@ -91,6 +117,7 @@ steps: build-gateway: image: gcr.io/kaniko-project/executor:debug + when: *image_build_when environment: REGISTRY_USER: from_secret: gitea_username @@ -116,6 +143,7 @@ steps: build-appservice: image: gcr.io/kaniko-project/executor:debug + when: *image_build_when environment: REGISTRY_USER: from_secret: gitea_username @@ -141,6 +169,7 @@ steps: build-web: image: gcr.io/kaniko-project/executor:debug + when: *image_build_when environment: REGISTRY_USER: from_secret: gitea_username