Skip to content

Commit abb87bf

Browse files
jpr5claude
andcommitted
fix: harden release system — registry error handling, tag check, prerelease tests
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 9686a71 commit abb87bf

3 files changed

Lines changed: 37 additions & 3 deletions

File tree

.github/workflows/publish-release.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,20 @@ jobs:
7474
git config --global user.email "github-actions[bot]@users.noreply.github.com"
7575
git config --global user.name "github-actions[bot]"
7676
77+
- name: Check for pre-existing tags
78+
run: |
79+
SCOPE="${{ steps.meta.outputs.scope }}"
80+
VERSION="${{ steps.publish.outputs.version }}"
81+
if [ "$SCOPE" == "monorepo" ]; then
82+
TAG="v${VERSION}"
83+
else
84+
TAG="${SCOPE}/v${VERSION}"
85+
fi
86+
if git rev-parse "$TAG" >/dev/null 2>&1; then
87+
echo "ERROR: Tag $TAG already exists" >&2
88+
exit 1
89+
fi
90+
7791
- name: Create and push git tag
7892
run: |
7993
SCOPE="${{ steps.meta.outputs.scope }}"

scripts/release/prerelease.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ function main() {
7676
console.log("\nBuilding packages...");
7777
run("pnpm", ["run", "build"]);
7878

79+
// Run tests before publishing
80+
console.log("\nRunning tests...");
81+
run("pnpm", ["run", "test"]);
82+
7983
// Publish each package
8084
console.log("\nPublishing packages...");
8185
for (const p of getPackagesForScope(scope)) {

scripts/release/publish-release.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,17 @@ function getPublishedVersion(packageName: string): string | null {
4343
encoding: "utf8",
4444
timeout: 15000,
4545
});
46-
if (result.status !== 0) return null;
47-
return result.stdout.trim() || null;
46+
if (result.status === 0) {
47+
return result.stdout.trim() || null;
48+
}
49+
// E404 means package doesn't exist on registry — genuinely not published
50+
if (result.stderr?.includes("E404") || result.stderr?.includes("is not in this registry")) {
51+
return null;
52+
}
53+
// Any other error (network, auth, rate limit) should stop the release
54+
throw new Error(
55+
`npm registry check failed for ${packageName}: ${result.stderr?.trim() || "unknown error"}`
56+
);
4857
}
4958

5059
function isGreaterVersion(next: string, current: string): boolean {
@@ -87,7 +96,14 @@ async function main() {
8796
}
8897

8998
// Safety check: refuse to publish if version isn't greater than what's on npm
90-
const published = getPublishedVersion(scopeConfig.versionSource);
99+
let published: string | null;
100+
try {
101+
published = getPublishedVersion(scopeConfig.versionSource);
102+
} catch (err: any) {
103+
console.error(`Registry check failed — aborting release to avoid publishing over an existing version.`);
104+
console.error(err.message);
105+
process.exit(1);
106+
}
91107
if (published) {
92108
console.log(`Currently published version: ${published}`);
93109
if (!isGreaterVersion(version, published)) {

0 commit comments

Comments
 (0)