From 322e24fc02e6c4ac4aa7955c83fa7962d8fdd868 Mon Sep 17 00:00:00 2001 From: Andrey Avtomonov Date: Wed, 20 May 2026 00:55:15 +0200 Subject: [PATCH] fix(ci): publish the pre-built tarball instead of re-packing (#159) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(ci): publish the pre-built tarball instead of re-packing The release workflow built the tarball twice — once via pnpm pack in artifacts:check (leaving it at dist/artifacts/npm/) and again inside @semantic-release/npm's prepare step, which then tried to fs-extra move npm pack's output into the same directory and crashed with "dest already exists". On top of being a publish blocker, that meant the published tarball was different from the one smoke-tested in artifacts:check. Drop @semantic-release/npm and publish the exact tarball that artifacts:check verified via an exec publishCmd: npm publish dist/artifacts/npm/kaelio-ktx-.tgz \ --tag --access public --provenance Auth uses OIDC trusted publishing — the workflow already grants id-token: write and setup-node configures the registry, and release-workflow.test.mjs asserts NODE_AUTH_TOKEN is not set. * fix(ci): allow @kaelio/ktx tarball name in semantic-release config The new publishCmd added in the previous commit hardcodes the dist/artifacts/npm/kaelio-ktx-.tgz path, which trips the boundary check that forbids the literal product name outside release-machinery files. The release config is exactly such a release-machinery file — its job is to bridge the generic ktx project to the @kaelio/ktx npm package — so add it to identifierAllowPatterns alongside the existing build-public-npm-package and public-npm-release-metadata entries. --- scripts/check-boundaries.mjs | 1 + scripts/check-boundaries.test.mjs | 1 + scripts/semantic-release-config.cjs | 17 ++++------------- scripts/semantic-release-config.test.mjs | 20 ++++++++++++-------- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/scripts/check-boundaries.mjs b/scripts/check-boundaries.mjs index 3093fd42..1a2adf4f 100644 --- a/scripts/check-boundaries.mjs +++ b/scripts/check-boundaries.mjs @@ -11,6 +11,7 @@ const identifierAllowPatterns = [ /^packages\/cli\/src\/(?:index|managed-local-embeddings|managed-python-command|managed-python-daemon|managed-python-runtime|release-version|runtime)(?:\.test)?\.ts$/, /^python\/ktx-daemon\/src\/ktx_daemon\/__init__\.py$/, /^scripts\/(?:build-public-npm-package|build-python-runtime-wheel|local-embeddings-runtime-smoke|package-artifacts|public-npm-release-metadata|published-package-smoke|release-readiness)(?:\.test)?\.mjs$/, + /^scripts\/semantic-release-config\.cjs$/, ]; const forbiddenIdentifierTerms = ['kae' + 'lio', 'Kae' + 'lio', 'KAE' + 'LIO_']; diff --git a/scripts/check-boundaries.test.mjs b/scripts/check-boundaries.test.mjs index 832dc1c2..9fb8999d 100644 --- a/scripts/check-boundaries.test.mjs +++ b/scripts/check-boundaries.test.mjs @@ -79,6 +79,7 @@ describe('scanFileContent', () => { assert.equal(scanFileContent('scripts/local-embeddings-runtime-smoke.mjs', `@${name}/ktx`).length, 0); assert.equal(scanFileContent('scripts/package-artifacts.test.mjs', `${name}-ktx`).length, 0); assert.equal(scanFileContent('scripts/public-npm-release-metadata.mjs', `@${name}/ktx`).length, 0); + assert.equal(scanFileContent('scripts/semantic-release-config.cjs', `${name}-ktx-`).length, 0); assert.equal(scanFileContent('packages/cli/src/release-version.ts', `@${name}/ktx`).length, 0); assert.equal(scanFileContent('packages/cli/src/managed-python-runtime.ts', `${name}_ktx`).length, 0); assert.equal(scanFileContent('python/ktx-daemon/src/ktx_daemon/__init__.py', `${name}-ktx`).length, 0); diff --git a/scripts/semantic-release-config.cjs b/scripts/semantic-release-config.cjs index e9ec9cc5..fb1f959d 100644 --- a/scripts/semantic-release-config.cjs +++ b/scripts/semantic-release-config.cjs @@ -166,19 +166,10 @@ function createReleaseConfig(env = process.env) { 'pnpm run artifacts:check', 'pnpm run release:readiness', ].join(' && '), - }, - ], - [ - '@semantic-release/npm', - { - pkgRoot: 'dist/public-npm-package', - tarballDir: 'dist/artifacts/npm', - }, - ], - [ - '@semantic-release/exec', - { - publishCmd: 'pnpm run release:published-smoke', + publishCmd: [ + `npm publish dist/artifacts/npm/kaelio-ktx-\${nextRelease.version}.tgz --tag ${tag} --access public --provenance`, + 'pnpm run release:published-smoke', + ].join(' && '), }, ], ...releaseGitPlugins(kind), diff --git a/scripts/semantic-release-config.test.mjs b/scripts/semantic-release-config.test.mjs index 99cd53c4..c62f0fdf 100644 --- a/scripts/semantic-release-config.test.mjs +++ b/scripts/semantic-release-config.test.mjs @@ -27,20 +27,20 @@ describe('semantic-release config', () => { ]); const config = createReleaseConfig({ KTX_RELEASE_KIND: 'rc', GITHUB_REF_NAME: 'main' }); - assert.deepEqual( + assert.equal( config.plugins.find((plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/npm'), - [ - '@semantic-release/npm', - { - pkgRoot: 'dist/public-npm-package', - tarballDir: 'dist/artifacts/npm', - }, - ], + undefined, + '@semantic-release/npm must not run; the exec publishCmd publishes the pre-built tarball', ); assert.match( releaseExecOptions(config).prepareCmd, /update-public-release-version\.mjs "\$\{nextRelease\.version\}" "next"/, ); + assert.match( + releaseExecOptions(config).publishCmd, + /^npm publish dist\/artifacts\/npm\/kaelio-ktx-\$\{nextRelease\.version\}\.tgz --tag next --access public --provenance/, + ); + assert.match(releaseExecOptions(config).publishCmd, /pnpm run release:published-smoke/); assert.doesNotMatch(JSON.stringify(config.plugins), /release:npm-publish/); const releaseFilePluginNames = pluginNames(config).filter( (plugin) => plugin === '@semantic-release/changelog' || plugin === '@semantic-release/git', @@ -62,6 +62,10 @@ describe('semantic-release config', () => { releaseExecOptions(config).prepareCmd, /update-public-release-version\.mjs "\$\{nextRelease\.version\}" "latest"/, ); + assert.match( + releaseExecOptions(config).publishCmd, + /^npm publish dist\/artifacts\/npm\/kaelio-ktx-\$\{nextRelease\.version\}\.tgz --tag latest --access public --provenance/, + ); assert.equal(config.plugins.includes('./scripts/semantic-release-version-policy.cjs'), false); });