Skip to content

Commit 4f2e22c

Browse files
committed
fix(publish): properly capture stderr to detect already-published errors
- Add stderr capture option to run() function - Check stderr output for npm already-published errors - Stream stderr to console while also capturing it - Gracefully skip packages that npm rejects as already published
1 parent 0d32425 commit 4f2e22c

File tree

1 file changed

+22
-7
lines changed

1 file changed

+22
-7
lines changed

scripts/publish.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,30 @@ await Bun.write(npmrcPath, `//registry.npmjs.org/:_authToken=${npmToken}\n`);
3535
chmodSync(npmrcPath, 0o600);
3636

3737
const log = (msg: string) => console.log(`[publish] ${msg}`);
38-
const run = async (cmd: string, cwd = repoRoot) => {
38+
const run = async (cmd: string, cwd = repoRoot, captureStderr = false) => {
3939
log(cmd);
4040
// Invoke via bash -lc to support full command strings while still streaming output.
4141
const proc = Bun.spawn(['bash', '-lc', cmd], {
4242
cwd,
43-
stdout: 'inherit', // Stream stdout directly to console
44-
stderr: 'inherit', // Stream stderr directly to console
43+
stdout: 'inherit',
44+
stderr: captureStderr ? 'pipe' : 'inherit',
4545
});
4646

47+
let stderrOutput = '';
48+
if (captureStderr && proc.stderr) {
49+
const decoder = new TextDecoder();
50+
for await (const chunk of proc.stderr) {
51+
const text = decoder.decode(chunk);
52+
process.stderr.write(text); // Still show it to user
53+
stderrOutput += text;
54+
}
55+
}
56+
4757
const exitCode = await proc.exited;
4858
if (exitCode !== 0) {
49-
throw new Error(`Command failed with exit code ${exitCode}: ${cmd}`);
59+
const error: any = new Error(`Command failed with exit code ${exitCode}: ${cmd}`);
60+
error.stderr = stderrOutput;
61+
throw error;
5062
}
5163
};
5264

@@ -127,14 +139,17 @@ const publishPackage = async (dir: string, displayName: string): Promise<'publis
127139
log(`📦 Publishing ${displayName}@${pkgVersion}...`);
128140

129141
try {
130-
await run(publishCmd, dir);
142+
await run(publishCmd, dir, true); // Capture stderr
131143
log(`✅ ${dryRun ? 'Dry-run' : 'Published'} ${displayName}@${pkgVersion}`);
132144
return 'published';
133-
} catch (error) {
145+
} catch (error: any) {
134146
// Check if it's an "already published" error
135147
const errorStr = String(error);
148+
const stderr = error.stderr || '';
149+
136150
if (errorStr.includes('Cannot publish over previously published version') ||
137-
errorStr.includes('You cannot publish over the previously published versions')) {
151+
stderr.includes('Cannot publish over previously published version') ||
152+
stderr.includes('You cannot publish over the previously published versions')) {
138153
log(`⏭️ Skipping ${displayName}@${pkgVersion} (already published - detected during publish attempt)`);
139154
return 'skipped';
140155
}

0 commit comments

Comments
 (0)