feat: support multiple branches and distribution channels

- Allow to configure multiple branches to release from
- Allow to define a distribution channel associated with each branch
- Manage the availability on distribution channels based on git merges
- Support regular releases, maintenance releases and pre-releases
- Add the `addChannel` plugin step to make an existing release available on a different distribution channel

BREAKING CHANGE: the `branch` option has been removed in favor of `branches`

The new `branches` option expect either an Array or a single branch definition. To migrate your configuration:
- If you want to publish package from multiple branches, please the configuration documentation
- If you use the default configuration and want to publish only from `master`: nothing to change
- If you use the `branch` configuration and want to publish only from one branch: replace `branch` by `branches` (`"branch": "my-release-branch"` => `"branches": "my-release-branch"`)
This commit is contained in:
Pierre Vanduynslager
2018-11-29 14:13:03 -05:00
parent 7a9922a492
commit 7b4052470b
50 changed files with 4069 additions and 516 deletions
+14 -26
View File
@@ -1,8 +1,6 @@
const {escapeRegExp, template} = require('lodash');
const {isUndefined} = require('lodash');
const semver = require('semver');
const pLocate = require('p-locate');
const debug = require('debug')('semantic-release:get-last-release');
const {getTags, isRefInHistory, getTagHead} = require('./git');
const {makeTag} = require('./utils');
/**
* Last release.
@@ -15,37 +13,27 @@ const {getTags, isRefInHistory, getTagHead} = require('./git');
/**
* Determine the Git tag and version of the last tagged release.
*
* - Obtain all the tags referencing commits in the current branch history
* - Filter out the ones that are not valid semantic version or doesn't match the `tagFormat`
* - Filter out the branch tags that are not valid semantic version
* - Sort the versions
* - Retrive the highest version
*
* @param {Object} context semantic-release context.
* @param {Object} params Function parameters.
* @param {Object} params.before Find only releases with version number lower than this version.
*
* @return {Promise<LastRelease>} The last tagged release or `undefined` if none is found.
* @return {LastRelease} The last tagged release or empty object if none is found.
*/
module.exports = async ({cwd, env, options: {tagFormat}, logger}) => {
// Generate a regex to parse tags formatted with `tagFormat`
// by replacing the `version` variable in the template by `(.+)`.
// The `tagFormat` is compiled with space as the `version` as it's an invalid tag character,
// so it's guaranteed to no be present in the `tagFormat`.
const tagRegexp = `^${escapeRegExp(template(tagFormat)({version: ' '})).replace(' ', '(.+)')}`;
const tags = (await getTags({cwd, env}))
.map(tag => ({gitTag: tag, version: (tag.match(tagRegexp) || new Array(2))[1]}))
.filter(
tag => tag.version && semver.valid(semver.clean(tag.version)) && !semver.prerelease(semver.clean(tag.version))
)
module.exports = ({branch: {name, tags, type}, options: {tagFormat}, logger}, {before} = {}) => {
const [{version, gitTag, gitHead, channel} = {}] = tags
.filter(tag => type === 'prerelease' || !semver.prerelease(tag.version))
.filter(tag => isUndefined(before) || semver.lt(tag.version, before))
.sort((a, b) => semver.rcompare(a.version, b.version));
debug('found tags: %o', tags);
const tag = await pLocate(tags, tag => isRefInHistory(tag.gitTag, {cwd, env}), {preserveOrder: true});
if (tag) {
logger.log(`Found git tag ${tag.gitTag} associated with version ${tag.version}`);
return {gitHead: await getTagHead(tag.gitTag, {cwd, env}), ...tag};
if (gitTag) {
logger.log(`Found git tag ${gitTag} associated with version ${version} on branch ${name}`);
return {version, gitTag, gitHead, channel, name: makeTag(tagFormat, version)};
}
logger.log('No git tag version found');
logger.log(`No git tag version found on branch ${name}`);
return {};
};