From 166f0d8bcdfad20b26c7f6394f05cb2b5342b017 Mon Sep 17 00:00:00 2001 From: Jake Ruesink Date: Wed, 29 Jul 2026 11:01:01 -0500 Subject: [PATCH 1/2] ci: make release publishing idempotent --- package.json | 2 +- scripts/release-if-needed.mjs | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 scripts/release-if-needed.mjs diff --git a/package.json b/package.json index 6a5e4573..f38ad857 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "lint": "biome check .", "lint:fix": "biome check . --write", "prerelease": "turbo run build", - "release": "changeset publish", + "release": "node scripts/release-if-needed.mjs", "build-storybook": "turbo run build-storybook" }, "devDependencies": { diff --git a/scripts/release-if-needed.mjs b/scripts/release-if-needed.mjs new file mode 100644 index 00000000..0bb41afd --- /dev/null +++ b/scripts/release-if-needed.mjs @@ -0,0 +1,28 @@ +import { execFileSync } from "node:child_process"; +import { readFileSync } from "node:fs"; + +const publishablePackages = ["packages/components/package.json"]; + +const unpublishedPackages = publishablePackages.filter((packagePath) => { + const localPackage = JSON.parse(readFileSync(packagePath, "utf8")); + + try { + const publishedVersion = JSON.parse( + execFileSync("npm", ["view", localPackage.name, "version", "--json"], { + encoding: "utf8", + stdio: ["ignore", "pipe", "pipe"], + }), + ); + + return publishedVersion !== localPackage.version; + } catch { + return true; + } +}); + +if (unpublishedPackages.length === 0) { + console.log("All publishable package versions are already on npm."); + process.exit(0); +} + +execFileSync("yarn", ["changeset", "publish"], { stdio: "inherit" }); From 8586ae93d1bbd590d1a9777e6afd23bd9a35a841 Mon Sep 17 00:00:00 2001 From: Jake Ruesink Date: Wed, 29 Jul 2026 11:03:10 -0500 Subject: [PATCH 2/2] fix: compare exact npm release versions --- scripts/release-if-needed.mjs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/scripts/release-if-needed.mjs b/scripts/release-if-needed.mjs index 0bb41afd..0deaafa8 100644 --- a/scripts/release-if-needed.mjs +++ b/scripts/release-if-needed.mjs @@ -7,14 +7,13 @@ const unpublishedPackages = publishablePackages.filter((packagePath) => { const localPackage = JSON.parse(readFileSync(packagePath, "utf8")); try { - const publishedVersion = JSON.parse( - execFileSync("npm", ["view", localPackage.name, "version", "--json"], { - encoding: "utf8", - stdio: ["ignore", "pipe", "pipe"], - }), - ); + const exactVersion = execFileSync( + "npm", + ["view", `${localPackage.name}@${localPackage.version}`, "version"], + { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }, + ).trim(); - return publishedVersion !== localPackage.version; + return exactVersion !== localPackage.version; } catch { return true; }