mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-13 08:15:14 +02:00
feat: release one public kaelio ktx npm artifact
This commit is contained in:
parent
24dbbe2a06
commit
ba47ab95e7
5 changed files with 123 additions and 163 deletions
|
|
@ -4,19 +4,7 @@
|
|||
"npm": {
|
||||
"publish": false,
|
||||
"registry": null,
|
||||
"packages": [
|
||||
"@ktx/cli",
|
||||
"@ktx/connector-bigquery",
|
||||
"@ktx/connector-clickhouse",
|
||||
"@ktx/connector-mysql",
|
||||
"@ktx/connector-postgres",
|
||||
"@ktx/connector-posthog",
|
||||
"@ktx/connector-snowflake",
|
||||
"@ktx/connector-sqlite",
|
||||
"@ktx/connector-sqlserver",
|
||||
"@ktx/context",
|
||||
"@ktx/llm"
|
||||
]
|
||||
"packages": ["@kaelio/ktx"]
|
||||
},
|
||||
"python": {
|
||||
"publish": false,
|
||||
|
|
@ -24,14 +12,12 @@
|
|||
"packages": ["ktx-sl", "ktx-daemon", "kaelio-ktx"]
|
||||
},
|
||||
"publishedPackageSmoke": {
|
||||
"packageName": null,
|
||||
"packageName": "@kaelio/ktx",
|
||||
"version": "latest",
|
||||
"registry": null
|
||||
},
|
||||
"requiredBeforePublishing": [
|
||||
"Choose npm registry and package visibility.",
|
||||
"Choose Python package repository.",
|
||||
"Choose public release versions.",
|
||||
"Choose public release version.",
|
||||
"Configure registry credentials outside source control.",
|
||||
"Choose release tag and provenance policy."
|
||||
]
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ import {
|
|||
RUNTIME_WHEEL_NORMALIZED_NAME,
|
||||
RUNTIME_WHEEL_PACKAGE_VERSION,
|
||||
} from './build-python-runtime-wheel.mjs';
|
||||
import {
|
||||
PUBLIC_NPM_PACKAGE_NAME,
|
||||
PUBLIC_NPM_PACKAGE_TARBALL,
|
||||
} from './build-public-npm-package.mjs';
|
||||
|
||||
const PACKAGE_VERSION = '0.0.0-private';
|
||||
const PYTHON_PACKAGE_VERSION = '0.1.0';
|
||||
|
|
@ -22,7 +26,7 @@ export {
|
|||
RUNTIME_WHEEL_PACKAGE_VERSION,
|
||||
};
|
||||
|
||||
export const NPM_ARTIFACT_PACKAGES = [
|
||||
export const INTERNAL_NPM_WORKSPACE_PACKAGES = [
|
||||
{ name: '@ktx/context', packageRoot: 'packages/context' },
|
||||
{ name: '@ktx/llm', packageRoot: 'packages/llm' },
|
||||
{ name: '@ktx/connector-bigquery', packageRoot: 'packages/connector-bigquery' },
|
||||
|
|
@ -36,9 +40,11 @@ export const NPM_ARTIFACT_PACKAGES = [
|
|||
{ name: '@ktx/cli', packageRoot: 'packages/cli' },
|
||||
];
|
||||
|
||||
export const NPM_ARTIFACT_PACKAGES = [{ name: PUBLIC_NPM_PACKAGE_NAME, packageRoot: 'packages/cli' }];
|
||||
|
||||
export const CLI_PYTHON_ASSET_MANIFEST = 'manifest.json';
|
||||
|
||||
const CONNECTOR_PACKAGE_NAMES = NPM_ARTIFACT_PACKAGES
|
||||
const CONNECTOR_PACKAGE_NAMES = INTERNAL_NPM_WORKSPACE_PACKAGES
|
||||
.map((packageInfo) => packageInfo.name)
|
||||
.filter((packageName) => packageName.startsWith('@ktx/connector-'));
|
||||
|
||||
|
|
@ -62,6 +68,9 @@ function scriptRootDir() {
|
|||
}
|
||||
|
||||
function npmPackageTarballName(packageName) {
|
||||
if (packageName === PUBLIC_NPM_PACKAGE_NAME) {
|
||||
return PUBLIC_NPM_PACKAGE_TARBALL;
|
||||
}
|
||||
return `${packageName.replace('@ktx/', 'ktx-')}-${PACKAGE_VERSION}.tgz`;
|
||||
}
|
||||
|
||||
|
|
@ -83,17 +92,15 @@ export function packageArtifactLayout(rootDir = scriptRootDir()) {
|
|||
npmDir,
|
||||
pythonDir,
|
||||
npmTarballs,
|
||||
contextTarball: npmTarballs['@ktx/context'],
|
||||
cliTarball: npmTarballs['@ktx/cli'],
|
||||
connectorTarballs: Object.fromEntries(
|
||||
CONNECTOR_PACKAGE_NAMES.map((packageName) => [packageName, npmTarballs[packageName]]),
|
||||
),
|
||||
contextTarball: npmTarballs[PUBLIC_NPM_PACKAGE_NAME],
|
||||
cliTarball: npmTarballs[PUBLIC_NPM_PACKAGE_NAME],
|
||||
connectorTarballs: {},
|
||||
manifestPath: join(artifactDir, 'manifest.json'),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildArtifactCommands(layout) {
|
||||
const packagesByName = new Map(NPM_ARTIFACT_PACKAGES.map((packageInfo) => [packageInfo.name, packageInfo]));
|
||||
const packagesByName = new Map(INTERNAL_NPM_WORKSPACE_PACKAGES.map((packageInfo) => [packageInfo.name, packageInfo]));
|
||||
const npmBuildCommands = NPM_ARTIFACT_BUILD_ORDER.map((packageName) => {
|
||||
const packageInfo = packagesByName.get(packageName);
|
||||
if (!packageInfo) {
|
||||
|
|
@ -105,11 +112,11 @@ export function buildArtifactCommands(layout) {
|
|||
cwd: layout.rootDir,
|
||||
};
|
||||
});
|
||||
const npmPackCommands = NPM_ARTIFACT_PACKAGES.map((packageInfo) => ({
|
||||
command: 'pnpm',
|
||||
args: ['--filter', packageInfo.name, 'pack', '--out', layout.npmTarballs[packageInfo.name]],
|
||||
const publicPackageCommand = {
|
||||
command: process.execPath,
|
||||
args: ['scripts/build-public-npm-package.mjs'],
|
||||
cwd: layout.rootDir,
|
||||
}));
|
||||
};
|
||||
|
||||
return [
|
||||
...npmBuildCommands,
|
||||
|
|
@ -128,7 +135,7 @@ export function buildArtifactCommands(layout) {
|
|||
args: ['build', '--package', 'ktx-daemon', '--out-dir', layout.pythonDir],
|
||||
cwd: layout.rootDir,
|
||||
},
|
||||
...npmPackCommands,
|
||||
publicPackageCommand,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -241,17 +248,18 @@ function releaseMetadataEntry({ ecosystem, packageName, packageRoot, packageVers
|
|||
|
||||
async function readNpmPackageMetadata(rootDir, packageInfo) {
|
||||
const packageJson = await readJson(join(rootDir, packageInfo.packageRoot, 'package.json'));
|
||||
if (packageJson.name !== packageInfo.name) {
|
||||
const expectedSourceName = packageInfo.name === PUBLIC_NPM_PACKAGE_NAME ? '@ktx/cli' : packageInfo.name;
|
||||
if (packageJson.name !== expectedSourceName) {
|
||||
throw new Error(
|
||||
`Unexpected package name in ${packageInfo.packageRoot}/package.json: expected ${packageInfo.name}, got ${packageJson.name}`,
|
||||
`Unexpected package name in ${packageInfo.packageRoot}/package.json: expected ${expectedSourceName}, got ${packageJson.name}`,
|
||||
);
|
||||
}
|
||||
return releaseMetadataEntry({
|
||||
ecosystem: 'npm',
|
||||
packageName: packageJson.name,
|
||||
packageName: packageInfo.name,
|
||||
packageRoot: packageInfo.packageRoot,
|
||||
packageVersion: packageJson.version,
|
||||
privatePackage: packageJson.private === true,
|
||||
privatePackage: packageInfo.name === PUBLIC_NPM_PACKAGE_NAME ? false : packageJson.private === true,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1623,8 +1631,8 @@ async function buildArtifacts(layout) {
|
|||
await mkdir(layout.pythonDir, { recursive: true });
|
||||
|
||||
const commands = buildArtifactCommands(layout);
|
||||
const npmBuildCount = NPM_ARTIFACT_PACKAGES.length;
|
||||
const npmPackStart = commands.length - NPM_ARTIFACT_PACKAGES.length;
|
||||
const npmBuildCount = NPM_ARTIFACT_BUILD_ORDER.length;
|
||||
const npmPackStart = commands.length - 1;
|
||||
|
||||
for (const command of commands.slice(0, npmBuildCount)) {
|
||||
await runCommand(command.command, command.args, { cwd: command.cwd });
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { describe, it } from 'node:test';
|
|||
|
||||
import {
|
||||
CLI_PYTHON_ASSET_MANIFEST,
|
||||
INTERNAL_NPM_WORKSPACE_PACKAGES,
|
||||
RUNTIME_WHEEL_DISTRIBUTION_NAME,
|
||||
RUNTIME_WHEEL_NORMALIZED_NAME,
|
||||
RUNTIME_WHEEL_PACKAGE_VERSION,
|
||||
|
|
@ -34,35 +35,17 @@ async function writeJson(path, value) {
|
|||
await writeFile(path, `${JSON.stringify(value, null, 2)}\n`);
|
||||
}
|
||||
|
||||
const CONNECTOR_PACKAGE_NAMES = [
|
||||
'@ktx/connector-bigquery',
|
||||
'@ktx/connector-clickhouse',
|
||||
'@ktx/connector-mysql',
|
||||
'@ktx/connector-postgres',
|
||||
'@ktx/connector-posthog',
|
||||
'@ktx/connector-snowflake',
|
||||
'@ktx/connector-sqlite',
|
||||
'@ktx/connector-sqlserver',
|
||||
];
|
||||
|
||||
const INTERNAL_BUILD_PACKAGE_NAMES = INTERNAL_NPM_WORKSPACE_PACKAGES.map((packageInfo) => packageInfo.name);
|
||||
const CONNECTOR_PACKAGE_NAMES = INTERNAL_BUILD_PACKAGE_NAMES.filter((packageName) =>
|
||||
packageName.startsWith('@ktx/connector-'),
|
||||
);
|
||||
const NPM_BUILD_PACKAGE_ORDER = ['@ktx/llm', '@ktx/context', ...CONNECTOR_PACKAGE_NAMES, '@ktx/cli'];
|
||||
|
||||
function packageRootForName(packageName) {
|
||||
return `packages/${packageName.replace('@ktx/', '')}`;
|
||||
}
|
||||
|
||||
function expectedNpmArtifactPath(packageName) {
|
||||
return `npm/${packageName.replace('@ktx/', 'ktx-')}-0.0.0-private.tgz`;
|
||||
}
|
||||
|
||||
async function writeReleaseMetadataInputs(root) {
|
||||
const npmPackages = ['@ktx/context', '@ktx/llm', ...CONNECTOR_PACKAGE_NAMES, '@ktx/cli'];
|
||||
|
||||
for (const packageName of npmPackages) {
|
||||
const packageRoot = packageName === '@ktx/context' ? 'packages/context' : packageRootForName(packageName);
|
||||
await mkdir(join(root, packageRoot), { recursive: true });
|
||||
await writeJson(join(root, packageRoot, 'package.json'), {
|
||||
name: packageName,
|
||||
for (const packageInfo of INTERNAL_NPM_WORKSPACE_PACKAGES) {
|
||||
await mkdir(join(root, packageInfo.packageRoot), { recursive: true });
|
||||
await writeJson(join(root, packageInfo.packageRoot, 'package.json'), {
|
||||
name: packageInfo.name,
|
||||
version: '0.0.0-private',
|
||||
private: true,
|
||||
});
|
||||
|
|
@ -111,20 +94,8 @@ describe('packageArtifactLayout', () => {
|
|||
assert.equal(layout.artifactDir, '/repo/ktx/dist/artifacts');
|
||||
assert.equal(layout.npmDir, '/repo/ktx/dist/artifacts/npm');
|
||||
assert.equal(layout.pythonDir, '/repo/ktx/dist/artifacts/python');
|
||||
assert.equal(layout.contextTarball, '/repo/ktx/dist/artifacts/npm/ktx-context-0.0.0-private.tgz');
|
||||
assert.equal(layout.cliTarball, '/repo/ktx/dist/artifacts/npm/ktx-cli-0.0.0-private.tgz');
|
||||
assert.equal(
|
||||
layout.connectorTarballs['@ktx/connector-sqlite'],
|
||||
'/repo/ktx/dist/artifacts/npm/ktx-connector-sqlite-0.0.0-private.tgz',
|
||||
);
|
||||
assert.equal(
|
||||
layout.connectorTarballs['@ktx/connector-postgres'],
|
||||
'/repo/ktx/dist/artifacts/npm/ktx-connector-postgres-0.0.0-private.tgz',
|
||||
);
|
||||
assert.deepEqual(
|
||||
Object.keys(layout.npmTarballs),
|
||||
NPM_ARTIFACT_PACKAGES.map((packageInfo) => packageInfo.name),
|
||||
);
|
||||
assert.equal(layout.cliTarball, '/repo/ktx/dist/artifacts/npm/kaelio-ktx-0.0.0-private.tgz');
|
||||
assert.deepEqual(Object.keys(layout.npmTarballs), ['@kaelio/ktx']);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -134,34 +105,23 @@ describe('buildArtifactCommands', () => {
|
|||
const commands = buildArtifactCommands(layout);
|
||||
|
||||
assert.deepEqual(
|
||||
commands.slice(0, NPM_ARTIFACT_PACKAGES.length).map((command) => [command.command, command.args]),
|
||||
commands.slice(0, NPM_BUILD_PACKAGE_ORDER.length).map((command) => [command.command, command.args]),
|
||||
NPM_BUILD_PACKAGE_ORDER.map((packageName) => ['pnpm', ['--filter', packageName, 'run', 'build']]),
|
||||
);
|
||||
assert.deepEqual(
|
||||
commands
|
||||
.slice(NPM_ARTIFACT_PACKAGES.length, NPM_ARTIFACT_PACKAGES.length + 3)
|
||||
.map((command) => [command.command, command.args]),
|
||||
commands.slice(NPM_BUILD_PACKAGE_ORDER.length, NPM_BUILD_PACKAGE_ORDER.length + 3).map((command) => [
|
||||
command.command,
|
||||
command.args,
|
||||
]),
|
||||
[
|
||||
[
|
||||
process.execPath,
|
||||
['scripts/build-python-runtime-wheel.mjs'],
|
||||
],
|
||||
[
|
||||
'uv',
|
||||
['build', '--package', 'ktx-sl', '--out-dir', '/repo/ktx/dist/artifacts/python'],
|
||||
],
|
||||
[
|
||||
'uv',
|
||||
['build', '--package', 'ktx-daemon', '--out-dir', '/repo/ktx/dist/artifacts/python'],
|
||||
],
|
||||
[process.execPath, ['scripts/build-python-runtime-wheel.mjs']],
|
||||
['uv', ['build', '--package', 'ktx-sl', '--out-dir', '/repo/ktx/dist/artifacts/python']],
|
||||
['uv', ['build', '--package', 'ktx-daemon', '--out-dir', '/repo/ktx/dist/artifacts/python']],
|
||||
],
|
||||
);
|
||||
assert.deepEqual(
|
||||
commands.slice(NPM_ARTIFACT_PACKAGES.length + 3).map((command) => [command.command, command.args]),
|
||||
NPM_ARTIFACT_PACKAGES.map((packageInfo) => [
|
||||
'pnpm',
|
||||
['--filter', packageInfo.name, 'pack', '--out', layout.npmTarballs[packageInfo.name]],
|
||||
]),
|
||||
commands.slice(NPM_BUILD_PACKAGE_ORDER.length + 3).map((command) => [command.command, command.args]),
|
||||
[[process.execPath, ['scripts/build-public-npm-package.mjs']]],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -173,14 +133,14 @@ describe('packageReleaseMetadata', () => {
|
|||
await writeReleaseMetadataInputs(root);
|
||||
|
||||
assert.deepEqual(await packageReleaseMetadata(root), [
|
||||
...NPM_ARTIFACT_PACKAGES.map((packageInfo) => ({
|
||||
{
|
||||
ecosystem: 'npm',
|
||||
packageName: packageInfo.name,
|
||||
packageRoot: packageInfo.packageRoot,
|
||||
packageName: '@kaelio/ktx',
|
||||
packageRoot: 'packages/cli',
|
||||
packageVersion: '0.0.0-private',
|
||||
private: true,
|
||||
private: false,
|
||||
releaseMode: 'ci-artifact-only',
|
||||
})),
|
||||
},
|
||||
{
|
||||
ecosystem: 'python',
|
||||
packageName: 'ktx-sl',
|
||||
|
|
@ -262,14 +222,16 @@ describe('artifact manifest', () => {
|
|||
assert.equal(manifest.sourceRevision, 'abc123');
|
||||
assert.deepEqual(
|
||||
manifest.packages.filter((entry) => entry.ecosystem === 'npm'),
|
||||
NPM_ARTIFACT_PACKAGES.map((packageInfo) => ({
|
||||
ecosystem: 'npm',
|
||||
packageName: packageInfo.name,
|
||||
packageRoot: packageInfo.packageRoot,
|
||||
packageVersion: '0.0.0-private',
|
||||
private: true,
|
||||
releaseMode: 'ci-artifact-only',
|
||||
})),
|
||||
[
|
||||
{
|
||||
ecosystem: 'npm',
|
||||
packageName: '@kaelio/ktx',
|
||||
packageRoot: 'packages/cli',
|
||||
packageVersion: '0.0.0-private',
|
||||
private: false,
|
||||
releaseMode: 'ci-artifact-only',
|
||||
},
|
||||
],
|
||||
);
|
||||
assert.deepEqual(
|
||||
manifest.packages.filter((entry) => entry.ecosystem === 'python'),
|
||||
|
|
@ -311,13 +273,15 @@ describe('artifact manifest', () => {
|
|||
path: file.path,
|
||||
}))
|
||||
.sort((left, right) => left.packageName.localeCompare(right.packageName)),
|
||||
NPM_ARTIFACT_PACKAGES.map((packageInfo) => ({
|
||||
artifactKind: 'tarball',
|
||||
ecosystem: 'npm',
|
||||
packageName: packageInfo.name,
|
||||
packageVersion: '0.0.0-private',
|
||||
path: expectedNpmArtifactPath(packageInfo.name),
|
||||
})).sort((left, right) => left.packageName.localeCompare(right.packageName)),
|
||||
[
|
||||
{
|
||||
artifactKind: 'tarball',
|
||||
ecosystem: 'npm',
|
||||
packageName: '@kaelio/ktx',
|
||||
packageVersion: '0.0.0-private',
|
||||
path: 'npm/kaelio-ktx-0.0.0-private.tgz',
|
||||
},
|
||||
],
|
||||
);
|
||||
assert.deepEqual(
|
||||
manifest.files
|
||||
|
|
@ -368,10 +332,10 @@ describe('artifact manifest', () => {
|
|||
],
|
||||
);
|
||||
|
||||
const sqliteEntry = manifest.files.find((file) => file.path === 'npm/ktx-connector-sqlite-0.0.0-private.tgz');
|
||||
assert.ok(sqliteEntry);
|
||||
assert.equal(sqliteEntry.bytes, Buffer.byteLength('@ktx/connector-sqlite-tarball'));
|
||||
assert.equal(sqliteEntry.sha256, createHash('sha256').update('@ktx/connector-sqlite-tarball').digest('hex'));
|
||||
const npmEntry = manifest.files.find((file) => file.path === 'npm/kaelio-ktx-0.0.0-private.tgz');
|
||||
assert.ok(npmEntry);
|
||||
assert.equal(npmEntry.bytes, Buffer.byteLength('@kaelio/ktx-tarball'));
|
||||
assert.equal(npmEntry.sha256, createHash('sha256').update('@kaelio/ktx-tarball').digest('hex'));
|
||||
|
||||
const writtenManifest = JSON.parse(await readFile(artifactManifestPath(layout), 'utf-8'));
|
||||
assert.deepEqual(writtenManifest, manifest);
|
||||
|
|
|
|||
|
|
@ -180,7 +180,12 @@ function assertNonPublishingArtifactPolicy(policy, metadata) {
|
|||
throw new Error(`Package ${entry.packageName} releaseMode must remain ci-artifact-only`);
|
||||
}
|
||||
if (entry.ecosystem === 'npm') {
|
||||
if (entry.private !== true) {
|
||||
const isPublicKtxPackage = entry.packageName === '@kaelio/ktx';
|
||||
if (isPublicKtxPackage) {
|
||||
if (entry.private !== false) {
|
||||
throw new Error(`${policyLabel} npm package @kaelio/ktx must be publishable when npm.publish is false`);
|
||||
}
|
||||
} else if (entry.private !== true) {
|
||||
throw new Error(`${policyLabel} npm package ${entry.packageName} must remain private`);
|
||||
}
|
||||
if (!entry.packageVersion.endsWith('-private')) {
|
||||
|
|
|
|||
|
|
@ -4,25 +4,25 @@ import { tmpdir } from 'node:os';
|
|||
import { join } from 'node:path';
|
||||
import { describe, it } from 'node:test';
|
||||
|
||||
import { NPM_ARTIFACT_PACKAGES, packageArtifactLayout, writeArtifactManifest } from './package-artifacts.mjs';
|
||||
import {
|
||||
INTERNAL_NPM_WORKSPACE_PACKAGES,
|
||||
NPM_ARTIFACT_PACKAGES,
|
||||
packageArtifactLayout,
|
||||
writeArtifactManifest,
|
||||
} from './package-artifacts.mjs';
|
||||
import { readReleasePolicy, releasePolicyPath, releaseReadinessReport } from './release-readiness.mjs';
|
||||
|
||||
async function writeJson(path, value) {
|
||||
await writeFile(path, `${JSON.stringify(value, null, 2)}\n`);
|
||||
}
|
||||
|
||||
async function writeReleaseMetadataInputs(root, options = {}) {
|
||||
for (const packageInfo of NPM_ARTIFACT_PACKAGES) {
|
||||
async function writeReleaseMetadataInputs(root) {
|
||||
for (const packageInfo of INTERNAL_NPM_WORKSPACE_PACKAGES) {
|
||||
await mkdir(join(root, packageInfo.packageRoot), { recursive: true });
|
||||
await writeJson(join(root, packageInfo.packageRoot, 'package.json'), {
|
||||
name: packageInfo.name,
|
||||
version: '0.0.0-private',
|
||||
private:
|
||||
packageInfo.name === '@ktx/context'
|
||||
? (options.contextPrivate ?? true)
|
||||
: packageInfo.name === '@ktx/cli'
|
||||
? (options.cliPrivate ?? true)
|
||||
: true,
|
||||
private: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ function releasePolicy(overrides = {}) {
|
|||
npm: {
|
||||
publish: false,
|
||||
registry: null,
|
||||
packages: NPM_ARTIFACT_PACKAGES.map((packageInfo) => packageInfo.name),
|
||||
packages: ['@kaelio/ktx'],
|
||||
...npmOverrides,
|
||||
},
|
||||
python: {
|
||||
|
|
@ -79,14 +79,12 @@ function releasePolicy(overrides = {}) {
|
|||
...pythonOverrides,
|
||||
},
|
||||
publishedPackageSmoke: {
|
||||
packageName: null,
|
||||
packageName: '@kaelio/ktx',
|
||||
version: 'latest',
|
||||
registry: null,
|
||||
},
|
||||
requiredBeforePublishing: [
|
||||
'Choose npm registry and package visibility.',
|
||||
'Choose Python package repository.',
|
||||
'Choose public release versions.',
|
||||
'Choose public release version.',
|
||||
'Configure registry credentials outside source control.',
|
||||
'Choose release tag and provenance policy.',
|
||||
],
|
||||
|
|
@ -99,7 +97,7 @@ async function writePolicy(root, policy = releasePolicy()) {
|
|||
}
|
||||
|
||||
async function writeReadyFixture(root, options = {}) {
|
||||
await writeReleaseMetadataInputs(root, options);
|
||||
await writeReleaseMetadataInputs(root);
|
||||
await writePolicy(root, options.policy ?? releasePolicy());
|
||||
const layout = packageArtifactLayout(root);
|
||||
await writeUploadableArtifactFixtures(layout);
|
||||
|
|
@ -136,25 +134,18 @@ describe('release readiness policy', () => {
|
|||
sourceRevision: 'abc123',
|
||||
npmPublishEnabled: false,
|
||||
pythonPublishEnabled: false,
|
||||
packageNames: [
|
||||
...NPM_ARTIFACT_PACKAGES.map((packageInfo) => packageInfo.name),
|
||||
'ktx-sl',
|
||||
'ktx-daemon',
|
||||
'kaelio-ktx',
|
||||
],
|
||||
packageNames: ['@kaelio/ktx', 'ktx-sl', 'ktx-daemon', 'kaelio-ktx'],
|
||||
publishedPackageSmokeGate: {
|
||||
status: 'not_required',
|
||||
script: 'pnpm run release:published-smoke',
|
||||
reason: 'Published package smoke remains pending until release-policy.json enables npm registry publishing.',
|
||||
configSource: null,
|
||||
packageName: null,
|
||||
configSource: 'release-policy',
|
||||
packageName: '@kaelio/ktx',
|
||||
version: 'latest',
|
||||
registry: null,
|
||||
},
|
||||
blockedPublishingDecisions: [
|
||||
'Choose npm registry and package visibility.',
|
||||
'Choose Python package repository.',
|
||||
'Choose public release versions.',
|
||||
'Choose public release version.',
|
||||
'Configure registry credentials outside source control.',
|
||||
'Choose release tag and provenance policy.',
|
||||
],
|
||||
|
|
@ -170,7 +161,7 @@ describe('release readiness policy', () => {
|
|||
await writeReadyFixture(root, {
|
||||
policy: releasePolicy({
|
||||
publishedPackageSmoke: {
|
||||
packageName: '@ktx/cli-public',
|
||||
packageName: '@kaelio/ktx',
|
||||
version: '2026.5.8',
|
||||
registry: 'https://registry.npmjs.org/',
|
||||
},
|
||||
|
|
@ -184,7 +175,7 @@ describe('release readiness policy', () => {
|
|||
script: 'pnpm run release:published-smoke',
|
||||
reason: 'Published package smoke remains pending until release-policy.json enables npm registry publishing.',
|
||||
configSource: 'release-policy',
|
||||
packageName: '@ktx/cli-public',
|
||||
packageName: '@kaelio/ktx',
|
||||
version: '2026.5.8',
|
||||
registry: 'https://registry.npmjs.org/',
|
||||
});
|
||||
|
|
@ -200,7 +191,7 @@ describe('release readiness policy', () => {
|
|||
policy: releasePolicy({
|
||||
releaseMode: 'published-package-smoke-required',
|
||||
publishedPackageSmoke: {
|
||||
packageName: '@ktx/cli-public',
|
||||
packageName: '@kaelio/ktx',
|
||||
version: '2026.5.8',
|
||||
registry: 'https://registry.npmjs.org/',
|
||||
},
|
||||
|
|
@ -216,18 +207,13 @@ describe('release readiness policy', () => {
|
|||
sourceRevision: 'abc123',
|
||||
npmPublishEnabled: false,
|
||||
pythonPublishEnabled: false,
|
||||
packageNames: [
|
||||
...NPM_ARTIFACT_PACKAGES.map((packageInfo) => packageInfo.name),
|
||||
'ktx-sl',
|
||||
'ktx-daemon',
|
||||
'kaelio-ktx',
|
||||
],
|
||||
packageNames: ['@kaelio/ktx', 'ktx-sl', 'ktx-daemon', 'kaelio-ktx'],
|
||||
publishedPackageSmokeGate: {
|
||||
status: 'required',
|
||||
script: 'pnpm run release:published-smoke',
|
||||
reason: 'Run the published package smoke before accepting the hybrid-search release.',
|
||||
configSource: 'release-policy',
|
||||
packageName: '@ktx/cli-public',
|
||||
packageName: '@kaelio/ktx',
|
||||
version: '2026.5.8',
|
||||
registry: 'https://registry.npmjs.org/',
|
||||
},
|
||||
|
|
@ -244,6 +230,11 @@ describe('release readiness policy', () => {
|
|||
await writeReadyFixture(root, {
|
||||
policy: releasePolicy({
|
||||
releaseMode: 'published-package-smoke-required',
|
||||
publishedPackageSmoke: {
|
||||
packageName: null,
|
||||
version: 'latest',
|
||||
registry: null,
|
||||
},
|
||||
requiredBeforePublishing: [],
|
||||
}),
|
||||
});
|
||||
|
|
@ -264,7 +255,7 @@ describe('release readiness policy', () => {
|
|||
policy: releasePolicy({
|
||||
releaseMode: 'published-package-smoke-required',
|
||||
publishedPackageSmoke: {
|
||||
packageName: '@ktx/cli-public',
|
||||
packageName: '@kaelio/ktx',
|
||||
version: 'latest',
|
||||
registry: null,
|
||||
},
|
||||
|
|
@ -356,14 +347,20 @@ describe('release readiness policy', () => {
|
|||
}
|
||||
});
|
||||
|
||||
it('rejects a public npm package while releaseMode is ci-artifact-only', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'ktx-release-public-npm-test-'));
|
||||
it('rejects release policy that still lists internal npm packages', async () => {
|
||||
const root = await mkdtemp(join(tmpdir(), 'ktx-release-stale-internal-npm-policy-test-'));
|
||||
try {
|
||||
await writeReadyFixture(root, { contextPrivate: false });
|
||||
await writeReadyFixture(root, {
|
||||
policy: releasePolicy({
|
||||
npm: {
|
||||
packages: ['@kaelio/ktx', '@ktx/context'],
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
await assert.rejects(
|
||||
() => releaseReadinessReport(root),
|
||||
/ci-artifact-only policy npm package @ktx\/context must remain private/,
|
||||
/Release policy npm\.packages mismatch/,
|
||||
);
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue