fix(ci): restore workspace manifests after publish pin transform (#1404)
ci/woodpecker/pr/ci Pipeline was successful

PR #1400's transform rewrites package.json files in the shared pipeline
workspace (pnpm publish reads the workspace manifests, so in-place is
required) but did not restore them. build-gateway's kaniko build then
COPYs the mutated manifests and its pnpm install --frozen-lockfile
refuses: pnpm-lock.yaml still records workspace:^ while the manifest
says 0.0.x-next.NNNN — ERR_PNPM_OUTDATED_LOCKFILE, next tip red
(pipeline 2646).

Fix (restore, chosen over tarball-scoped pack because pnpm publish
must read the workspace tree anyway — a temp-copy pack would need to
reconstruct the workspace linkage per package; restore is one cp per
manifest and byte-exact): snapshot every publishable manifest to a
step-local mktemp dir BEFORE the transform; after publish + the #1389
guard, restore byte-exact (cp -p preserves mtime), then a pristine
guard runs git diff --exit-code over '**/package.json' and fails THIS
step if any residual mutation remains — the #1404 class now fails in
publish-next-npm with a named cause instead of surfacing as a frozen-
lockfile error in build-gateway.

Red-first control (scratch clone of next, real scripts extracted from
the committed YAML): transform without restore -> git diff dirty
(guard red) AND pnpm install --frozen-lockfile reproduces
ERR_PNPM_OUTDATED_LOCKFILE verbatim (the 2646 failure class); with
snapshot+restore -> git diff clean, frozen install rc=0. Also fixed a
trailing space after the NODE heredoc opener introduced with #1400's
edit that would have broken the heredoc invocation in real CI.
This commit is contained in:
2026-08-24 18:38:52 -05:00
parent 4d24ae8618
commit 1a28212a89
+37
View File
@@ -202,6 +202,20 @@ steps:
echo "@mosaicstack:registry=https://git.mosaicstack.dev/api/packages/mosaicstack/npm/" >> ~/.npmrc echo "@mosaicstack:registry=https://git.mosaicstack.dev/api/packages/mosaicstack/npm/" >> ~/.npmrc
DIST_TAGS_JSON="$(npm view @mosaicstack/mosaic dist-tags --registry https://git.mosaicstack.dev/api/packages/mosaicstack/npm/ --json)" DIST_TAGS_JSON="$(npm view @mosaicstack/mosaic dist-tags --registry https://git.mosaicstack.dev/api/packages/mosaicstack/npm/ --json)"
DIST_TAGS_JSON="$DIST_TAGS_JSON" node -e 'const tags = JSON.parse(process.env.DIST_TAGS_JSON || "{}"); if (!tags || typeof tags !== "object" || !Object.hasOwn(tags, "latest")) { throw new Error("Gitea npm registry did not return a usable dist-tags object"); } console.log("[publish-next] registry dist-tags OK: latest=" + tags.latest);' DIST_TAGS_JSON="$DIST_TAGS_JSON" node -e 'const tags = JSON.parse(process.env.DIST_TAGS_JSON || "{}"); if (!tags || typeof tags !== "object" || !Object.hasOwn(tags, "latest")) { throw new Error("Gitea npm registry did not return a usable dist-tags object"); } console.log("[publish-next] registry dist-tags OK: latest=" + tags.latest);'
# #1404: snapshot every publishable manifest BEFORE the transform so the
# workspace can be restored byte-exact after publish. The transform
# rewrites package.json in place (needed: pnpm publish reads the
# workspace manifests); without restore, later steps in this pipeline
# (build-gateway kaniko COPY + pnpm install --frozen-lockfile) see
# manifests that no longer match pnpm-lock.yaml and fail
# ERR_PNPM_OUTDATED_LOCKFILE. Snapshot dir is step-local tmp.
SNAPSHOT_DIR="$(mktemp -d /tmp/publish-next-manifests.XXXXXX)"
export SNAPSHOT_DIR
find apps packages plugins -name package.json -not -path "*/node_modules/*" -not -path "*/dist/*" | while read -r mf; do
mkdir -p "$SNAPSHOT_DIR/$(dirname "$mf")"
cp -p "$mf" "$SNAPSHOT_DIR/$mf"
done
echo "[publish-next] snapshotted $(find "$SNAPSHOT_DIR" -name package.json | wc -l) manifests to $SNAPSHOT_DIR"
node <<'NODE' node <<'NODE'
const fs = require('node:fs'); const fs = require('node:fs');
const path = require('node:path'); const path = require('node:path');
@@ -357,6 +371,29 @@ steps:
} }
console.log('[publish-next-guard] OK: all ' + published.length + ' published manifests carry exact same-pipeline @mosaicstack/* dep pins'); console.log('[publish-next-guard] OK: all ' + published.length + ' published manifests carry exact same-pipeline @mosaicstack/* dep pins');
GUARD GUARD
# #1404 restore: put the workspace manifests back byte-exact so later
# steps (build-gateway frozen-lockfile install) see the committed tree.
RESTORE_FAIL=0
while read -r mf; do
if [ -f "$SNAPSHOT_DIR/$mf" ]; then
cp -p "$SNAPSHOT_DIR/$mf" "$mf"
else
echo "[publish-next] FATAL: no snapshot for $mf — cannot restore (snapshot incomplete?)" >&2
RESTORE_FAIL=1
fi
done < <(find apps packages plugins -name package.json -not -path "*/node_modules/*" -not -path "*/dist/*")
# Pristine guard (#1404 red-first control): the publish step must leave
# the workspace byte-identical to the checkout for every manifest.
# git diff is the arbiter — any residual mutation fails THIS step
# instead of surfacing as ERR_PNPM_OUTDATED_LOCKFILE in build-gateway.
if ! git diff --exit-code -- '**/package.json' >/dev/null 2>&1; then
echo "[publish-next] FATAL: workspace package.json files still differ from HEAD after restore (#1404 class)" >&2
git diff --stat -- '**/package.json' >&2 || true
RESTORE_FAIL=1
fi
rm -rf "$SNAPSHOT_DIR"
if [ "$RESTORE_FAIL" -ne 0 ]; then exit 1; fi
echo "[publish-next] workspace manifests restored byte-exact (git diff clean); later steps see the committed tree"
depends_on: depends_on:
- build - build
- verify - verify