fix: allow multiple branches with same channel
This commit is contained in:
parent
20e7a38cdb
commit
63f51ae6dd
@ -48,8 +48,10 @@ For example the configuration `['+([0-9])?(.{+([0-9]),x}).x', 'master', 'next']`
|
|||||||
|
|
||||||
### channel
|
### channel
|
||||||
|
|
||||||
The `channel` can be defined for any branch type. If it's not defined, releases will be done on the default distribution channel (for example the `@latest` [dist-tag](https://docs.npmjs.com/cli/dist-tag) for npm).
|
The `channel` can be defined for any branch type. By default releases will be done on the default distribution channel (for example the `@latest` [dist-tag](https://docs.npmjs.com/cli/dist-tag) for npm) for the first [release branch](#release-branches) and on a distribution channel named based on the branch `name` for any other branch.
|
||||||
The value of `channel`, if defined, is generated with [Lodash template](https://lodash.com/docs#template) with the variable `name` available.
|
If the `channel` property is set to `false` the default channel will be used.
|
||||||
|
|
||||||
|
The value of `channel`, if defined as a string, is generated with [Lodash template](https://lodash.com/docs#template) with the variable `name` available.
|
||||||
|
|
||||||
For example the configuration `['master', {name: 'next', channel: 'channel-${name}'}]` will be expanded as:
|
For example the configuration `['master', {name: 'next', channel: 'channel-${name}'}]` will be expanded as:
|
||||||
```js
|
```js
|
||||||
@ -78,7 +80,7 @@ For example the configuration `['1.1.x', '1.2.x', 'master']` will be expanded as
|
|||||||
|
|
||||||
### prerelease
|
### prerelease
|
||||||
|
|
||||||
A `prerelease` property applies only to pre-release branches, is required and The `prerelease` value must be valid per the [Semantic Versioning Specification](https://semver.org/#spec-item-9). It will determine the name of versions (for example if `prerelease` is set to `beta` the version be formatted like `2.0.0-beta.1`, `2.0.0-beta.2` etc...).
|
A `prerelease` property applies only to pre-release branches and the `prerelease` value must be valid per the [Semantic Versioning Specification](https://semver.org/#spec-item-9). It will determine the name of versions (for example if `prerelease` is set to `beta` the version be formatted like `2.0.0-beta.1`, `2.0.0-beta.2` etc...).
|
||||||
If the `prerelease` property is set to `true` the `name` value will be used.
|
If the `prerelease` property is set to `true` the `name` value will be used.
|
||||||
|
|
||||||
The value of `prerelease`, if defined as a string, is generated with [Lodash template](https://lodash.com/docs#template) with the variable `name` available.
|
The value of `prerelease`, if defined as a string, is generated with [Lodash template](https://lodash.com/docs#template) with the variable `name` available.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const {isUndefined} = require('lodash');
|
const {isUndefined} = require('lodash');
|
||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
const {makeTag} = require('./utils');
|
const {makeTag, isSameChannel} = require('./utils');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last release.
|
* Last release.
|
||||||
@ -28,7 +28,10 @@ const {makeTag} = require('./utils');
|
|||||||
*/
|
*/
|
||||||
module.exports = ({branch, options: {tagFormat}}, {before} = {}) => {
|
module.exports = ({branch, options: {tagFormat}}, {before} = {}) => {
|
||||||
const [{version, gitTag, channel} = {}] = branch.tags
|
const [{version, gitTag, channel} = {}] = branch.tags
|
||||||
.filter(tag => (branch.type === 'prerelease' && branch.channel === tag.channel) || !semver.prerelease(tag.version))
|
.filter(
|
||||||
|
tag =>
|
||||||
|
(branch.type === 'prerelease' && isSameChannel(branch.channel, tag.channel)) || !semver.prerelease(tag.version)
|
||||||
|
)
|
||||||
.filter(tag => isUndefined(before) || semver.lt(tag.version, before))
|
.filter(tag => isUndefined(before) || semver.lt(tag.version, before))
|
||||||
.sort((a, b) => semver.rcompare(a.version, b.version));
|
.sort((a, b) => semver.rcompare(a.version, b.version));
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
const semver = require('semver');
|
const semver = require('semver');
|
||||||
const {FIRST_RELEASE, FIRSTPRERELEASE} = require('./definitions/constants');
|
const {FIRST_RELEASE, FIRSTPRERELEASE} = require('./definitions/constants');
|
||||||
|
const {isSameChannel} = require('./utils');
|
||||||
|
|
||||||
module.exports = ({branch, nextRelease: {type, channel}, lastRelease, logger}) => {
|
module.exports = ({branch, nextRelease: {type, channel}, lastRelease, logger}) => {
|
||||||
let version;
|
let version;
|
||||||
@ -7,7 +8,7 @@ module.exports = ({branch, nextRelease: {type, channel}, lastRelease, logger}) =
|
|||||||
const {major, minor, patch} = semver.parse(lastRelease.version);
|
const {major, minor, patch} = semver.parse(lastRelease.version);
|
||||||
version =
|
version =
|
||||||
branch.type === 'prerelease'
|
branch.type === 'prerelease'
|
||||||
? semver.prerelease(lastRelease.version) && lastRelease.channel === channel
|
? semver.prerelease(lastRelease.version) && isSameChannel(lastRelease.channel, channel)
|
||||||
? semver.inc(lastRelease.version, 'prerelease')
|
? semver.inc(lastRelease.version, 'prerelease')
|
||||||
: `${semver.inc(`${major}.${minor}.${patch}`, type)}-${branch.prerelease}.${FIRSTPRERELEASE}`
|
: `${semver.inc(`${major}.${minor}.${patch}`, type)}-${branch.prerelease}.${FIRSTPRERELEASE}`
|
||||||
: semver.inc(lastRelease.version, type);
|
: semver.inc(lastRelease.version, type);
|
||||||
|
@ -71,6 +71,10 @@ function makeTag(tagFormat, version, channel) {
|
|||||||
return template(tagFormat)({version: `${version}${channel ? `@${channel}` : ''}`});
|
return template(tagFormat)({version: `${version}${channel ? `@${channel}` : ''}`});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSameChannel(channel, otherChannel) {
|
||||||
|
return channel === otherChannel || (!channel && !otherChannel);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extractErrors,
|
extractErrors,
|
||||||
hideSensitiveValues,
|
hideSensitiveValues,
|
||||||
@ -86,4 +90,5 @@ module.exports = {
|
|||||||
getFirstVersion,
|
getFirstVersion,
|
||||||
getRange,
|
getRange,
|
||||||
makeTag,
|
makeTag,
|
||||||
|
isSameChannel,
|
||||||
};
|
};
|
||||||
|
@ -581,6 +581,117 @@ test('Publish a pre-release version', async t => {
|
|||||||
t.is(releases[0].gitTag, 'v1.1.0-beta.2@beta');
|
t.is(releases[0].gitTag, 'v1.1.0-beta.2@beta');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Publish releases from different branch on the same channel', async t => {
|
||||||
|
const {cwd, repositoryUrl} = await gitRepo(true);
|
||||||
|
await gitCommits(['feat: initial commit'], {cwd});
|
||||||
|
await gitTagVersion('v1.0.0', undefined, {cwd});
|
||||||
|
await gitPush(repositoryUrl, 'master', {cwd});
|
||||||
|
await gitCheckout('next-major', true, {cwd});
|
||||||
|
await gitPush(repositoryUrl, 'next-major', {cwd});
|
||||||
|
await gitCheckout('next', true, {cwd});
|
||||||
|
await gitCommits(['feat: a feature'], {cwd});
|
||||||
|
await gitPush(repositoryUrl, 'next', {cwd});
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
branches: ['master', {name: 'next', channel: false}, {name: 'next-major', channel: false}],
|
||||||
|
repositoryUrl,
|
||||||
|
};
|
||||||
|
const addChannel = stub().resolves({});
|
||||||
|
const options = {
|
||||||
|
...config,
|
||||||
|
verifyConditions: stub().resolves(),
|
||||||
|
verifyRelease: stub().resolves(),
|
||||||
|
generateNotes: stub().resolves(''),
|
||||||
|
addChannel,
|
||||||
|
prepare: stub().resolves(),
|
||||||
|
publish: stub().resolves(),
|
||||||
|
success: stub().resolves(),
|
||||||
|
fail: stub().resolves(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let semanticRelease = requireNoCache('..', {
|
||||||
|
'./lib/get-logger': () => t.context.logger,
|
||||||
|
'env-ci': () => ({isCi: true, branch: 'next', isPr: false}),
|
||||||
|
});
|
||||||
|
let {releases} = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}});
|
||||||
|
|
||||||
|
t.is(releases.length, 1);
|
||||||
|
t.is(releases[0].version, '1.1.0');
|
||||||
|
t.is(releases[0].gitTag, 'v1.1.0');
|
||||||
|
|
||||||
|
await gitCommits(['fix: a fix'], {cwd});
|
||||||
|
({releases} = await semanticRelease(options, {
|
||||||
|
cwd,
|
||||||
|
env: {},
|
||||||
|
stdout: {write: () => {}},
|
||||||
|
stderr: {write: () => {}},
|
||||||
|
}));
|
||||||
|
|
||||||
|
t.is(releases.length, 1);
|
||||||
|
t.is(releases[0].version, '1.1.1');
|
||||||
|
t.is(releases[0].gitTag, 'v1.1.1');
|
||||||
|
|
||||||
|
await gitCheckout('master', false, {cwd});
|
||||||
|
await merge('next', {cwd});
|
||||||
|
await gitPush('origin', 'master', {cwd});
|
||||||
|
|
||||||
|
semanticRelease = requireNoCache('..', {
|
||||||
|
'./lib/get-logger': () => t.context.logger,
|
||||||
|
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||||
|
});
|
||||||
|
|
||||||
|
t.falsy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}));
|
||||||
|
t.is(addChannel.callCount, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Publish pre-releases the same channel as regular releases', async t => {
|
||||||
|
const {cwd, repositoryUrl} = await gitRepo(true);
|
||||||
|
await gitCommits(['feat: initial commit'], {cwd});
|
||||||
|
await gitTagVersion('v1.0.0', undefined, {cwd});
|
||||||
|
await gitPush(repositoryUrl, 'master', {cwd});
|
||||||
|
await gitCheckout('beta', true, {cwd});
|
||||||
|
await gitCommits(['feat: a feature'], {cwd});
|
||||||
|
await gitPush(repositoryUrl, 'beta', {cwd});
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
branches: ['master', {name: 'beta', channel: false, prerelease: true}],
|
||||||
|
repositoryUrl,
|
||||||
|
};
|
||||||
|
const options = {
|
||||||
|
...config,
|
||||||
|
verifyConditions: stub().resolves(),
|
||||||
|
verifyRelease: stub().resolves(),
|
||||||
|
generateNotes: stub().resolves(''),
|
||||||
|
addChannel: false,
|
||||||
|
prepare: stub().resolves(),
|
||||||
|
publish: stub().resolves(),
|
||||||
|
success: stub().resolves(),
|
||||||
|
fail: stub().resolves(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const semanticRelease = requireNoCache('..', {
|
||||||
|
'./lib/get-logger': () => t.context.logger,
|
||||||
|
'env-ci': () => ({isCi: true, branch: 'beta', isPr: false}),
|
||||||
|
});
|
||||||
|
let {releases} = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}});
|
||||||
|
|
||||||
|
t.is(releases.length, 1);
|
||||||
|
t.is(releases[0].version, '1.1.0-beta.1');
|
||||||
|
t.is(releases[0].gitTag, 'v1.1.0-beta.1');
|
||||||
|
|
||||||
|
await gitCommits(['fix: a fix'], {cwd});
|
||||||
|
({releases} = await semanticRelease(options, {
|
||||||
|
cwd,
|
||||||
|
env: {},
|
||||||
|
stdout: {write: () => {}},
|
||||||
|
stderr: {write: () => {}},
|
||||||
|
}));
|
||||||
|
|
||||||
|
t.is(releases.length, 1);
|
||||||
|
t.is(releases[0].version, '1.1.0-beta.2');
|
||||||
|
t.is(releases[0].gitTag, 'v1.1.0-beta.2');
|
||||||
|
});
|
||||||
|
|
||||||
test('Do not add pre-releases to a different channel', async t => {
|
test('Do not add pre-releases to a different channel', async t => {
|
||||||
const {cwd, repositoryUrl} = await gitRepo(true);
|
const {cwd, repositoryUrl} = await gitRepo(true);
|
||||||
const commits = await gitCommits(['feat: initial release'], {cwd});
|
const commits = await gitCommits(['feat: initial release'], {cwd});
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
getFirstVersion,
|
getFirstVersion,
|
||||||
getRange,
|
getRange,
|
||||||
makeTag,
|
makeTag,
|
||||||
|
isSameChannel,
|
||||||
} from '../lib/utils';
|
} from '../lib/utils';
|
||||||
|
|
||||||
test('extractErrors', t => {
|
test('extractErrors', t => {
|
||||||
@ -178,3 +179,12 @@ test('makeTag', t => {
|
|||||||
t.is(makeTag(`v\${version}`, '1.0.0', 'next'), 'v1.0.0@next');
|
t.is(makeTag(`v\${version}`, '1.0.0', 'next'), 'v1.0.0@next');
|
||||||
t.is(makeTag(`v\${version}@test`, '1.0.0', 'next'), 'v1.0.0@next@test');
|
t.is(makeTag(`v\${version}@test`, '1.0.0', 'next'), 'v1.0.0@next@test');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('isSameChannel', t => {
|
||||||
|
t.true(isSameChannel('next', 'next'));
|
||||||
|
t.true(isSameChannel(null, undefined));
|
||||||
|
t.true(isSameChannel(false, undefined));
|
||||||
|
t.true(isSameChannel('', false));
|
||||||
|
|
||||||
|
t.false(isSameChannel('next', false));
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user