mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
refactor(release): drop release-policy.json runtime dep and next branch
Strips the release-policy.json fallback from release-version.ts so the CLI
reads its version straight from packages/cli/package.json. dev → 0.0.0-private,
installed @kaelio/ktx → the real semver baked into the published package.json.
KtxCliPackageInfo collapses to { name, version, contextPackageName }; /health
no longer depends on version files surviving past a CI run.
Replaces the dual-branch (main + next) semantic-release model with a single-
branch model on main. rcs and stables interleave on the same branch via
{ name: 'main', prerelease: 'rc', channel: 'next' } / ['main']. Drops
@semantic-release/git and @semantic-release/changelog (nothing is committed
back to the repo on any channel) and the workflow's "Prepare next prerelease
branch" step plus the KTX_PRERELEASE_BRANCH plumbing. The git tag plus the
published npm artifact carry the version forward.
Updates docs/release.md, removes the two now-unused devDeps, regenerates
pnpm-lock.yaml. 611/611 @ktx/cli tests, 173/173 script tests, type-check,
biome, knip all clean.
This commit is contained in:
parent
a0d3ddbbc2
commit
66b674f73a
13 changed files with 83 additions and 320 deletions
45
.github/workflows/release.yml
vendored
45
.github/workflows/release.yml
vendored
|
|
@ -69,27 +69,6 @@ jobs:
|
|||
- name: Install Python dependencies
|
||||
run: uv sync --all-packages
|
||||
|
||||
- name: Prepare next prerelease branch
|
||||
if: ${{ inputs.release_kind == 'rc' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
source_sha="$(git rev-parse HEAD)"
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
if git ls-remote --exit-code --heads origin "${KTX_PRERELEASE_BRANCH}" >/dev/null 2>&1; then
|
||||
git fetch origin "${KTX_PRERELEASE_BRANCH}"
|
||||
git checkout -B "${KTX_PRERELEASE_BRANCH}" "origin/${KTX_PRERELEASE_BRANCH}"
|
||||
git merge --no-edit "${source_sha}"
|
||||
else
|
||||
git checkout -B "${KTX_PRERELEASE_BRANCH}" "${source_sha}"
|
||||
fi
|
||||
|
||||
git push --set-upstream origin "HEAD:${KTX_PRERELEASE_BRANCH}"
|
||||
env:
|
||||
KTX_PRERELEASE_BRANCH: next
|
||||
|
||||
- name: Prepare npm package root for release verification
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
|
@ -112,36 +91,16 @@ jobs:
|
|||
|
||||
- name: Dry-run semantic release
|
||||
if: ${{ !inputs.publish_live }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ "${KTX_RELEASE_KIND}" = "rc" ]; then
|
||||
export GITHUB_REF="refs/heads/${KTX_PRERELEASE_BRANCH}"
|
||||
export GITHUB_REF_NAME="${KTX_PRERELEASE_BRANCH}"
|
||||
export GITHUB_SHA="$(git rev-parse HEAD)"
|
||||
fi
|
||||
|
||||
pnpm run semantic-release:dry-run
|
||||
run: pnpm run semantic-release:dry-run
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
KTX_RELEASE_KIND: ${{ inputs.release_kind }}
|
||||
KTX_PRERELEASE_BRANCH: next
|
||||
FORCE_RELEASE: ${{ inputs.force_release }}
|
||||
|
||||
- name: Create semantic release
|
||||
if: ${{ inputs.publish_live }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [ "${KTX_RELEASE_KIND}" = "rc" ]; then
|
||||
export GITHUB_REF="refs/heads/${KTX_PRERELEASE_BRANCH}"
|
||||
export GITHUB_REF_NAME="${KTX_PRERELEASE_BRANCH}"
|
||||
export GITHUB_SHA="$(git rev-parse HEAD)"
|
||||
fi
|
||||
|
||||
pnpm run semantic-release
|
||||
run: pnpm run semantic-release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
KTX_RELEASE_KIND: ${{ inputs.release_kind }}
|
||||
KTX_PRERELEASE_BRANCH: next
|
||||
FORCE_RELEASE: ${{ inputs.force_release }}
|
||||
|
|
|
|||
|
|
@ -2,25 +2,24 @@
|
|||
|
||||
This runbook covers the maintainer workflow for publishing `@kaelio/ktx` to
|
||||
npm through GitHub Actions. The workflow uses semantic-release to choose the
|
||||
next version, update release metadata, publish the package, create the GitHub
|
||||
release, and commit prerelease files back to the `next` branch.
|
||||
next version, update release metadata in the CI workspace, publish the
|
||||
package, and create the GitHub release. No files are ever committed back to
|
||||
the repository — the git tag and the published npm artifact are the source of
|
||||
truth for any released version.
|
||||
|
||||
## Release channels
|
||||
|
||||
KTX has two npm release channels:
|
||||
`main` is the bleeding-edge branch. Every release runs from `main`; the
|
||||
dispatcher chooses the channel:
|
||||
|
||||
- `rc` publishes prereleases such as `0.1.0-rc.2` to the npm `next` tag.
|
||||
- `stable` publishes normal releases such as `0.1.0` to the npm `latest` tag.
|
||||
- `rc` publishes prereleases such as `0.3.0-rc.1` to the npm `next` tag.
|
||||
- `stable` publishes normal releases such as `0.3.0` to the npm `latest` tag.
|
||||
|
||||
Run rc releases from the source branch you want to publish. The workflow
|
||||
creates or updates the `next` prerelease branch from that source branch before
|
||||
running semantic-release, because semantic-release requires a dedicated
|
||||
prerelease branch in addition to the stable `main` branch. You can publish an
|
||||
rc from `main` when you want to validate the current stable branch before a
|
||||
stable release.
|
||||
Tag history on `main` interleaves rc and stable tags
|
||||
(`v0.2.0 → v0.3.0-rc.1 → v0.3.0-rc.2 → v0.3.0 → …`). semantic-release uses the
|
||||
prerelease tags to graduate to the next stable cleanly.
|
||||
|
||||
Run stable releases only from `main`. The workflow rejects stable releases from
|
||||
other branches.
|
||||
The workflow rejects releases from any branch other than `main`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
|
@ -59,16 +58,15 @@ publishing to npm.
|
|||
|
||||
1. Open **Actions** in GitHub.
|
||||
2. Select **KTX Release**.
|
||||
3. Select the branch to release from.
|
||||
3. Select `main`.
|
||||
4. Set **release_kind** to `rc` or `stable`.
|
||||
5. Set **publish_live** to `false`.
|
||||
6. Optional: Set **force_release** to `true` when you need a patch release even
|
||||
if semantic-release doesn't find a releasable commit.
|
||||
7. Run the workflow.
|
||||
|
||||
The dry-run uses the same semantic-release configuration as a live release. For
|
||||
rc releases, it can create or update the `next` branch. It doesn't publish to
|
||||
npm and doesn't commit release files.
|
||||
The dry-run uses the same semantic-release configuration as a live release. It
|
||||
doesn't publish to npm and doesn't push any tags.
|
||||
|
||||
## Publish an rc release
|
||||
|
||||
|
|
@ -77,16 +75,15 @@ promoting to `latest`.
|
|||
|
||||
1. Open **Actions** in GitHub.
|
||||
2. Select **KTX Release**.
|
||||
3. Select the source branch to release from, including `main` when needed.
|
||||
3. Select `main`.
|
||||
4. Set **release_kind** to `rc`.
|
||||
5. Leave **publish_live** set to `true`.
|
||||
6. Optional: Set **force_release** to `true`.
|
||||
7. Run the workflow.
|
||||
|
||||
The workflow merges the selected source branch into `next`, publishes
|
||||
`@kaelio/ktx` with `--access public --tag next`, runs the published package
|
||||
smoke test, creates a GitHub release, and commits `CHANGELOG.md`,
|
||||
`package.json`, and `release-policy.json` on `next`.
|
||||
The workflow publishes `@kaelio/ktx` with `--access public --tag next`, runs
|
||||
the published package smoke test, creates a GitHub release, and pushes the
|
||||
`vX.Y.Z-rc.N` tag.
|
||||
|
||||
## Publish a stable release
|
||||
|
||||
|
|
@ -101,26 +98,28 @@ Publish a stable release from `main` after you have validated an rc package.
|
|||
7. Run the workflow.
|
||||
|
||||
The workflow publishes `@kaelio/ktx` with `--access public --tag latest`, runs
|
||||
the published package smoke test, and creates a GitHub release. Stable releases
|
||||
don't commit release metadata back to `main`, because `main` is protected and
|
||||
requires changes through pull requests.
|
||||
the published package smoke test, creates a GitHub release, and pushes the
|
||||
`vX.Y.Z` tag. semantic-release graduates from the most recent rc tag, so the
|
||||
prior rc lineage is consumed cleanly.
|
||||
|
||||
## Release metadata
|
||||
|
||||
semantic-release calls `scripts/update-public-release-version.mjs` during the
|
||||
prepare step before `@semantic-release/npm` publishes the package. That script
|
||||
updates:
|
||||
prepare step before the exec publish command runs. That script updates the
|
||||
following files **inside the CI runner only**:
|
||||
|
||||
- `package.json` with the semantic-release version.
|
||||
- `release-policy.json` with `publicNpmPackageVersion`, npm publish settings,
|
||||
and the published package smoke-test version.
|
||||
|
||||
The artifact packaging and readiness scripts read `publicNpmPackageVersion`
|
||||
from `release-policy.json`, so manual version edits in build scripts aren't
|
||||
needed for rc releases. The semantic-release npm plugin publishes the generated
|
||||
`dist/public-npm-package` tree and writes the release tarball under
|
||||
`dist/artifacts/npm`. Stable releases use the updated metadata during the
|
||||
workflow run, but that generated metadata isn't committed back to `main`.
|
||||
The artifact packaging, readiness, and smoke-test scripts read
|
||||
`publicNpmPackageVersion` from `release-policy.json` within the same CI run.
|
||||
Nothing reads these files at runtime — the daemon and CLI rely on the
|
||||
published `package.json` (for the installed `@kaelio/ktx` package) or
|
||||
`packages/cli/package.json` (for dev-tree runs from this repo, which always
|
||||
report `0.0.0-private`). Because the metadata mutation never has to survive
|
||||
the run, no commit is pushed back to `main`. The git tag plus the published
|
||||
npm artifact carry the version forward.
|
||||
|
||||
The bundled Python runtime wheel also derives its version from
|
||||
`publicNpmPackageVersion`. Stable npm versions are reused as-is, and rc
|
||||
|
|
|
|||
|
|
@ -48,10 +48,8 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.4.15",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/commit-analyzer": "^13.0.1",
|
||||
"@semantic-release/exec": "^7.1.0",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
"@semantic-release/github": "^12.0.8",
|
||||
"@semantic-release/npm": "^13.1.5",
|
||||
"@semantic-release/release-notes-generator": "^14.1.1",
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ describe('admin reindex Commander routing', () => {
|
|||
force: true,
|
||||
json: true,
|
||||
output: 'plain',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
},
|
||||
io.io,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ function stubPackageInfo(): KtxCliPackageInfo {
|
|||
return {
|
||||
name: '@ktx/cli',
|
||||
version: '0.0.0-test',
|
||||
packageVersion: '0.0.0-private',
|
||||
runtimeVersion: '0.0.0-test',
|
||||
contextPackageName: '@ktx/context',
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import type { KtxSlArgs } from './sl.js';
|
|||
import type { KtxSqlArgs } from './sql.js';
|
||||
import { profileMark, profileSpan } from './startup-profile.js';
|
||||
import type { KtxTextIngestArgs } from './text-ingest.js';
|
||||
import { resolveKtxRuntimeVersion } from './release-version.js';
|
||||
import { assertCliVersion } from './release-version.js';
|
||||
|
||||
profileMark('module:cli-runtime');
|
||||
|
||||
|
|
@ -20,8 +20,6 @@ const requirePackageJson = createRequire(import.meta.url);
|
|||
export interface KtxCliPackageInfo {
|
||||
name: string;
|
||||
version: string;
|
||||
packageVersion: string;
|
||||
runtimeVersion: string;
|
||||
contextPackageName: '@ktx/context';
|
||||
}
|
||||
|
||||
|
|
@ -66,16 +64,9 @@ export function packageInfoFromJson(packageJson: unknown): KtxCliPackageInfo {
|
|||
throw new Error('Invalid KTX CLI package metadata');
|
||||
}
|
||||
|
||||
const runtimeVersion = resolveKtxRuntimeVersion({
|
||||
packageName: packageJson.name,
|
||||
packageVersion: packageJson.version,
|
||||
});
|
||||
|
||||
return {
|
||||
name: packageJson.name,
|
||||
version: runtimeVersion,
|
||||
packageVersion: packageJson.version,
|
||||
runtimeVersion,
|
||||
version: assertCliVersion(packageJson.version, `${packageJson.name}/package.json`),
|
||||
contextPackageName: '@ktx/context',
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,9 +45,7 @@ describe('getKtxCliPackageInfo', () => {
|
|||
it('identifies the CLI package and its context dependency', () => {
|
||||
expect(getKtxCliPackageInfo()).toEqual({
|
||||
name: '@ktx/cli',
|
||||
version: '0.1.0-rc.1',
|
||||
packageVersion: '0.0.0-private',
|
||||
runtimeVersion: '0.1.0-rc.1',
|
||||
version: '0.0.0-private',
|
||||
contextPackageName: '@ktx/context',
|
||||
});
|
||||
});
|
||||
|
|
@ -70,8 +68,6 @@ describe('getKtxCliPackageInfo', () => {
|
|||
).toEqual({
|
||||
name: '@kaelio/ktx',
|
||||
version: '0.1.0',
|
||||
packageVersion: '0.1.0',
|
||||
runtimeVersion: '0.1.0',
|
||||
contextPackageName: '@ktx/context',
|
||||
});
|
||||
});
|
||||
|
|
@ -118,7 +114,7 @@ describe('runKtxCli', () => {
|
|||
|
||||
await expect(runKtxCli(['--version'], testIo.io)).resolves.toBe(0);
|
||||
|
||||
expect(testIo.stdout()).toBe('@ktx/cli 0.1.0-rc.1\n');
|
||||
expect(testIo.stdout()).toBe('@ktx/cli 0.0.0-private\n');
|
||||
expect(testIo.stderr()).toBe('');
|
||||
});
|
||||
|
||||
|
|
@ -282,7 +278,7 @@ describe('runKtxCli', () => {
|
|||
expect(unknownIo.stderr()).toContain("unknown option '--query'");
|
||||
});
|
||||
|
||||
it('routes runtime management commands with the release runtime version', async () => {
|
||||
it('routes runtime management commands with the CLI package version', async () => {
|
||||
const runtime = vi.fn(async () => 0);
|
||||
const installIo = makeIo();
|
||||
const startIo = makeIo();
|
||||
|
|
@ -308,7 +304,7 @@ describe('runKtxCli', () => {
|
|||
1,
|
||||
{
|
||||
command: 'install',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
feature: 'local-embeddings',
|
||||
force: true,
|
||||
},
|
||||
|
|
@ -318,7 +314,7 @@ describe('runKtxCli', () => {
|
|||
2,
|
||||
{
|
||||
command: 'start',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
projectDir: expect.any(String),
|
||||
feature: 'local-embeddings',
|
||||
force: true,
|
||||
|
|
@ -329,7 +325,7 @@ describe('runKtxCli', () => {
|
|||
3,
|
||||
{
|
||||
command: 'stop',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
projectDir: expect.any(String),
|
||||
all: false,
|
||||
},
|
||||
|
|
@ -339,7 +335,7 @@ describe('runKtxCli', () => {
|
|||
4,
|
||||
{
|
||||
command: 'stop',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
projectDir: expect.any(String),
|
||||
all: true,
|
||||
},
|
||||
|
|
@ -349,7 +345,7 @@ describe('runKtxCli', () => {
|
|||
5,
|
||||
{
|
||||
command: 'status',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
json: true,
|
||||
},
|
||||
statusIo.io,
|
||||
|
|
@ -422,7 +418,7 @@ describe('runKtxCli', () => {
|
|||
expect.objectContaining({
|
||||
command: 'query',
|
||||
projectDir: tempDir,
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'prompt',
|
||||
query: expect.objectContaining({ measures: ['orders.order_count'], dimensions: [] }),
|
||||
}),
|
||||
|
|
@ -437,7 +433,7 @@ describe('runKtxCli', () => {
|
|||
).resolves.toBe(0);
|
||||
expect(sl).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'auto',
|
||||
}),
|
||||
autoIo.io,
|
||||
|
|
@ -453,7 +449,7 @@ describe('runKtxCli', () => {
|
|||
).resolves.toBe(0);
|
||||
expect(sl).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'never',
|
||||
}),
|
||||
noInputIo.io,
|
||||
|
|
@ -589,7 +585,7 @@ describe('runKtxCli', () => {
|
|||
skipAgents: false,
|
||||
inputMode: 'auto',
|
||||
yes: false,
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
skipLlm: false,
|
||||
skipEmbeddings: false,
|
||||
databaseSchemas: [],
|
||||
|
|
@ -719,7 +715,7 @@ describe('runKtxCli', () => {
|
|||
inputMode: 'disabled',
|
||||
depth: 'fast',
|
||||
queryHistory: 'default',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'never',
|
||||
},
|
||||
testIo.io,
|
||||
|
|
@ -746,7 +742,7 @@ describe('runKtxCli', () => {
|
|||
inputMode: 'auto',
|
||||
depth: 'deep',
|
||||
queryHistory: 'default',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'prompt',
|
||||
},
|
||||
testIo.io,
|
||||
|
|
@ -823,7 +819,7 @@ describe('runKtxCli', () => {
|
|||
json: false,
|
||||
inputMode: 'disabled',
|
||||
queryHistory: 'default',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'never',
|
||||
},
|
||||
testIo.io,
|
||||
|
|
@ -1128,7 +1124,7 @@ describe('runKtxCli', () => {
|
|||
command: 'run',
|
||||
projectDir: tempDir,
|
||||
inputMode: 'disabled',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
anthropicApiKeyEnv: 'ANTHROPIC_API_KEY', // pragma: allowlist secret
|
||||
llmModel: 'claude-sonnet-4-6',
|
||||
skipLlm: false,
|
||||
|
|
@ -1167,7 +1163,7 @@ describe('runKtxCli', () => {
|
|||
command: 'run',
|
||||
projectDir: tempDir,
|
||||
inputMode: 'disabled',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
llmBackend: 'vertex',
|
||||
vertexProject: 'local-gcp-project',
|
||||
vertexLocation: 'us-east5',
|
||||
|
|
@ -1204,7 +1200,7 @@ describe('runKtxCli', () => {
|
|||
command: 'run',
|
||||
projectDir: tempDir,
|
||||
inputMode: 'disabled',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
llmBackend: 'claude-code',
|
||||
llmModel: 'opus',
|
||||
skipLlm: false,
|
||||
|
|
@ -1312,7 +1308,7 @@ describe('runKtxCli', () => {
|
|||
projectDir: '/tmp/project',
|
||||
inputMode: 'disabled',
|
||||
yes: true,
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
skipLlm: true,
|
||||
skipEmbeddings: true,
|
||||
databaseDrivers: ['postgres'],
|
||||
|
|
@ -1653,7 +1649,7 @@ describe('runKtxCli', () => {
|
|||
queryFile: '/tmp/query.json',
|
||||
execute: false,
|
||||
format: 'json',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'auto',
|
||||
},
|
||||
autoIo.io,
|
||||
|
|
@ -1667,7 +1663,7 @@ describe('runKtxCli', () => {
|
|||
queryFile: '/tmp/query.json',
|
||||
execute: false,
|
||||
format: 'json',
|
||||
cliVersion: '0.1.0-rc.1',
|
||||
cliVersion: '0.0.0-private',
|
||||
runtimeInstallPolicy: 'never',
|
||||
},
|
||||
neverIo.io,
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ function stubPackageInfo(): KtxCliPackageInfo {
|
|||
return {
|
||||
name: '@ktx/cli',
|
||||
version: '0.0.0-docs',
|
||||
packageVersion: '0.0.0-private',
|
||||
runtimeVersion: '0.0.0-docs',
|
||||
contextPackageName: '@ktx/context',
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +1,9 @@
|
|||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { dirname, join, parse } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const semverPattern =
|
||||
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
||||
|
||||
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function assertReleaseVersion(value: unknown, source: string): string {
|
||||
export function assertCliVersion(value: unknown, source: string): string {
|
||||
if (typeof value !== 'string' || !semverPattern.test(value)) {
|
||||
throw new Error(`Invalid KTX release version in ${source}`);
|
||||
throw new Error(`Invalid KTX CLI version in ${source}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function findReleasePolicyPath(startDir: string): string | undefined {
|
||||
let current = startDir;
|
||||
const root = parse(current).root;
|
||||
while (true) {
|
||||
const candidate = join(current, 'release-policy.json');
|
||||
if (existsSync(candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
if (current === root) {
|
||||
return undefined;
|
||||
}
|
||||
current = dirname(current);
|
||||
}
|
||||
}
|
||||
|
||||
function readSourceReleaseVersion(startDir = dirname(fileURLToPath(import.meta.url))): string | undefined {
|
||||
const policyPath = findReleasePolicyPath(startDir);
|
||||
if (!policyPath) {
|
||||
return undefined;
|
||||
}
|
||||
const policy = JSON.parse(readFileSync(policyPath, 'utf8')) as unknown;
|
||||
if (!isPlainObject(policy)) {
|
||||
throw new Error(`Invalid KTX release policy: ${policyPath}`);
|
||||
}
|
||||
return assertReleaseVersion(policy.publicNpmPackageVersion, policyPath);
|
||||
}
|
||||
|
||||
export function resolveKtxRuntimeVersion(input: {
|
||||
packageName: string;
|
||||
packageVersion: string;
|
||||
startDir?: string;
|
||||
}): string {
|
||||
if (input.packageName === '@kaelio/ktx') {
|
||||
return assertReleaseVersion(input.packageVersion, `${input.packageName}/package.json`);
|
||||
}
|
||||
return readSourceReleaseVersion(input.startDir) ?? input.packageVersion;
|
||||
}
|
||||
|
|
|
|||
93
pnpm-lock.yaml
generated
93
pnpm-lock.yaml
generated
|
|
@ -15,18 +15,12 @@ importers:
|
|||
'@biomejs/biome':
|
||||
specifier: ^2.4.15
|
||||
version: 2.4.15
|
||||
'@semantic-release/changelog':
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3(semantic-release@25.0.3(typescript@6.0.3))
|
||||
'@semantic-release/commit-analyzer':
|
||||
specifier: ^13.0.1
|
||||
version: 13.0.1(semantic-release@25.0.3(typescript@6.0.3))
|
||||
'@semantic-release/exec':
|
||||
specifier: ^7.1.0
|
||||
version: 7.1.0(semantic-release@25.0.3(typescript@6.0.3))
|
||||
'@semantic-release/git':
|
||||
specifier: ^10.0.1
|
||||
version: 10.0.1(semantic-release@25.0.3(typescript@6.0.3))
|
||||
'@semantic-release/github':
|
||||
specifier: ^12.0.8
|
||||
version: 12.0.8(semantic-release@25.0.3(typescript@6.0.3))
|
||||
|
|
@ -2326,22 +2320,12 @@ packages:
|
|||
'@sec-ant/readable-stream@0.4.1':
|
||||
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
|
||||
|
||||
'@semantic-release/changelog@6.0.3':
|
||||
resolution: {integrity: sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag==}
|
||||
engines: {node: '>=14.17'}
|
||||
peerDependencies:
|
||||
semantic-release: '>=18.0.0'
|
||||
|
||||
'@semantic-release/commit-analyzer@13.0.1':
|
||||
resolution: {integrity: sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ==}
|
||||
engines: {node: '>=20.8.1'}
|
||||
peerDependencies:
|
||||
semantic-release: '>=20.1.0'
|
||||
|
||||
'@semantic-release/error@3.0.0':
|
||||
resolution: {integrity: sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==}
|
||||
engines: {node: '>=14.17'}
|
||||
|
||||
'@semantic-release/error@4.0.0':
|
||||
resolution: {integrity: sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
|
@ -2352,12 +2336,6 @@ packages:
|
|||
peerDependencies:
|
||||
semantic-release: '>=24.1.0'
|
||||
|
||||
'@semantic-release/git@10.0.1':
|
||||
resolution: {integrity: sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==}
|
||||
engines: {node: '>=14.17'}
|
||||
peerDependencies:
|
||||
semantic-release: '>=18.0.0'
|
||||
|
||||
'@semantic-release/github@12.0.8':
|
||||
resolution: {integrity: sha512-tej5AAgK5X9wHRoDmYhecMXEHEkFeGOY1XsEblKxu8pIQwahzf1STYyr7iPU6Lpbg6C5I3N2w/ocXrBo+L7jhw==}
|
||||
engines: {node: ^22.14.0 || >= 24.10.0}
|
||||
|
|
@ -3623,10 +3601,6 @@ packages:
|
|||
resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
execa@5.1.1:
|
||||
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
execa@8.0.1:
|
||||
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
|
||||
engines: {node: '>=16.17'}
|
||||
|
|
@ -4106,10 +4080,6 @@ packages:
|
|||
resolution: {integrity: sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g==}
|
||||
engines: {node: '>= 20'}
|
||||
|
||||
human-signals@2.1.0:
|
||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||
engines: {node: '>=10.17.0'}
|
||||
|
||||
human-signals@5.0.0:
|
||||
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
|
||||
engines: {node: '>=16.17.0'}
|
||||
|
|
@ -4490,9 +4460,6 @@ packages:
|
|||
lodash.uniqby@4.7.0:
|
||||
resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==}
|
||||
|
||||
lodash@4.18.1:
|
||||
resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==}
|
||||
|
||||
logform@2.7.0:
|
||||
resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
|
@ -4909,10 +4876,6 @@ packages:
|
|||
resolution: {integrity: sha512-z9nC87iaZXXySbWWtTHfCFJyFvKaUAW6lODhikG7ILSbVgmwuFjUqkgnheHvAUcGedO29e2QGBRXMUD64aurqQ==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
npm-run-path@4.0.1:
|
||||
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
npm-run-path@5.3.0:
|
||||
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
|
@ -5085,10 +5048,6 @@ packages:
|
|||
resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
p-reduce@2.1.0:
|
||||
resolution: {integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
p-reduce@3.0.0:
|
||||
resolution: {integrity: sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -5707,10 +5666,6 @@ packages:
|
|||
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
strip-final-newline@2.0.0:
|
||||
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
strip-final-newline@3.0.0:
|
||||
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
|
||||
engines: {node: '>=12'}
|
||||
|
|
@ -8558,14 +8513,6 @@ snapshots:
|
|||
|
||||
'@sec-ant/readable-stream@0.4.1': {}
|
||||
|
||||
'@semantic-release/changelog@6.0.3(semantic-release@25.0.3(typescript@6.0.3))':
|
||||
dependencies:
|
||||
'@semantic-release/error': 3.0.0
|
||||
aggregate-error: 3.1.0
|
||||
fs-extra: 11.3.5
|
||||
lodash: 4.18.1
|
||||
semantic-release: 25.0.3(typescript@6.0.3)
|
||||
|
||||
'@semantic-release/commit-analyzer@13.0.1(semantic-release@25.0.3(typescript@6.0.3))':
|
||||
dependencies:
|
||||
conventional-changelog-angular: 8.3.1
|
||||
|
|
@ -8580,8 +8527,6 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@semantic-release/error@3.0.0': {}
|
||||
|
||||
'@semantic-release/error@4.0.0': {}
|
||||
|
||||
'@semantic-release/exec@7.1.0(semantic-release@25.0.3(typescript@6.0.3))':
|
||||
|
|
@ -8596,20 +8541,6 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@semantic-release/git@10.0.1(semantic-release@25.0.3(typescript@6.0.3))':
|
||||
dependencies:
|
||||
'@semantic-release/error': 3.0.0
|
||||
aggregate-error: 3.1.0
|
||||
debug: 4.4.3
|
||||
dir-glob: 3.0.1
|
||||
execa: 5.1.1
|
||||
lodash: 4.18.1
|
||||
micromatch: 4.0.8
|
||||
p-reduce: 2.1.0
|
||||
semantic-release: 25.0.3(typescript@6.0.3)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@semantic-release/github@12.0.8(semantic-release@25.0.3(typescript@6.0.3))':
|
||||
dependencies:
|
||||
'@octokit/core': 7.0.6
|
||||
|
|
@ -10034,18 +9965,6 @@ snapshots:
|
|||
dependencies:
|
||||
eventsource-parser: 3.0.8
|
||||
|
||||
execa@5.1.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
get-stream: 6.0.1
|
||||
human-signals: 2.1.0
|
||||
is-stream: 2.0.1
|
||||
merge-stream: 2.0.0
|
||||
npm-run-path: 4.0.1
|
||||
onetime: 5.1.2
|
||||
signal-exit: 3.0.7
|
||||
strip-final-newline: 2.0.0
|
||||
|
||||
execa@8.0.1:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.6
|
||||
|
|
@ -10642,8 +10561,6 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
human-signals@2.1.0: {}
|
||||
|
||||
human-signals@5.0.0: {}
|
||||
|
||||
human-signals@8.0.1: {}
|
||||
|
|
@ -10983,8 +10900,6 @@ snapshots:
|
|||
|
||||
lodash.uniqby@4.7.0: {}
|
||||
|
||||
lodash@4.18.1: {}
|
||||
|
||||
logform@2.7.0:
|
||||
dependencies:
|
||||
'@colors/colors': 1.6.0
|
||||
|
|
@ -11671,10 +11586,6 @@ snapshots:
|
|||
|
||||
normalize-url@9.0.0: {}
|
||||
|
||||
npm-run-path@4.0.1:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
|
||||
npm-run-path@5.3.0:
|
||||
dependencies:
|
||||
path-key: 4.0.0
|
||||
|
|
@ -11818,8 +11729,6 @@ snapshots:
|
|||
|
||||
p-map@7.0.4: {}
|
||||
|
||||
p-reduce@2.1.0: {}
|
||||
|
||||
p-reduce@3.0.0: {}
|
||||
|
||||
p-timeout@6.1.4: {}
|
||||
|
|
@ -12619,8 +12528,6 @@ snapshots:
|
|||
|
||||
strip-bom@3.0.0: {}
|
||||
|
||||
strip-final-newline@2.0.0: {}
|
||||
|
||||
strip-final-newline@3.0.0: {}
|
||||
|
||||
strip-final-newline@4.0.0: {}
|
||||
|
|
|
|||
|
|
@ -21,15 +21,14 @@ describe('release workflow', () => {
|
|||
assert.doesNotMatch(workflow, /Prepare first stable release floor/);
|
||||
assert.doesNotMatch(workflow, /git tag v0\.0\.0/);
|
||||
assert.doesNotMatch(workflow, /KTX_STABLE_RELEASE_FLOOR_TAG/);
|
||||
assert.match(workflow, /Prepare next prerelease branch/);
|
||||
assert.match(workflow, /git checkout -B "\$\{KTX_PRERELEASE_BRANCH\}"/);
|
||||
assert.doesNotMatch(workflow, /Prepare next prerelease branch/);
|
||||
assert.doesNotMatch(workflow, /KTX_PRERELEASE_BRANCH/);
|
||||
assert.doesNotMatch(workflow, /GITHUB_REF="refs\/heads\//);
|
||||
assert.match(workflow, /Prepare npm package root for release verification/);
|
||||
assert.match(workflow, /dist\/public-npm-package\/package\.json/);
|
||||
assert.match(workflow, /GITHUB_REF="refs\/heads\/\$\{KTX_PRERELEASE_BRANCH\}"/);
|
||||
assert.match(workflow, /pnpm run semantic-release:dry-run/);
|
||||
assert.match(workflow, /pnpm run semantic-release$/m);
|
||||
assert.match(workflow, /KTX_RELEASE_KIND: \$\{\{ inputs.release_kind \}\}/);
|
||||
assert.match(workflow, /KTX_PRERELEASE_BRANCH: next/);
|
||||
assert.match(workflow, /FORCE_RELEASE: \$\{\{ inputs.force_release \}\}/);
|
||||
assert.doesNotMatch(workflow, /NODE_AUTH_TOKEN/);
|
||||
assert.doesNotMatch(workflow, /^ push:/m);
|
||||
|
|
|
|||
|
|
@ -82,46 +82,23 @@ function releaseKind(env) {
|
|||
return env.KTX_RELEASE_KIND || env.INPUT_RELEASE_KIND || 'rc';
|
||||
}
|
||||
|
||||
function prereleaseBranch(env) {
|
||||
return env.KTX_PRERELEASE_BRANCH || env.INPUT_PRERELEASE_BRANCH || 'next';
|
||||
}
|
||||
|
||||
function releaseTag(kind) {
|
||||
return kind === 'rc' ? 'next' : 'latest';
|
||||
}
|
||||
|
||||
function releaseChangelogPlugins(kind) {
|
||||
return kind === 'rc' ? ['@semantic-release/changelog'] : [];
|
||||
}
|
||||
|
||||
function releaseGitPlugins(kind) {
|
||||
if (kind !== 'rc') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
'@semantic-release/git',
|
||||
{
|
||||
assets: ['CHANGELOG.md', 'package.json', 'release-policy.json'],
|
||||
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
|
||||
},
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
function releaseBranches(env = process.env) {
|
||||
const branch = currentBranch(env);
|
||||
const kind = releaseKind(env);
|
||||
|
||||
if (branch !== 'main') {
|
||||
throw new Error(`KTX releases must run from main, got ${branch}`);
|
||||
}
|
||||
|
||||
if (kind === 'rc') {
|
||||
return ['main', { name: prereleaseBranch(env), prerelease: 'rc', channel: 'next' }];
|
||||
return [{ name: 'main', prerelease: 'rc', channel: 'next' }];
|
||||
}
|
||||
|
||||
if (kind === 'stable') {
|
||||
if (branch !== 'main') {
|
||||
throw new Error(`Stable KTX releases must run from main, got ${branch}`);
|
||||
}
|
||||
return ['main'];
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +134,6 @@ function createReleaseConfig(env = process.env) {
|
|||
},
|
||||
},
|
||||
],
|
||||
...releaseChangelogPlugins(kind),
|
||||
[
|
||||
'@semantic-release/exec',
|
||||
{
|
||||
|
|
@ -172,7 +148,6 @@ function createReleaseConfig(env = process.env) {
|
|||
].join(' && '),
|
||||
},
|
||||
],
|
||||
...releaseGitPlugins(kind),
|
||||
[
|
||||
'@semantic-release/github',
|
||||
{
|
||||
|
|
@ -188,7 +163,6 @@ function createReleaseConfig(env = process.env) {
|
|||
|
||||
module.exports = {
|
||||
createReleaseConfig,
|
||||
prereleaseBranch,
|
||||
releaseBranches,
|
||||
releaseKind,
|
||||
releaseTag,
|
||||
|
|
|
|||
|
|
@ -9,21 +9,16 @@ function releaseExecOptions(config) {
|
|||
return config.plugins.find((plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/exec' && plugin[1].prepareCmd)[1];
|
||||
}
|
||||
|
||||
function releaseExecIndex(config) {
|
||||
return config.plugins.findIndex((plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/exec' && plugin[1].prepareCmd);
|
||||
}
|
||||
|
||||
function pluginNames(config) {
|
||||
return config.plugins.map((plugin) => (Array.isArray(plugin) ? plugin[0] : plugin));
|
||||
}
|
||||
|
||||
describe('semantic-release config', () => {
|
||||
it('configures rc releases on a dedicated next prerelease branch', () => {
|
||||
it('configures rc releases as a prerelease on main', () => {
|
||||
assert.equal(releaseKind({ KTX_RELEASE_KIND: 'rc' }), 'rc');
|
||||
assert.equal(releaseTag('rc'), 'next');
|
||||
assert.deepEqual(releaseBranches({ KTX_RELEASE_KIND: 'rc', GITHUB_REF_NAME: 'main' }), [
|
||||
'main',
|
||||
{ name: 'next', prerelease: 'rc', channel: 'next' },
|
||||
{ name: 'main', prerelease: 'rc', channel: 'next' },
|
||||
]);
|
||||
|
||||
const config = createReleaseConfig({ KTX_RELEASE_KIND: 'rc', GITHUB_REF_NAME: 'main' });
|
||||
|
|
@ -42,14 +37,6 @@ describe('semantic-release config', () => {
|
|||
);
|
||||
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',
|
||||
);
|
||||
assert.deepEqual(releaseFilePluginNames, ['@semantic-release/changelog', '@semantic-release/git']);
|
||||
|
||||
const names = pluginNames(config);
|
||||
assert.ok(names.indexOf('@semantic-release/changelog') < releaseExecIndex(config));
|
||||
assert.ok(names.indexOf('@semantic-release/git') > releaseExecIndex(config));
|
||||
});
|
||||
|
||||
it('configures stable releases only from main with latest tag', () => {
|
||||
|
|
@ -69,18 +56,21 @@ describe('semantic-release config', () => {
|
|||
assert.equal(config.plugins.includes('./scripts/semantic-release-version-policy.cjs'), false);
|
||||
});
|
||||
|
||||
it('does not commit release files back to protected main during stable releases', () => {
|
||||
const config = createReleaseConfig({ KTX_RELEASE_KIND: 'stable', GITHUB_REF_NAME: 'main' });
|
||||
|
||||
assert.equal(pluginNames(config).includes('@semantic-release/git'), false);
|
||||
assert.equal(pluginNames(config).includes('@semantic-release/changelog'), false);
|
||||
it('never commits release files back to the repo', () => {
|
||||
for (const kind of ['rc', 'stable']) {
|
||||
const config = createReleaseConfig({ KTX_RELEASE_KIND: kind, GITHUB_REF_NAME: 'main' });
|
||||
assert.equal(pluginNames(config).includes('@semantic-release/git'), false, `${kind}: @semantic-release/git`);
|
||||
assert.equal(pluginNames(config).includes('@semantic-release/changelog'), false, `${kind}: @semantic-release/changelog`);
|
||||
}
|
||||
});
|
||||
|
||||
it('rejects stable releases from non-main branches', () => {
|
||||
assert.throws(
|
||||
() => releaseBranches({ KTX_RELEASE_KIND: 'stable', GITHUB_REF_NAME: 'feature/release-test' }),
|
||||
/Stable KTX releases must run from main, got feature\/release-test/,
|
||||
);
|
||||
it('rejects releases from non-main branches', () => {
|
||||
for (const kind of ['rc', 'stable']) {
|
||||
assert.throws(
|
||||
() => releaseBranches({ KTX_RELEASE_KIND: kind, GITHUB_REF_NAME: 'feature/release-test' }),
|
||||
/KTX releases must run from main, got feature\/release-test/,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps the force-release patch escape hatch', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue