mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
feat(release): one version everywhere via @semantic-release/git (#186)
* feat(release): commit version files back to branch for one-version-everywhere
Add @semantic-release/git to the release plugin chain so the bumped
package.json, release-policy.json, and packages/cli/package.json land
back on the release branch after publish. This keeps the published npm
version and the in-repo version files in sync, so local builds from
main report the released version (e.g. ktx --version and the daemon
/health endpoint via KTX_DAEMON_VERSION).
Also widens assertPublicNpmReleaseTag to accept branch-<sanitized> tags,
unblocking branch RC publishes that pass through update-public-release-
version.mjs.
* test(release): pin GITHUB_REF_NAME in main-rc releaseTag assertion
The bare releaseTag('rc') call defaulted to process.env.GITHUB_REF_NAME,
which on PR CI is the merge ref (e.g. 186/merge) and yields
'branch-186-merge' instead of 'next'. Pass an explicit { GITHUB_REF_NAME:
'main' } so the test exercises the main-rc path regardless of CI env.
This commit is contained in:
parent
2667952aa9
commit
2f70861a18
8 changed files with 192 additions and 14 deletions
|
|
@ -50,6 +50,7 @@
|
||||||
"@biomejs/biome": "^2.4.15",
|
"@biomejs/biome": "^2.4.15",
|
||||||
"@semantic-release/commit-analyzer": "^13.0.1",
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
||||||
"@semantic-release/exec": "^7.1.0",
|
"@semantic-release/exec": "^7.1.0",
|
||||||
|
"@semantic-release/git": "^10.0.1",
|
||||||
"@semantic-release/github": "^12.0.8",
|
"@semantic-release/github": "^12.0.8",
|
||||||
"@semantic-release/npm": "^13.1.5",
|
"@semantic-release/npm": "^13.1.5",
|
||||||
"@semantic-release/release-notes-generator": "^14.1.1",
|
"@semantic-release/release-notes-generator": "^14.1.1",
|
||||||
|
|
|
||||||
76
pnpm-lock.yaml
generated
76
pnpm-lock.yaml
generated
|
|
@ -28,6 +28,9 @@ importers:
|
||||||
'@semantic-release/exec':
|
'@semantic-release/exec':
|
||||||
specifier: ^7.1.0
|
specifier: ^7.1.0
|
||||||
version: 7.1.0(semantic-release@25.0.3(typescript@6.0.3))
|
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':
|
'@semantic-release/github':
|
||||||
specifier: ^12.0.8
|
specifier: ^12.0.8
|
||||||
version: 12.0.8(semantic-release@25.0.3(typescript@6.0.3))
|
version: 12.0.8(semantic-release@25.0.3(typescript@6.0.3))
|
||||||
|
|
@ -2333,6 +2336,10 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
semantic-release: '>=20.1.0'
|
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':
|
'@semantic-release/error@4.0.0':
|
||||||
resolution: {integrity: sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==}
|
resolution: {integrity: sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
@ -2343,6 +2350,12 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
semantic-release: '>=24.1.0'
|
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':
|
'@semantic-release/github@12.0.8':
|
||||||
resolution: {integrity: sha512-tej5AAgK5X9wHRoDmYhecMXEHEkFeGOY1XsEblKxu8pIQwahzf1STYyr7iPU6Lpbg6C5I3N2w/ocXrBo+L7jhw==}
|
resolution: {integrity: sha512-tej5AAgK5X9wHRoDmYhecMXEHEkFeGOY1XsEblKxu8pIQwahzf1STYyr7iPU6Lpbg6C5I3N2w/ocXrBo+L7jhw==}
|
||||||
engines: {node: ^22.14.0 || >= 24.10.0}
|
engines: {node: ^22.14.0 || >= 24.10.0}
|
||||||
|
|
@ -3608,6 +3621,10 @@ packages:
|
||||||
resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
|
resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
|
||||||
engines: {node: '>=18.0.0'}
|
engines: {node: '>=18.0.0'}
|
||||||
|
|
||||||
|
execa@5.1.1:
|
||||||
|
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
execa@8.0.1:
|
execa@8.0.1:
|
||||||
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
|
resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==}
|
||||||
engines: {node: '>=16.17'}
|
engines: {node: '>=16.17'}
|
||||||
|
|
@ -4087,6 +4104,10 @@ packages:
|
||||||
resolution: {integrity: sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g==}
|
resolution: {integrity: sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g==}
|
||||||
engines: {node: '>= 20'}
|
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:
|
human-signals@5.0.0:
|
||||||
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
|
resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==}
|
||||||
engines: {node: '>=16.17.0'}
|
engines: {node: '>=16.17.0'}
|
||||||
|
|
@ -4467,6 +4488,9 @@ packages:
|
||||||
lodash.uniqby@4.7.0:
|
lodash.uniqby@4.7.0:
|
||||||
resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==}
|
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:
|
logform@2.7.0:
|
||||||
resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==}
|
resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
|
|
@ -4883,6 +4907,10 @@ packages:
|
||||||
resolution: {integrity: sha512-z9nC87iaZXXySbWWtTHfCFJyFvKaUAW6lODhikG7ILSbVgmwuFjUqkgnheHvAUcGedO29e2QGBRXMUD64aurqQ==}
|
resolution: {integrity: sha512-z9nC87iaZXXySbWWtTHfCFJyFvKaUAW6lODhikG7ILSbVgmwuFjUqkgnheHvAUcGedO29e2QGBRXMUD64aurqQ==}
|
||||||
engines: {node: '>=20'}
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
|
npm-run-path@4.0.1:
|
||||||
|
resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
npm-run-path@5.3.0:
|
npm-run-path@5.3.0:
|
||||||
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
|
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
|
@ -5055,6 +5083,10 @@ packages:
|
||||||
resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==}
|
resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
p-reduce@2.1.0:
|
||||||
|
resolution: {integrity: sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
p-reduce@3.0.0:
|
p-reduce@3.0.0:
|
||||||
resolution: {integrity: sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==}
|
resolution: {integrity: sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
@ -5669,6 +5701,10 @@ packages:
|
||||||
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
|
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
strip-final-newline@2.0.0:
|
||||||
|
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
strip-final-newline@3.0.0:
|
strip-final-newline@3.0.0:
|
||||||
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
|
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
@ -8530,6 +8566,8 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
'@semantic-release/error@3.0.0': {}
|
||||||
|
|
||||||
'@semantic-release/error@4.0.0': {}
|
'@semantic-release/error@4.0.0': {}
|
||||||
|
|
||||||
'@semantic-release/exec@7.1.0(semantic-release@25.0.3(typescript@6.0.3))':
|
'@semantic-release/exec@7.1.0(semantic-release@25.0.3(typescript@6.0.3))':
|
||||||
|
|
@ -8544,6 +8582,20 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- 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))':
|
'@semantic-release/github@12.0.8(semantic-release@25.0.3(typescript@6.0.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@octokit/core': 7.0.6
|
'@octokit/core': 7.0.6
|
||||||
|
|
@ -9968,6 +10020,18 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
eventsource-parser: 3.0.8
|
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:
|
execa@8.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
|
|
@ -10564,6 +10628,8 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
human-signals@2.1.0: {}
|
||||||
|
|
||||||
human-signals@5.0.0: {}
|
human-signals@5.0.0: {}
|
||||||
|
|
||||||
human-signals@8.0.1: {}
|
human-signals@8.0.1: {}
|
||||||
|
|
@ -10903,6 +10969,8 @@ snapshots:
|
||||||
|
|
||||||
lodash.uniqby@4.7.0: {}
|
lodash.uniqby@4.7.0: {}
|
||||||
|
|
||||||
|
lodash@4.18.1: {}
|
||||||
|
|
||||||
logform@2.7.0:
|
logform@2.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@colors/colors': 1.6.0
|
'@colors/colors': 1.6.0
|
||||||
|
|
@ -11589,6 +11657,10 @@ snapshots:
|
||||||
|
|
||||||
normalize-url@9.0.0: {}
|
normalize-url@9.0.0: {}
|
||||||
|
|
||||||
|
npm-run-path@4.0.1:
|
||||||
|
dependencies:
|
||||||
|
path-key: 3.1.1
|
||||||
|
|
||||||
npm-run-path@5.3.0:
|
npm-run-path@5.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key: 4.0.0
|
path-key: 4.0.0
|
||||||
|
|
@ -11732,6 +11804,8 @@ snapshots:
|
||||||
|
|
||||||
p-map@7.0.4: {}
|
p-map@7.0.4: {}
|
||||||
|
|
||||||
|
p-reduce@2.1.0: {}
|
||||||
|
|
||||||
p-reduce@3.0.0: {}
|
p-reduce@3.0.0: {}
|
||||||
|
|
||||||
p-timeout@6.1.4: {}
|
p-timeout@6.1.4: {}
|
||||||
|
|
@ -12525,6 +12599,8 @@ snapshots:
|
||||||
|
|
||||||
strip-bom@3.0.0: {}
|
strip-bom@3.0.0: {}
|
||||||
|
|
||||||
|
strip-final-newline@2.0.0: {}
|
||||||
|
|
||||||
strip-final-newline@3.0.0: {}
|
strip-final-newline@3.0.0: {}
|
||||||
|
|
||||||
strip-final-newline@4.0.0: {}
|
strip-final-newline@4.0.0: {}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
export const PUBLIC_NPM_PACKAGE_NAME = '@kaelio/ktx';
|
export const PUBLIC_NPM_PACKAGE_NAME = '@kaelio/ktx';
|
||||||
export const PUBLIC_NPM_RELEASE_TAGS = new Set(['latest', 'next']);
|
export const PUBLIC_NPM_RELEASE_TAGS = new Set(['latest', 'next']);
|
||||||
|
export const PUBLIC_NPM_BRANCH_RELEASE_TAG_PATTERN = /^branch-[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
||||||
|
|
||||||
const SEMVER_PATTERN =
|
const SEMVER_PATTERN =
|
||||||
/^(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-]+)*)?$/;
|
/^(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-]+)*)?$/;
|
||||||
|
|
@ -56,10 +57,13 @@ export function publicNpmPackageVersionToPythonVersion(version) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function assertPublicNpmReleaseTag(tag) {
|
export function assertPublicNpmReleaseTag(tag) {
|
||||||
if (!PUBLIC_NPM_RELEASE_TAGS.has(tag)) {
|
if (typeof tag !== 'string') {
|
||||||
throw new Error(`Invalid public npm release tag: ${tag}`);
|
throw new Error(`Invalid public npm release tag: ${tag}`);
|
||||||
}
|
}
|
||||||
return tag;
|
if (PUBLIC_NPM_RELEASE_TAGS.has(tag) || PUBLIC_NPM_BRANCH_RELEASE_TAG_PATTERN.test(tag)) {
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
throw new Error(`Invalid public npm release tag: ${tag}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readPublicNpmReleaseMetadata(rootDir = scriptRootDir()) {
|
export function readPublicNpmReleaseMetadata(rootDir = scriptRootDir()) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import { describe, it } from 'node:test';
|
import { describe, it } from 'node:test';
|
||||||
|
|
||||||
import { publicNpmPackageVersionToPythonVersion } from './public-npm-release-metadata.mjs';
|
import { assertPublicNpmReleaseTag, publicNpmPackageVersionToPythonVersion } from './public-npm-release-metadata.mjs';
|
||||||
|
|
||||||
describe('publicNpmPackageVersionToPythonVersion', () => {
|
describe('publicNpmPackageVersionToPythonVersion', () => {
|
||||||
it('keeps stable public npm versions unchanged for Python wheels', () => {
|
it('keeps stable public npm versions unchanged for Python wheels', () => {
|
||||||
|
|
@ -24,3 +24,22 @@ describe('publicNpmPackageVersionToPythonVersion', () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('assertPublicNpmReleaseTag', () => {
|
||||||
|
it('accepts the canonical latest and next tags', () => {
|
||||||
|
assert.equal(assertPublicNpmReleaseTag('latest'), 'latest');
|
||||||
|
assert.equal(assertPublicNpmReleaseTag('next'), 'next');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts branch-prefixed release tags produced by branch RC publishes', () => {
|
||||||
|
assert.equal(assertPublicNpmReleaseTag('branch-feature-foo'), 'branch-feature-foo');
|
||||||
|
assert.equal(assertPublicNpmReleaseTag('branch-rel-1-2-3'), 'branch-rel-1-2-3');
|
||||||
|
assert.equal(assertPublicNpmReleaseTag('branch-x'), 'branch-x');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('rejects malformed or non-string tags', () => {
|
||||||
|
for (const bad of ['', 'BRANCH-x', 'branch-', 'branch--foo', 'branch_foo', 'beta', null, undefined, 42]) {
|
||||||
|
assert.throws(() => assertPublicNpmReleaseTag(bad), /Invalid public npm release tag/);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,18 @@ function createReleaseConfig(env = process.env) {
|
||||||
'pnpm run artifacts:check',
|
'pnpm run artifacts:check',
|
||||||
'pnpm run release:readiness',
|
'pnpm run release:readiness',
|
||||||
].join(' && '),
|
].join(' && '),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'@semantic-release/git',
|
||||||
|
{
|
||||||
|
assets: ['package.json', 'release-policy.json', 'packages/cli/package.json'],
|
||||||
|
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'@semantic-release/exec',
|
||||||
|
{
|
||||||
publishCmd: [
|
publishCmd: [
|
||||||
`npm publish dist/artifacts/npm/kaelio-ktx-\${nextRelease.version}.tgz --tag ${tag} --access public --provenance`,
|
`npm publish dist/artifacts/npm/kaelio-ktx-\${nextRelease.version}.tgz --tag ${tag} --access public --provenance`,
|
||||||
'pnpm run release:published-smoke',
|
'pnpm run release:published-smoke',
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,19 @@ import { describe, it } from 'node:test';
|
||||||
const require = createRequire(import.meta.url);
|
const require = createRequire(import.meta.url);
|
||||||
const { createReleaseConfig, releaseBranches, releaseKind, releaseTag } = require('./semantic-release-config.cjs');
|
const { createReleaseConfig, releaseBranches, releaseKind, releaseTag } = require('./semantic-release-config.cjs');
|
||||||
|
|
||||||
function releaseExecOptions(config) {
|
function prepareExecOptions(config) {
|
||||||
return config.plugins.find((plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/exec' && plugin[1].prepareCmd)[1];
|
return config.plugins.find((plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/exec' && plugin[1].prepareCmd)[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function publishExecOptions(config) {
|
||||||
|
return config.plugins.find((plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/exec' && plugin[1].publishCmd)[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function gitPluginOptions(config) {
|
||||||
|
const found = config.plugins.find((plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/git');
|
||||||
|
return found ? found[1] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
function pluginNames(config) {
|
function pluginNames(config) {
|
||||||
return config.plugins.map((plugin) => (Array.isArray(plugin) ? plugin[0] : plugin));
|
return config.plugins.map((plugin) => (Array.isArray(plugin) ? plugin[0] : plugin));
|
||||||
}
|
}
|
||||||
|
|
@ -16,7 +25,7 @@ function pluginNames(config) {
|
||||||
describe('semantic-release config', () => {
|
describe('semantic-release config', () => {
|
||||||
it('configures rc releases as a prerelease on main', () => {
|
it('configures rc releases as a prerelease on main', () => {
|
||||||
assert.equal(releaseKind({ KTX_RELEASE_KIND: 'rc' }), 'rc');
|
assert.equal(releaseKind({ KTX_RELEASE_KIND: 'rc' }), 'rc');
|
||||||
assert.equal(releaseTag('rc'), 'next');
|
assert.equal(releaseTag('rc', { GITHUB_REF_NAME: 'main' }), 'next');
|
||||||
assert.deepEqual(releaseBranches({ KTX_RELEASE_KIND: 'rc', GITHUB_REF_NAME: 'main' }), [
|
assert.deepEqual(releaseBranches({ KTX_RELEASE_KIND: 'rc', GITHUB_REF_NAME: 'main' }), [
|
||||||
{ name: 'main', prerelease: 'rc', channel: 'next' },
|
{ name: 'main', prerelease: 'rc', channel: 'next' },
|
||||||
]);
|
]);
|
||||||
|
|
@ -28,14 +37,14 @@ describe('semantic-release config', () => {
|
||||||
'@semantic-release/npm must not run; the exec publishCmd publishes the pre-built tarball',
|
'@semantic-release/npm must not run; the exec publishCmd publishes the pre-built tarball',
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
releaseExecOptions(config).prepareCmd,
|
prepareExecOptions(config).prepareCmd,
|
||||||
/update-public-release-version\.mjs "\$\{nextRelease\.version\}" "next"/,
|
/update-public-release-version\.mjs "\$\{nextRelease\.version\}" "next"/,
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
releaseExecOptions(config).publishCmd,
|
publishExecOptions(config).publishCmd,
|
||||||
/^npm publish dist\/artifacts\/npm\/kaelio-ktx-\$\{nextRelease\.version\}\.tgz --tag next --access public --provenance/,
|
/^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.match(publishExecOptions(config).publishCmd, /pnpm run release:published-smoke/);
|
||||||
assert.doesNotMatch(JSON.stringify(config.plugins), /release:npm-publish/);
|
assert.doesNotMatch(JSON.stringify(config.plugins), /release:npm-publish/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -48,11 +57,11 @@ describe('semantic-release config', () => {
|
||||||
|
|
||||||
const config = createReleaseConfig({ KTX_RELEASE_KIND: 'rc', GITHUB_REF_NAME: 'feature/branch-release' });
|
const config = createReleaseConfig({ KTX_RELEASE_KIND: 'rc', GITHUB_REF_NAME: 'feature/branch-release' });
|
||||||
assert.match(
|
assert.match(
|
||||||
releaseExecOptions(config).prepareCmd,
|
prepareExecOptions(config).prepareCmd,
|
||||||
/update-public-release-version\.mjs "\$\{nextRelease\.version\}" "branch-feature-branch-release"/,
|
/update-public-release-version\.mjs "\$\{nextRelease\.version\}" "branch-feature-branch-release"/,
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
releaseExecOptions(config).publishCmd,
|
publishExecOptions(config).publishCmd,
|
||||||
/^npm publish dist\/artifacts\/npm\/kaelio-ktx-\$\{nextRelease\.version\}\.tgz --tag branch-feature-branch-release --access public --provenance/,
|
/^npm publish dist\/artifacts\/npm\/kaelio-ktx-\$\{nextRelease\.version\}\.tgz --tag branch-feature-branch-release --access public --provenance/,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
@ -64,24 +73,50 @@ describe('semantic-release config', () => {
|
||||||
|
|
||||||
const config = createReleaseConfig({ KTX_RELEASE_KIND: 'stable', GITHUB_REF_NAME: 'main' });
|
const config = createReleaseConfig({ KTX_RELEASE_KIND: 'stable', GITHUB_REF_NAME: 'main' });
|
||||||
assert.match(
|
assert.match(
|
||||||
releaseExecOptions(config).prepareCmd,
|
prepareExecOptions(config).prepareCmd,
|
||||||
/update-public-release-version\.mjs "\$\{nextRelease\.version\}" "latest"/,
|
/update-public-release-version\.mjs "\$\{nextRelease\.version\}" "latest"/,
|
||||||
);
|
);
|
||||||
assert.match(
|
assert.match(
|
||||||
releaseExecOptions(config).publishCmd,
|
publishExecOptions(config).publishCmd,
|
||||||
/^npm publish dist\/artifacts\/npm\/kaelio-ktx-\$\{nextRelease\.version\}\.tgz --tag latest --access public --provenance/,
|
/^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);
|
assert.equal(config.plugins.includes('./scripts/semantic-release-version-policy.cjs'), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('never commits release files back to the repo', () => {
|
it('commits release version files back to the branch via @semantic-release/git', () => {
|
||||||
for (const kind of ['rc', 'stable']) {
|
for (const kind of ['rc', 'stable']) {
|
||||||
const config = createReleaseConfig({ KTX_RELEASE_KIND: kind, GITHUB_REF_NAME: 'main' });
|
const config = createReleaseConfig({ KTX_RELEASE_KIND: kind, GITHUB_REF_NAME: 'main' });
|
||||||
assert.equal(pluginNames(config).includes('@semantic-release/git'), false, `${kind}: @semantic-release/git`);
|
const git = gitPluginOptions(config);
|
||||||
|
assert.ok(git, `${kind}: @semantic-release/git plugin must be configured`);
|
||||||
|
assert.deepEqual(git.assets, ['package.json', 'release-policy.json', 'packages/cli/package.json']);
|
||||||
|
assert.match(git.message, /^chore\(release\): \$\{nextRelease\.version\} \[skip ci\]/);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps @semantic-release/npm and @semantic-release/changelog out of the plugin chain', () => {
|
||||||
|
for (const kind of ['rc', 'stable']) {
|
||||||
|
const config = createReleaseConfig({ KTX_RELEASE_KIND: kind, GITHUB_REF_NAME: 'main' });
|
||||||
|
assert.equal(pluginNames(config).includes('@semantic-release/npm'), false, `${kind}: @semantic-release/npm`);
|
||||||
assert.equal(pluginNames(config).includes('@semantic-release/changelog'), false, `${kind}: @semantic-release/changelog`);
|
assert.equal(pluginNames(config).includes('@semantic-release/changelog'), false, `${kind}: @semantic-release/changelog`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('orders the prepare exec before @semantic-release/git before the publish exec', () => {
|
||||||
|
const config = createReleaseConfig({ KTX_RELEASE_KIND: 'stable', GITHUB_REF_NAME: 'main' });
|
||||||
|
const prepareIndex = config.plugins.findIndex(
|
||||||
|
(plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/exec' && plugin[1].prepareCmd,
|
||||||
|
);
|
||||||
|
const gitIndex = config.plugins.findIndex(
|
||||||
|
(plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/git',
|
||||||
|
);
|
||||||
|
const publishIndex = config.plugins.findIndex(
|
||||||
|
(plugin) => Array.isArray(plugin) && plugin[0] === '@semantic-release/exec' && plugin[1].publishCmd,
|
||||||
|
);
|
||||||
|
assert.ok(prepareIndex !== -1 && gitIndex !== -1 && publishIndex !== -1);
|
||||||
|
assert.ok(prepareIndex < gitIndex, 'prepare exec must run before @semantic-release/git');
|
||||||
|
assert.ok(gitIndex < publishIndex, '@semantic-release/git must run before the publish exec');
|
||||||
|
});
|
||||||
|
|
||||||
it('produces a loadable config regardless of GITHUB_REF_NAME', () => {
|
it('produces a loadable config regardless of GITHUB_REF_NAME', () => {
|
||||||
// Knip and other tooling load .releaserc.cjs on PR runners where
|
// Knip and other tooling load .releaserc.cjs on PR runners where
|
||||||
// GITHUB_REF_NAME is the merge ref. semantic-release itself enforces the
|
// GITHUB_REF_NAME is the merge ref. semantic-release itself enforces the
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,11 @@ export async function updatePublicReleaseVersion(rootDir, version, tag) {
|
||||||
packageJson.version = safeVersion;
|
packageJson.version = safeVersion;
|
||||||
await writeJson(packageJsonPath, packageJson);
|
await writeJson(packageJsonPath, packageJson);
|
||||||
|
|
||||||
|
const cliPackageJsonPath = join(rootDir, 'packages', 'cli', 'package.json');
|
||||||
|
const cliPackageJson = await readJson(cliPackageJsonPath);
|
||||||
|
cliPackageJson.version = safeVersion;
|
||||||
|
await writeJson(cliPackageJsonPath, cliPackageJson);
|
||||||
|
|
||||||
const policyPath = releasePolicyPath(rootDir);
|
const policyPath = releasePolicyPath(rootDir);
|
||||||
const policy = await readJson(policyPath);
|
const policy = await readJson(policyPath);
|
||||||
policy.publicNpmPackageVersion = safeVersion;
|
policy.publicNpmPackageVersion = safeVersion;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,11 @@ async function writeReleaseFixture(root) {
|
||||||
version: '0.0.0-private',
|
version: '0.0.0-private',
|
||||||
private: true,
|
private: true,
|
||||||
});
|
});
|
||||||
|
await writeJson(join(root, 'packages', 'cli', 'package.json'), {
|
||||||
|
name: '@ktx/cli',
|
||||||
|
version: '0.0.0-private',
|
||||||
|
private: true,
|
||||||
|
});
|
||||||
await writeJson(join(root, 'release-policy.json'), {
|
await writeJson(join(root, 'release-policy.json'), {
|
||||||
schemaVersion: 1,
|
schemaVersion: 1,
|
||||||
publicNpmPackageVersion: '0.1.0-rc.1',
|
publicNpmPackageVersion: '0.1.0-rc.1',
|
||||||
|
|
@ -60,6 +65,7 @@ describe('updatePublicReleaseVersion', () => {
|
||||||
await updatePublicReleaseVersion(root, '0.1.0-rc.2', 'next');
|
await updatePublicReleaseVersion(root, '0.1.0-rc.2', 'next');
|
||||||
|
|
||||||
assert.equal((await readJson(join(root, 'package.json'))).version, '0.1.0-rc.2');
|
assert.equal((await readJson(join(root, 'package.json'))).version, '0.1.0-rc.2');
|
||||||
|
assert.equal((await readJson(join(root, 'packages', 'cli', 'package.json'))).version, '0.1.0-rc.2');
|
||||||
assert.deepEqual(await readJson(join(root, 'release-policy.json')), {
|
assert.deepEqual(await readJson(join(root, 'release-policy.json')), {
|
||||||
schemaVersion: 1,
|
schemaVersion: 1,
|
||||||
publicNpmPackageVersion: '0.1.0-rc.2',
|
publicNpmPackageVersion: '0.1.0-rc.2',
|
||||||
|
|
@ -93,6 +99,26 @@ describe('updatePublicReleaseVersion', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('accepts branch-prefixed npm release tags produced by branch RC publishes', async () => {
|
||||||
|
const root = await mkdtemp(join(tmpdir(), 'ktx-release-version-branch-test-'));
|
||||||
|
try {
|
||||||
|
await writeReleaseFixture(root);
|
||||||
|
|
||||||
|
await updatePublicReleaseVersion(root, '0.1.0-feature-foo.0', 'branch-feature-foo');
|
||||||
|
|
||||||
|
assert.equal((await readJson(join(root, 'package.json'))).version, '0.1.0-feature-foo.0');
|
||||||
|
assert.equal(
|
||||||
|
(await readJson(join(root, 'packages', 'cli', 'package.json'))).version,
|
||||||
|
'0.1.0-feature-foo.0',
|
||||||
|
);
|
||||||
|
const policy = await readJson(join(root, 'release-policy.json'));
|
||||||
|
assert.equal(policy.publicNpmPackageVersion, '0.1.0-feature-foo.0');
|
||||||
|
assert.equal(policy.npm.tag, 'branch-feature-foo');
|
||||||
|
} finally {
|
||||||
|
await rm(root, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('rejects invalid versions and tags', async () => {
|
it('rejects invalid versions and tags', async () => {
|
||||||
const root = await mkdtemp(join(tmpdir(), 'ktx-release-version-invalid-test-'));
|
const root = await mkdtemp(join(tmpdir(), 'ktx-release-version-invalid-test-'));
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue