From 45374fa3abd9007bdcb17d28d832d21a74cca2ff Mon Sep 17 00:00:00 2001 From: Andrey Avtomonov Date: Sun, 17 May 2026 00:43:37 +0200 Subject: [PATCH] fix(release): make npm publish noninteractive --- scripts/publish-public-npm-package.mjs | 49 +++++++++++++++++---- scripts/publish-public-npm-package.test.mjs | 5 +-- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/scripts/publish-public-npm-package.mjs b/scripts/publish-public-npm-package.mjs index d82a157d..c8c5b6e3 100644 --- a/scripts/publish-public-npm-package.mjs +++ b/scripts/publish-public-npm-package.mjs @@ -1,14 +1,13 @@ #!/usr/bin/env node -import { execFile } from 'node:child_process'; +import { spawn } from 'node:child_process'; import { access } from 'node:fs/promises'; import { pathToFileURL } from 'node:url'; -import { promisify } from 'node:util'; import { packageArtifactLayout } from './package-artifacts.mjs'; import { releaseReadinessReport } from './release-readiness.mjs'; -const execFileAsync = promisify(execFile); +export const NPM_PUBLISH_TIMEOUT_MS = 180_000; export function resolvePublishMode(args = process.argv.slice(2)) { return { live: args.includes('--publish') }; @@ -23,7 +22,7 @@ export function requireNpmPublicReleaseReady(report) { export function buildNpmPublishCommand(tarballPath, publish, mode) { return { - command: 'pnpm', + command: 'npm', args: [ 'publish', tarballPath, @@ -31,7 +30,7 @@ export function buildNpmPublishCommand(tarballPath, publish, mode) { publish.access, '--tag', publish.tag, - ...(mode.live ? [] : ['--dry-run', '--no-git-checks']), + ...(mode.live ? [] : ['--dry-run']), ], env: publish.registry ? { npm_config_registry: publish.registry } : {}, }; @@ -47,10 +46,42 @@ async function assertFileExists(path) { async function runPublishCommand(command) { process.stdout.write(`$ ${command.command} ${command.args.join(' ')}\n`); - await execFileAsync(command.command, command.args, { - env: { ...process.env, ...command.env }, - encoding: 'utf8', - maxBuffer: 1024 * 1024 * 20, + + await new Promise((resolvePromise, reject) => { + let settled = false; + const child = spawn(command.command, command.args, { + env: { ...process.env, ...command.env }, + stdio: ['ignore', 'pipe', 'pipe'], + }); + const settle = (callback, value) => { + if (settled) { + return; + } + settled = true; + clearTimeout(timeout); + callback(value); + }; + const timeout = setTimeout(() => { + child.kill('SIGTERM'); + settle(reject, new Error(`Timed out after ${NPM_PUBLISH_TIMEOUT_MS}ms while publishing npm package`)); + }, NPM_PUBLISH_TIMEOUT_MS); + + child.stdout.on('data', (chunk) => { + process.stdout.write(chunk); + }); + child.stderr.on('data', (chunk) => { + process.stderr.write(chunk); + }); + child.on('error', (error) => { + settle(reject, error); + }); + child.on('close', (code, signal) => { + if (code === 0) { + settle(resolvePromise); + return; + } + settle(reject, new Error(`npm publish failed with ${signal ? `signal ${signal}` : `exit code ${code}`}`)); + }); }); } diff --git a/scripts/publish-public-npm-package.test.mjs b/scripts/publish-public-npm-package.test.mjs index d622ffe2..d3b5b016 100644 --- a/scripts/publish-public-npm-package.test.mjs +++ b/scripts/publish-public-npm-package.test.mjs @@ -49,13 +49,13 @@ describe('requireNpmPublicReleaseReady', () => { }); describe('buildNpmPublishCommand', () => { - it('builds a dry-run pnpm publish command by default', () => { + it('builds a dry-run npm publish command by default', () => { assert.deepEqual( buildNpmPublishCommand('/repo/ktx/dist/artifacts/npm/kaelio-ktx-0.1.0-rc.1.tgz', readyReport.npmPublish, { live: false, }), { - command: 'pnpm', + command: 'npm', args: [ 'publish', '/repo/ktx/dist/artifacts/npm/kaelio-ktx-0.1.0-rc.1.tgz', @@ -64,7 +64,6 @@ describe('buildNpmPublishCommand', () => { '--tag', 'next', '--dry-run', - '--no-git-checks', ], env: {}, },