From 668d58b5bd9d7e009b426c0c0617b5da79ab0c39 Mon Sep 17 00:00:00 2001 From: prode Date: Sun, 31 May 2026 17:39:44 -0300 Subject: [PATCH] fix(release): fail clearly instead of cryptic errors in the npm build/publish path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The local release tooling surfaced confusing failures when inputs were missing. A version mismatch (e.g. `npm-build VERSION=v0.1.2` against v0.1.1 tarballs) died with a `tar: Cannot open` error and left a half-built npm/dist, which then made `npm-publish` crash with `Cannot find module './package.json'`. - build-packages.mjs: preflight that every platform artifact for the version exists before touching npm/dist — clear "missing artifacts … build them first: make dist VERSION=…" message, and it no longer wipes or half-builds npm/dist on a mismatch. - Makefile: npm-publish / npm-dry-run now bail with guidance when npm/dist isn't assembled, and skip any directory that has no package.json. Co-Authored-By: Claude Opus 4.8 (1M context) --- Makefile | 7 ++++++- npm/scripts/build-packages.mjs | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9e10253..646545d 100644 --- a/Makefile +++ b/Makefile @@ -89,14 +89,19 @@ npm-build: require-version ## Assemble npm/dist/ (CLI + mcp-server) from artifac .PHONY: npm-dry-run npm-dry-run: ## Dry-run publish every assembled package - @set -euo pipefail; for d in npm/dist/csdd-*/ npm/dist/csdd/; do \ + @set -euo pipefail; \ + if [ ! -f npm/dist/csdd/package.json ]; then echo "npm/dist not assembled — run: make npm-build VERSION=vX.Y.Z first" >&2; exit 1; fi; \ + for d in npm/dist/csdd-*/ npm/dist/csdd/; do \ + [ -f "$$d/package.json" ] || continue; \ echo "== $$d"; npm publish "$$d" --access public --dry-run; done .PHONY: npm-publish npm-publish: ## Publish the assembled packages (CLI + mcp-server), skips already-published; OTP=123456 if 2FA @set -euo pipefail; \ + if [ ! -f npm/dist/csdd/package.json ]; then echo "npm/dist not assembled — run: make dist VERSION=vX.Y.Z && make mcp-dist && make npm-build VERSION=vX.Y.Z" >&2; exit 1; fi; \ otp=; if [ -n "$(OTP)" ]; then otp="--otp=$(OTP)"; fi; \ for d in npm/dist/csdd-*/ npm/dist/csdd/; do \ + [ -f "$$d/package.json" ] || continue; \ name=$$(cd "$$d" && node -p "require('./package.json').name"); \ ver=$$(cd "$$d" && node -p "require('./package.json').version"); \ if npm view "$$name@$$ver" version >/dev/null 2>&1; then \ diff --git a/npm/scripts/build-packages.mjs b/npm/scripts/build-packages.mjs index 217f410..34756e9 100644 --- a/npm/scripts/build-packages.mjs +++ b/npm/scripts/build-packages.mjs @@ -53,6 +53,23 @@ const version = tag.replace(/^v/, ""); const artifactsDir = resolve(process.argv[3] ?? join(repoRoot, "artifacts")); const outDir = join(npmDir, "dist"); +// Preflight: every platform artifact must exist before we touch npm/dist, so a +// version mismatch (e.g. `npm-build VERSION=v0.1.2` against v0.1.1 tarballs) +// fails with a clear message instead of a cryptic tar/unzip error — and never +// wipes a good npm/dist or leaves a half-built one that breaks `npm-publish`. +const missingArtifacts = TARGETS.map((t) => { + const ext = t.goos === "windows" ? "zip" : "tar.gz"; + return join(artifactsDir, `csdd_${tag}_${t.goos}_${t.goarch}.${ext}`); +}).filter((f) => !existsSync(f)); +if (missingArtifacts.length > 0) { + console.error( + `error: missing release artifacts for ${tag} in ${artifactsDir}:\n` + + missingArtifacts.map((f) => " " + f).join("\n") + + `\nbuild them first: make dist VERSION=${tag}` + ); + process.exit(1); +} + rmSync(outDir, { recursive: true, force: true }); mkdirSync(outDir, { recursive: true });