fix: prevent stable release pushes to main (#145)

This commit is contained in:
Andrey Avtomonov 2026-05-19 16:01:07 +02:00 committed by GitHub
parent 7110aa6f5c
commit 03e2f9f0a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 51 additions and 12 deletions

View file

@ -90,6 +90,26 @@ 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);
@ -138,7 +158,7 @@ function createReleaseConfig(env = process.env) {
},
],
'./scripts/semantic-release-version-policy.cjs',
'@semantic-release/changelog',
...releaseChangelogPlugins(kind),
[
'@semantic-release/exec',
{
@ -153,13 +173,7 @@ function createReleaseConfig(env = process.env) {
].join(' && '),
},
],
[
'@semantic-release/git',
{
assets: ['CHANGELOG.md', 'package.json', 'release-policy.json'],
message: 'chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}',
},
],
...releaseGitPlugins(kind),
[
'@semantic-release/github',
{

View file

@ -9,6 +9,14 @@ 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', () => {
assert.equal(releaseKind({ KTX_RELEASE_KIND: 'rc' }), 'rc');
@ -23,6 +31,14 @@ describe('semantic-release config', () => {
releaseExecOptions(config).prepareCmd,
/update-public-release-version\.mjs "\$\{nextRelease\.version\}" "next"/,
);
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', () => {
@ -38,6 +54,13 @@ describe('semantic-release config', () => {
assert.ok(config.plugins.includes('./scripts/semantic-release-version-policy.cjs'));
});
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('rejects stable releases from non-main branches', () => {
assert.throws(
() => releaseBranches({ KTX_RELEASE_KIND: 'stable', GITHUB_REF_NAME: 'feature/release-test' }),