Compare commits

..
Author SHA1 Message Date
Pierre Vanduynslager 0457a074e7 fix: correctly determine next pre-release version 2019-01-07 18:22:41 -05:00
Pierre Vanduynslager 1d8c35d889 docs: update FAQ regarding initial release version 2018-12-31 03:35:32 -05:00
Pierre Vanduynslager 0d91027e9f docs: update release triggering section in README 2018-12-31 03:35:32 -05:00
Pierre Vanduynslager 2144f2064f docs: add missing recipes link in README 2018-12-31 03:35:32 -05:00
Pierre Vanduynslager d55fda3306 fix(pacjage): update @semantic-release/github and @semantic-release/npm 2018-12-27 15:42:15 -05:00
greenkeeper[bot]andPierre Vanduynslager ba00e16f43 chore(package): update ava to version 1.0.1 2018-12-27 15:04:57 -05:00
greenkeeper[bot]andPierre Vanduynslager 5d6fd7c1cd fix(package): update aggregate-error to version 2.0.0 2018-12-27 15:04:57 -05:00
Pierre Vanduynslager f96c660c1b fix: harmonize parameters passed to getError 2018-12-18 18:02:02 -05:00
Pierre Vanduynslager 4aad9cd490 fix: do not call addChannelfor 2 merged branches configured with the same channel 2018-12-18 02:18:19 -05:00
Pierre Vanduynslager 390e966341 fix(package): update @semantic-release/npm to version 5.2.0-beta.3 2018-12-17 15:23:04 -05:00
Pierre Vanduynslager c1c96a87a3 fix(package): update @semantic-release/github to version 5.3.0-beta.5 2018-12-17 15:23:04 -05:00
Pierre Vanduynslager 725780bf0a fix(package): update @semantic-release/commit-analyzer to version 7.0.0-beta.2 2018-12-17 15:23:04 -05:00
Pierre Vanduynslager 9a023b4088 fix: call success plugin only once for releases added to a channel 2018-12-17 15:23:04 -05:00
Pierre Vanduynslager c22ae17a9b fix: on maintenance branch add to channel only version >= to start range 2018-12-17 15:23:04 -05:00
Pierre Vanduynslager 162b4b9e3b fix: remove confusing logs when searching for releases to add to a channel 2018-12-17 15:23:04 -05:00
24 changed files with 301 additions and 197 deletions
+7 -4
View File
@@ -77,11 +77,12 @@ Here is an example of the release type that will be done based on a commit messa
### Triggering a release
For each new commits added to the release branch (i.e. `master`) with `git push` or by merging a pull request or merging from another branch, a CI build is triggered and runs the `semantic-release` command to make a release if there are codebase changes since the last release that affect the package functionalities.
For each new commits added to one of the release branches (for example `master`, `next`, `beta`), with `git push` or by merging a pull request or merging from another branch, a CI build is triggered and runs the `semantic-release` command to make a release if there are codebase changes since the last release that affect the package functionalities.
If you need more control over the timing of releases you have a couple of options:
- Publish releases on a distribution channel (for example npm’s [dist-tags](https://docs.npmjs.com/cli/dist-tag)). This way you can keep control over what your users end up using by default, and you can decide when to make an automatically released version available to the stable channel, and promote it.
- Develop on a `dev` branch and merge it to the release branch (i.e. `master`) once you are ready to publish. **semantic-release** will run only on pushes to the release branch.
**semantic-release** offers various ways to control the timing, the content and the audience of published releases. See example workflows in the following recipes:
- [Using distribution channels](docs/recipes/distribution-channels.md#publishing-on-distribution-channels)
- [Maintenance releases](docs/recipes/maintenance-releases.md#publishing-maintenance-releases)
- [Pre-releases](docs/recipes/pre-releases.md#publishing-pre-releases)
### Release steps
@@ -113,6 +114,8 @@ After running the tests, the command `semantic-release` will execute the followi
- [Shareable configuration](docs/extending/shareable-configurations-list.md)
- Recipes
- [CI configurations](docs/recipes/README.md)
- [Git hosted services](docs/recipes/README.md)
- [Release workflow](docs/recipes/README.md)
- [Package managers and languages](docs/recipes/README.md)
- Developer guide
- [JavaScript API](docs/developer-guide/js-api.md)
+1 -1
View File
@@ -222,7 +222,7 @@ If you need more control over the timing of releases, see [Triggering a release]
This is not supported by **semantic-release** as it's not considered a good practice, mostly because [Semantic Versioning](https://semver.org) rules applies differently to major version zero.
In early development phase when your package is not ready for production yet we recommend to publish releases on a distribution channel (for example npm’s [dist-tags](https://docs.npmjs.com/cli/dist-tag)) or to develop on a `dev` branch and merge it to `master` periodically. See [Triggering a release](../../README.md#triggering-a-release) for more details on those solutions.
If your project is under heavy development, with frequent breaking changes, and is not production ready yet we recommend [publishing pre-releases](../recipes/pre-releases.md#publishing-pre-releases).
See [“Introduction to SemVer” - Irina Gebauer](https://blog.greenkeeper.io/introduction-to-semver-d272990c44f2) for more details on [Semantic Versioning](https://semver.org) and the recommendation to start at version `1.0.0`.
+6 -6
View File
@@ -20,12 +20,12 @@ The type of the branch is automatically determined based on naming convention an
## Branches properties
| Property | Branch type | Description | Default |
|--------------|-------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
| `name` | All | **Required.** The Git branch holding the commits to analyze and the code to release. See [name](#name). | - The value itself if defined as a `String` or the matching branches name if defined as a glob. |
| `channel` | All | The distribution channel on which to publish releases from this branch. See [channel](#channel). | `undefined` for the first release branch, the value of `name` for subsequent ones. |
| `range` | [maintenance](#maintenance-branches) only | **Required unless `name` is formatted like `N.N.x` or `N.x` (`N` is a number).** The range of [semantic versions](https://semver.org) to support on this branch. See [range](#range). | The value of `name`. |
| `prerelease` | [pre-release](#pre-release-branches) only | **Required.** The pre-release detonation to append to [semantic versions](https://semver.org) released from this branch. See [prerelease](#prerelease). | - |
| Property | Branch type | Description | Default |
|--------------|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
| `name` | All | **Required.** The Git branch holding the commits to analyze and the code to release. See [name](#name). | - The value itself if defined as a `String` or the matching branches name if defined as a glob. |
| `channel` | All | The distribution channel on which to publish releases from this branch. Set to `false` to force the default distribution channel instead of using the default. See [channel](#channel). | `undefined` for the first release branch, the value of `name` for subsequent ones. |
| `range` | [maintenance](#maintenance-branches) only | **Required unless `name` is formatted like `N.N.x` or `N.x` (`N` is a number).** The range of [semantic versions](https://semver.org) to support on this branch. See [range](#range). | The value of `name`. |
| `prerelease` | [pre-release](#pre-release-branches) only | **Required.** The pre-release detonation to append to [semantic versions](https://semver.org) released from this branch. See [prerelease](#prerelease). | - |
### name
+16 -5
View File
@@ -86,7 +86,7 @@ async function run(context, plugins) {
}
} catch (error) {
logger.error(`The command "${error.cmd}" failed with the error message ${error.stderr}.`);
throw getError('EGITNOPERMISSION', {options});
throw getError('EGITNOPERMISSION', context);
}
logger.success(`Allowed to push to the Git repository`);
@@ -98,8 +98,8 @@ async function run(context, plugins) {
context.releases = [];
await pEachSeries(releasesToAdd, async ({lastRelease, currentRelease, nextRelease}) => {
if (context.branch['merge-range'] && !semver.satisfies(nextRelease.version, context.branch['merge-range'])) {
errors.push(getError('EINVALIDMAINTENANCEMERGE', {nextRelease, branch: context.branch}));
if (context.branch.mergeRange && !semver.satisfies(nextRelease.version, context.branch.mergeRange)) {
errors.push(getError('EINVALIDMAINTENANCEMERGE', {...context, nextRelease}));
return;
}
@@ -127,6 +127,16 @@ async function run(context, plugins) {
context.lastRelease = await getLastRelease(context);
if (context.lastRelease.gitTag) {
logger.log(
`Found git tag ${context.lastRelease.gitTag} associated with version ${context.lastRelease.version} on branch ${
context.branch.name
}`
);
} else {
logger.log(`No git tag version found on branch ${context.branch.name}`);
}
context.commits = await getCommits(context);
const nextRelease = {
@@ -168,9 +178,10 @@ async function run(context, plugins) {
logger.success(`Created tag ${nextRelease.gitTag}`);
}
context.releases.push(...(await plugins.publish(context)));
const releases = await plugins.publish(context);
context.releases.push(...releases);
await plugins.success(context);
await plugins.success({...context, releases});
logger.success(`Published release ${nextRelease.version}`);
+5 -5
View File
@@ -1,4 +1,4 @@
const {sortBy} = require('lodash');
const {sortBy, isNil} = require('lodash');
const semver = require('semver');
const semverDiff = require('semver-diff');
const {FIRST_RELEASE, RELEASE_TYPE} = require('../definitions/constants');
@@ -20,7 +20,7 @@ function maintenance({maintenance, release}) {
...rest,
name,
range: range || name,
channel: channel || name,
channel: isNil(channel) ? name : channel,
})),
'range'
).map(({name, range, tags, ...rest}, idx, branches) => {
@@ -51,7 +51,7 @@ function maintenance({maintenance, release}) {
tags,
range: getRange(min, max),
accept: diff ? RELEASE_TYPE.slice(0, RELEASE_TYPE.indexOf(diff)) : [],
'merge-range': getRange(maintenanceMin, getUpperBound(range)),
mergeRange: getRange(maintenanceMin, getUpperBound(range)),
};
});
}
@@ -83,7 +83,7 @@ function release({release}) {
const diff = bound ? semverDiff(min, bound) : null;
return {
...rest,
channel: idx === 0 ? channel : channel || name,
channel: idx === 0 ? channel : isNil(channel) ? name : channel,
tags,
type: 'release',
name,
@@ -98,7 +98,7 @@ function prerelease({prerelease}) {
const preid = prerelease === true ? name : prerelease;
return {
...rest,
channel: channel || name,
channel: isNil(channel) ? name : channel,
type: 'prerelease',
name,
prerelease: preid,
+12 -28
View File
@@ -29,11 +29,9 @@ Please make sure to add the \`repositoryUrl\` to the [semantic-release configura
'docs/usage/configuration.md'
)}).`,
}),
EGITNOPERMISSION: ({options}) => ({
EGITNOPERMISSION: ({options: {repositoryUrl}, branch: {name}}) => ({
message: 'The push permission to the Git repository is required.',
details: `**semantic-release** cannot push the version tag to the branch \`${
options.branch
}\` on remote Git repository with URL \`${options.repositoryUrl}\`.
details: `**semantic-release** cannot push the version tag to the branch \`${name}\` on remote Git repository with URL \`${repositoryUrl}\`.
Please refer to the [authentication configuration documentation](${linkify(
'docs/usage/ci-configuration.md#authentication'
@@ -41,7 +39,7 @@ Please refer to the [authentication configuration documentation](${linkify(
'docs/usage/configuration.md#repositoryurl'
)}) is configured with a [valid Git URL](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols).`,
}),
EINVALIDTAGFORMAT: ({tagFormat}) => ({
EINVALIDTAGFORMAT: ({options: {tagFormat}}) => ({
message: 'Invalid `tagFormat` option.',
details: `The [tagFormat](${linkify(
'docs/usage/configuration.md#tagformat'
@@ -49,7 +47,7 @@ Please refer to the [authentication configuration documentation](${linkify(
Your configuration for the \`tagFormat\` option is \`${stringify(tagFormat)}\`.`,
}),
ETAGNOVERSION: ({tagFormat}) => ({
ETAGNOVERSION: ({options: {tagFormat}}) => ({
message: 'Invalid `tagFormat` option.',
details: `The [tagFormat](${linkify(
'docs/usage/configuration.md#tagformat'
@@ -205,40 +203,26 @@ Your configuration for the problematic branch is \`${stringify(branch)}\`.`,
Your configuration for the problematic branches is \`${stringify(branches)}\`.`,
}),
EINVALIDNEXTVERSION: ({nextRelease, branch, commits, validBranches}) => ({
message: `The release \`${nextRelease.version}\` on branch \`${
branch.name
}\` cannot be published as it is out of range.`,
details: `Based on the releases published on other branches, only versions within the range \`${
branch.range
}\` can be published from branch \`${branch.name}\`.
EINVALIDNEXTVERSION: ({nextRelease: {version}, branch: {name, range}, commits, validBranches}) => ({
message: `The release \`${version}\` on branch \`${name}\` cannot be published as it is out of range.`,
details: `Based on the releases published on other branches, only versions within the range \`${range}\` can be published from branch \`${name}\`.
The following commit${commits.length > 1 ? 's are' : ' is'} responsible for the invalid release:
${commits.map(({commit: {short}, subject}) => `- ${subject} (${short})`).join('\n')}
${
commits.length > 1 ? 'Those commits' : 'This commit'
} should be moved to a valid branch with [git merge](https://git-scm.com/docs/git-merge) or [git cherry-pick](https://git-scm.com/docs/git-cherry-pick) and removed from branch \`${
branch.name
}\` with [git revert](https://git-scm.com/docs/git-revert) or [git reset](https://git-scm.com/docs/git-reset).
} should be moved to a valid branch with [git merge](https://git-scm.com/docs/git-merge) or [git cherry-pick](https://git-scm.com/docs/git-cherry-pick) and removed from branch \`${name}\` with [git revert](https://git-scm.com/docs/git-revert) or [git reset](https://git-scm.com/docs/git-reset).
A valid branch could be ${wordsList(validBranches.map(({name}) => `\`${name}\``))}.
See the [workflow configuration documentation](${linkify('docs/usage/workflow-configuration.md')}) for more details.`,
}),
EINVALIDMAINTENANCEMERGE: ({nextRelease, branch}) => ({
message: `The release \`${nextRelease.version}\` on branch \`${
branch.name
}\` cannot be published as it is out of range.`,
details: `Only releases within the range \`${branch['merge-range']}\` can be merged into the maintenance branch \`${
branch.name
}\` and published to the \`${nextRelease.channel}\` distribution channel.
EINVALIDMAINTENANCEMERGE: ({nextRelease: {channel, gitTag, version}, branch: {mergeRange, name}}) => ({
message: `The release \`${version}\` on branch \`${name}\` cannot be published as it is out of range.`,
details: `Only releases within the range \`${mergeRange}\` can be merged into the maintenance branch \`${name}\` and published to the \`${channel}\` distribution channel.
The branch \`${
branch.name
}\` head should be [reset](https://git-scm.com/docs/git-reset) to a previous commit so the commit with tag \`${
nextRelease.gitTag
}\` is removed from the branch history.
The branch \`${name}\` head should be [reset](https://git-scm.com/docs/git-reset) to a previous commit so the commit with tag \`${gitTag}\` is removed from the branch history.
See the [workflow configuration documentation](${linkify('docs/usage/workflow-configuration.md')}) for more details.`,
}),
+1 -3
View File
@@ -23,17 +23,15 @@ const {makeTag} = require('./utils');
*
* @return {LastRelease} The last tagged release or empty object if none is found.
*/
module.exports = ({branch: {name, tags, type}, options: {tagFormat}, logger}, {before} = {}) => {
module.exports = ({branch: {tags, type}, options: {tagFormat}}, {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));
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 on branch ${name}`);
return {};
};
+4 -3
View File
@@ -1,14 +1,15 @@
const semver = require('semver');
const {FIRST_RELEASE, FIRSTPRERELEASE} = require('./definitions/constants');
module.exports = ({branch, nextRelease: {type}, lastRelease, logger}) => {
module.exports = ({branch, nextRelease: {type, channel}, lastRelease, logger}) => {
let version;
if (lastRelease.version) {
const {major, minor, patch} = semver.parse(lastRelease.version);
version =
branch.type === 'prerelease'
? semver.prerelease(lastRelease.version)
? semver.prerelease(lastRelease.version) && lastRelease.channel === channel
? semver.inc(lastRelease.version, 'prerelease')
: `${semver.inc(lastRelease.version, type)}-${branch.prerelease}.${FIRSTPRERELEASE}`
: `${semver.inc(`${major}.${minor}.${patch}`, type)}-${branch.prerelease}.${FIRSTPRERELEASE}`
: semver.inc(lastRelease.version, type);
logger.log('The next release version is %s', version);
} else {
+10 -3
View File
@@ -2,7 +2,7 @@ const {uniq} = require('lodash');
const semver = require('semver');
const semverDiff = require('semver-diff');
const getLastRelease = require('./get-last-release');
const {makeTag} = require('./utils');
const {makeTag, getLowerBound} = require('./utils');
/**
* Find releases that have been merged from from a higher branch but not added on the channel of the current branch.
@@ -28,8 +28,15 @@ module.exports = context => {
.reduce(
(releases, higherBranch) => [
...releases,
// For all unique release version of the higher branch merged on current branch
...uniq(branch.tags.filter(({channel}) => channel === higherBranch.channel))
// For all unique release version of the higher branch merged on current branch, excluding lower than start range version for maintenance branches
...uniq(
branch.tags.filter(
({channel, version}) =>
channel === higherBranch.channel &&
channel !== branch.channel &&
(branch.type !== 'maintenance' || semver.gte(version, getLowerBound(branch.mergeRange)))
)
)
// Find ones that are not released on the building branch channel
.filter(tag =>
branch.tags.every(
+8 -3
View File
@@ -3,7 +3,12 @@ const AggregateError = require('aggregate-error');
const {isGitRepo, verifyTagName} = require('./git');
const getError = require('./get-error');
module.exports = async ({cwd, env, options: {repositoryUrl, tagFormat, branches}}) => {
module.exports = async context => {
const {
cwd,
env,
options: {repositoryUrl, tagFormat, branches},
} = context;
const errors = [];
if (!(await isGitRepo({cwd, env}))) {
@@ -14,14 +19,14 @@ module.exports = async ({cwd, env, options: {repositoryUrl, tagFormat, branches}
// Verify that compiling the `tagFormat` produce a valid Git tag
if (!(await verifyTagName(template(tagFormat)({version: '0.0.0'})))) {
errors.push(getError('EINVALIDTAGFORMAT', {tagFormat}));
errors.push(getError('EINVALIDTAGFORMAT', context));
}
// Verify the `tagFormat` contains the variable `version` by compiling the `tagFormat` template
// with a space as the `version` value and verify the result contains the space.
// The space is used as it's an invalid tag character, so it's guaranteed to no be present in the `tagFormat`.
if ((template(tagFormat)({version: ' '}).match(/ /g) || []).length !== 1) {
errors.push(getError('ETAGNOVERSION', {tagFormat}));
errors.push(getError('ETAGNOVERSION', context));
}
branches.forEach(branch => {
+5 -5
View File
@@ -19,12 +19,12 @@
"Pierre Vanduynslager (https://twitter.com/@pvdlg_)"
],
"dependencies": {
"@semantic-release/commit-analyzer": "^7.0.0-beta.2",
"@semantic-release/commit-analyzer": "^7.0.0-beta.1",
"@semantic-release/error": "^2.2.0",
"@semantic-release/github": "^5.3.0-beta.3",
"@semantic-release/npm": "^5.2.0-beta.2",
"@semantic-release/github": "^5.3.0-beta.6",
"@semantic-release/npm": "^5.2.0-beta.5",
"@semantic-release/release-notes-generator": "^7.1.2",
"aggregate-error": "^1.0.0",
"aggregate-error": "^2.0.0",
"cosmiconfig": "^5.0.1",
"debug": "^4.0.0",
"env-ci": "^3.0.0",
@@ -49,7 +49,7 @@
"yargs": "^12.0.0"
},
"devDependencies": {
"ava": "^0.25.0",
"ava": "^1.0.1",
"clear-module": "^3.0.0",
"codecov": "^3.0.0",
"commitizen": "^3.0.0",
+3 -3
View File
@@ -146,7 +146,7 @@ test('Throw SemanticReleaseError for invalid configurations', async t => {
{name: 'preview', prerelease: 'alpha', tags: []},
];
const getBranches = proxyquire('../../lib/branches', {'./get-tags': () => branches, './expand': () => []});
const errors = [...(await t.throws(getBranches({options: {branches}})))];
const errors = [...(await t.throwsAsync(getBranches({options: {branches}})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'EMAINTENANCEBRANCH');
@@ -174,7 +174,7 @@ test('Throw a SemanticReleaseError if there is duplicate branches', async t => {
const branches = [{name: 'master', tags: []}, {name: 'master', tags: []}];
const getBranches = proxyquire('../../lib/branches', {'./get-tags': () => branches, './expand': () => []});
const errors = [...(await t.throws(getBranches({options: {branches}})))];
const errors = [...(await t.throwsAsync(getBranches({options: {branches}})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'EDUPLICATEBRANCHES');
@@ -186,7 +186,7 @@ test('Throw a SemanticReleaseError for each invalid branch name', async t => {
const branches = [{name: '~master', tags: []}, {name: '^master', tags: []}];
const getBranches = proxyquire('../../lib/branches', {'./get-tags': () => branches, './expand': () => []});
const errors = [...(await t.throws(getBranches({options: {branches}})))];
const errors = [...(await t.throwsAsync(getBranches({options: {branches}})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'EINVALIDBRANCHNAME');
+53 -34
View File
@@ -4,19 +4,17 @@ import normalize from '../../lib/branches/normalize';
const toTags = versions => versions.map(version => ({version}));
test('Maintenance branches - initial state', t => {
const maintenance = [{name: '1.x', tags: []}, {name: '1.1.x', tags: []}, {name: '1.2.x', tags: []}];
const maintenance = [{name: '1.x', channel: '1.x', tags: []}, {name: '1.1.x', tags: []}, {name: '1.2.x', tags: []}];
const release = [{name: 'master', tags: []}];
t.deepEqual(
normalize
.maintenance({maintenance, release})
.map(({type, name, range, accept, channel, 'merge-range': maintenanceRange}) => ({
type,
name,
range,
accept,
channel,
'merge-range': maintenanceRange,
})),
normalize.maintenance({maintenance, release}).map(({type, name, range, accept, channel, mergeRange}) => ({
type,
name,
range,
accept,
channel,
mergeRange,
})),
[
{
type: 'maintenance',
@@ -24,7 +22,7 @@ test('Maintenance branches - initial state', t => {
range: '>=1.1.0 <1.0.0',
accept: [],
channel: '1.1.x',
'merge-range': '>=1.1.0 <1.2.0',
mergeRange: '>=1.1.0 <1.2.0',
},
{
type: 'maintenance',
@@ -32,7 +30,7 @@ test('Maintenance branches - initial state', t => {
range: '>=1.2.0 <1.0.0',
accept: [],
channel: '1.2.x',
'merge-range': '>=1.2.0 <1.3.0',
mergeRange: '>=1.2.0 <1.3.0',
},
{
type: 'maintenance',
@@ -40,7 +38,7 @@ test('Maintenance branches - initial state', t => {
range: '>=1.3.0 <1.0.0',
accept: [],
channel: '1.x',
'merge-range': '>=1.3.0 <2.0.0',
mergeRange: '>=1.3.0 <2.0.0',
},
]
);
@@ -63,13 +61,13 @@ test('Maintenance branches - cap range to first release present on default branc
t.deepEqual(
normalize
.maintenance({maintenance, release})
.map(({type, name, range, accept, channel, 'merge-range': maintenanceRange}) => ({
.map(({type, name, range, accept, channel, mergeRange: maintenanceRange}) => ({
type,
name,
range,
accept,
channel,
'merge-range': maintenanceRange,
mergeRange: maintenanceRange,
})),
[
{
@@ -78,7 +76,7 @@ test('Maintenance branches - cap range to first release present on default branc
range: '>=1.1.1 <1.2.0',
accept: ['patch'],
channel: 'name',
'merge-range': '>=1.1.0 <1.2.0',
mergeRange: '>=1.1.0 <1.2.0',
},
{
type: 'maintenance',
@@ -86,7 +84,7 @@ test('Maintenance branches - cap range to first release present on default branc
range: '>=1.2.1 <1.3.0',
accept: ['patch'],
channel: '1.2.x',
'merge-range': '>=1.2.0 <1.3.0',
mergeRange: '>=1.2.0 <1.3.0',
},
{
type: 'maintenance',
@@ -94,7 +92,7 @@ test('Maintenance branches - cap range to first release present on default branc
range: '>=1.5.0 <1.6.0',
accept: ['patch'],
channel: '1.x',
'merge-range': '>=1.3.0 <2.0.0',
mergeRange: '>=1.3.0 <2.0.0',
},
{
type: 'maintenance',
@@ -102,7 +100,7 @@ test('Maintenance branches - cap range to first release present on default branc
range: '>=2.0.0 <1.6.0',
accept: [],
channel: '2.x.x',
'merge-range': '>=2.0.0 <3.0.0',
mergeRange: '>=2.0.0 <3.0.0',
},
]
);
@@ -116,16 +114,14 @@ test('Maintenance branches - cap range to default branch last release if all rel
const release = [{name: 'master', tags: toTags(['1.0.0', '1.2.0', '1.3.0', '2.0.0'])}];
t.deepEqual(
normalize
.maintenance({maintenance, release})
.map(({type, name, range, accept, channel, 'merge-range': maintenanceRange}) => ({
type,
name,
range,
accept,
channel,
'merge-range': maintenanceRange,
})),
normalize.maintenance({maintenance, release}).map(({type, name, range, accept, channel, mergeRange}) => ({
type,
name,
range,
accept,
channel,
mergeRange,
})),
[
{
type: 'maintenance',
@@ -133,7 +129,7 @@ test('Maintenance branches - cap range to default branch last release if all rel
range: '>=1.3.0 <2.0.0',
accept: ['patch', 'minor'],
channel: '1.x',
'merge-range': '>=1.0.0 <2.0.0',
mergeRange: '>=1.0.0 <2.0.0',
},
{
type: 'maintenance',
@@ -141,14 +137,18 @@ test('Maintenance branches - cap range to default branch last release if all rel
range: '>=2.0.0 <2.0.0',
accept: [],
channel: '2.x.x',
'merge-range': '>=2.0.0 <3.0.0',
mergeRange: '>=2.0.0 <3.0.0',
},
]
);
});
test('Release branches - initial state', t => {
const release = [{name: 'master', tags: []}, {name: 'next', tags: []}, {name: 'next-major', tags: []}];
const release = [
{name: 'master', tags: []},
{name: 'next', channel: 'next', tags: []},
{name: 'next-major', tags: []},
];
t.deepEqual(
normalize.release({release}).map(({type, name, range, accept, channel}) => ({type, name, range, accept, channel})),
@@ -298,10 +298,29 @@ test('Release branches - limit releases on 2nd and 3rd branche based on 1st bran
});
test('Prerelease branches', t => {
const prerelease = [{name: 'beta', prerelease: true, tags: []}, {name: 'alpha', prerelease: 'preview', tags: []}];
const prerelease = [
{name: 'beta', channel: 'beta', prerelease: true, tags: []},
{name: 'alpha', prerelease: 'preview', tags: []},
];
t.deepEqual(normalize.prerelease({prerelease}).map(({type, name, channel}) => ({type, name, channel})), [
{type: 'prerelease', name: 'beta', channel: 'beta'},
{type: 'prerelease', name: 'alpha', channel: 'alpha'},
]);
});
test('Allow to set channel to "false" to prevent default', t => {
const maintenance = [{name: '1.x', channel: false, tags: []}];
const release = [{name: 'master', channel: false, tags: []}, {name: 'next', channel: false, tags: []}];
const prerelease = [{name: 'beta', channel: false, prerelease: true, tags: []}];
t.deepEqual(normalize.maintenance({maintenance, release}).map(({name, channel}) => ({name, channel})), [
{name: '1.x', channel: false},
]);
t.deepEqual(normalize.release({release}).map(({name, channel}) => ({name, channel})), [
{name: 'master', channel: false},
{name: 'next', channel: false},
]);
t.deepEqual(normalize.prerelease({prerelease}).map(({name, channel}) => ({name, channel})), [
{name: 'beta', channel: false},
]);
});
+1 -1
View File
@@ -511,7 +511,7 @@ test('Throw an Error if one of the shareable config cannot be found', async t =>
await outputJson(path.resolve(cwd, 'package.json'), {release: pkhOptions});
await outputJson(path.resolve(cwd, 'shareable1.json'), options1);
const error = await t.throws(t.context.getConfig({cwd}), Error);
const error = await t.throwsAsync(t.context.getConfig({cwd}), Error);
t.is(error.message, "Cannot find module 'non-existing-path'");
t.is(error.code, 'MODULE_NOT_FOUND');
-13
View File
@@ -1,13 +1,6 @@
import test from 'ava';
import {stub} from 'sinon';
import getLastRelease from '../lib/get-last-release';
test.beforeEach(t => {
// Stub the logger functions
t.context.log = stub();
t.context.logger = {log: t.context.log};
});
test('Get the highest non-prerelease valid tag', t => {
const result = getLastRelease({
branch: {
@@ -20,11 +13,9 @@ test('Get the highest non-prerelease valid tag', t => {
type: 'release',
},
options: {tagFormat: `v\${version}`},
logger: t.context.logger,
});
t.deepEqual(result, {version: '2.0.0', gitTag: 'v2.0.0', name: 'v2.0.0', gitHead: '222', channel: undefined});
t.deepEqual(t.context.log.args[0][0], 'Found git tag v2.0.0 associated with version 2.0.0 on branch master');
});
test('Return empty object if no valid tag is found', t => {
@@ -35,11 +26,9 @@ test('Return empty object if no valid tag is found', t => {
type: 'release',
},
options: {tagFormat: `v\${version}`},
logger: t.context.logger,
});
t.deepEqual(result, {});
t.deepEqual(t.context.log.args[0][0], 'No git tag version found on branch master');
});
test('Get the highest non-prerelease valid tag before a certain version', t => {
@@ -58,11 +47,9 @@ test('Get the highest non-prerelease valid tag before a certain version', t => {
type: 'release',
},
options: {tagFormat: `v\${version}`},
logger: t.context.logger,
},
{before: '2.1.0'}
);
t.deepEqual(result, {version: '2.0.0', gitTag: 'v2.0.0', name: 'v2.0.0', gitHead: '333', channel: undefined});
t.deepEqual(t.context.log.args[0][0], 'Found git tag v2.0.0 associated with version 2.0.0 on branch master');
});
+30
View File
@@ -76,6 +76,16 @@ test('Increase version for patch release on prerelease branch', t => {
}),
'1.0.0-beta.2'
);
t.is(
getNextVersion({
branch: {name: 'alpha', type: 'prerelease', prerelease: 'alpha'},
nextRelease: {type: 'patch', channel: 'alpha'},
lastRelease: {version: '1.0.0-beta.1', channel: 'beta'},
logger: t.context.logger,
}),
'1.0.1-alpha.1'
);
});
test('Increase version for minor release on prerelease branch', t => {
@@ -98,6 +108,16 @@ test('Increase version for minor release on prerelease branch', t => {
}),
'1.0.0-beta.2'
);
t.is(
getNextVersion({
branch: {name: 'alpha', type: 'prerelease', prerelease: 'alpha'},
nextRelease: {type: 'minor', channel: 'alpha'},
lastRelease: {version: '1.0.0-beta.1', channel: 'beta'},
logger: t.context.logger,
}),
'1.1.0-alpha.1'
);
});
test('Increase version for major release on prerelease branch', t => {
@@ -120,6 +140,16 @@ test('Increase version for major release on prerelease branch', t => {
}),
'1.0.0-beta.2'
);
t.is(
getNextVersion({
branch: {name: 'alpha', type: 'prerelease', prerelease: 'alpha'},
nextRelease: {type: 'major', channel: 'alpha'},
lastRelease: {version: '1.0.0-beta.1', channel: 'beta'},
logger: t.context.logger,
}),
'2.0.0-alpha.1'
);
});
test('Return 1.0.0 if there is no previous release on prerelease branch', t => {
+93 -38
View File
@@ -1,73 +1,69 @@
import test from 'ava';
import {stub} from 'sinon';
import getReleasesToAdd from '../lib/get-releases-to-add';
test.beforeEach(t => {
// Stub the logger functions
t.context.log = stub();
t.context.logger = {log: t.context.log};
});
test('Return versions merged from release to maintenance branch', t => {
test('Return versions merged from release to maintenance branch, excluding lower than branch start range', t => {
const result = getReleasesToAdd({
branch: {
name: '1.x',
channel: '1.x',
name: '2.x',
channel: '2.x',
type: 'maintenance',
mergeRange: '>=2.0.0 <3.0.0',
tags: [
{gitTag: 'v1.0.0@1.x', version: '1.0.0', channel: '1.x', gitHead: '111'},
{gitTag: 'v1.0.0', version: '1.0.0', gitHead: '111'},
{gitTag: 'v1.1.0', version: '1.1.0', gitHead: '222'},
{gitTag: 'v1.1.1', version: '1.1.1', gitHead: '333'},
{gitTag: 'v2.0.0@2.x', version: '2.0.0', channel: '2.x', gitHead: '111'},
{gitTag: 'v2.0.0', version: '2.0.0', gitHead: '111'},
{gitTag: 'v2.1.0', version: '2.1.0', gitHead: '222'},
{gitTag: 'v2.1.1', version: '2.1.1', gitHead: '333'},
{gitTag: 'v1.0.0', version: '1.0.0', gitHead: '444'},
{gitTag: 'v1.1.0', version: '1.1.0', gitHead: '555'},
],
},
branches: [{name: '1.x', channel: '1.x'}, {name: 'master'}],
branches: [{name: '2.x', channel: '2.x'}, {name: 'master'}],
options: {tagFormat: `v\${version}`},
logger: t.context.logger,
});
t.deepEqual(result, [
{
lastRelease: {version: '1.0.0', channel: '1.x', gitTag: 'v1.0.0@1.x', name: 'v1.0.0', gitHead: '111'},
lastRelease: {version: '2.0.0', channel: '2.x', gitTag: 'v2.0.0@2.x', name: 'v2.0.0', gitHead: '111'},
currentRelease: {
type: 'minor',
version: '1.1.0',
version: '2.1.0',
channel: undefined,
gitTag: 'v1.1.0',
name: 'v1.1.0',
gitTag: 'v2.1.0',
name: 'v2.1.0',
gitHead: '222',
},
nextRelease: {
type: 'minor',
version: '1.1.0',
channel: '1.x',
gitTag: 'v1.1.0@1.x',
name: 'v1.1.0',
version: '2.1.0',
channel: '2.x',
gitTag: 'v2.1.0@2.x',
name: 'v2.1.0',
gitHead: '222',
},
},
{
lastRelease: {version: '1.1.0', channel: undefined, gitTag: 'v1.1.0', name: 'v1.1.0', gitHead: '222'},
lastRelease: {version: '2.1.0', channel: undefined, gitTag: 'v2.1.0', name: 'v2.1.0', gitHead: '222'},
currentRelease: {
type: 'patch',
version: '1.1.1',
version: '2.1.1',
channel: undefined,
gitTag: 'v1.1.1',
name: 'v1.1.1',
gitTag: 'v2.1.1',
name: 'v2.1.1',
gitHead: '333',
},
nextRelease: {
type: 'patch',
version: '1.1.1',
channel: '1.x',
gitTag: 'v1.1.1@1.x',
name: 'v1.1.1',
version: '2.1.1',
channel: '2.x',
gitTag: 'v2.1.1@2.x',
name: 'v2.1.1',
gitHead: '333',
},
},
]);
});
test('Return versions merged from future branch to release branch', t => {
test('Return versions merged between release branches', t => {
const result = getReleasesToAdd({
branch: {
name: 'master',
@@ -80,7 +76,6 @@ test('Return versions merged from future branch to release branch', t => {
},
branches: [{name: 'master'}, {name: 'next', channel: 'next'}, {name: 'next-major', channel: 'next-major'}],
options: {tagFormat: `v\${version}`},
logger: t.context.logger,
});
t.deepEqual(result, [
@@ -138,7 +133,6 @@ test('Return releases sorted by ascending order', t => {
},
branches: [{name: 'master'}, {name: 'next', channel: 'next'}, {name: 'next-major', channel: 'next-major'}],
options: {tagFormat: `v\${version}`},
logger: t.context.logger,
});
t.deepEqual(result, [
@@ -183,12 +177,11 @@ test('Return releases sorted by ascending order', t => {
]);
});
test('no lastRelease', t => {
test('No lastRelease', t => {
const result = getReleasesToAdd({
branch: {name: 'master', tags: [{gitTag: 'v1.0.0@next', version: '1.0.0', channel: 'next', gitHead: '111'}]},
branches: [{name: 'master'}, {name: 'next', channel: 'next'}],
options: {tagFormat: `v\${version}`},
logger: t.context.logger,
});
t.deepEqual(result, [
@@ -231,7 +224,6 @@ test('Ignore pre-release versions', t => {
{name: 'alpha', type: 'prerelease', channel: 'alpha'},
],
options: {tagFormat: `v\${version}`},
logger: t.context.logger,
});
t.deepEqual(result, [
@@ -256,3 +248,66 @@ test('Ignore pre-release versions', t => {
},
]);
});
test('Exclude versions merged from release to maintenance branch if they have the same "channel"', t => {
const result = getReleasesToAdd({
branch: {
name: '2.x',
channel: 'latest',
type: 'maintenance',
mergeRange: '>=2.0.0 <3.0.0',
tags: [
{gitTag: 'v2.0.0', version: '2.0.0', gitHead: '111'},
{gitTag: 'v2.0.0', version: '2.0.0', gitHead: '111'},
{gitTag: 'v2.1.0', version: '2.1.0', gitHead: '222'},
{gitTag: 'v2.1.1', version: '2.1.1', gitHead: '333'},
{gitTag: 'v1.0.0', version: '1.0.0', gitHead: '444'},
{gitTag: 'v1.1.0', version: '1.1.0', gitHead: '555'},
],
},
branches: [{name: '2.x', channel: 'latest'}, {name: 'master', channel: 'latest'}],
options: {tagFormat: `v\${version}`},
});
t.deepEqual(result, []);
});
test('Exclude versions merged between release branches if they have the same "channel"', t => {
const result = getReleasesToAdd({
branch: {
name: 'master',
channel: 'latest',
tags: [
{gitTag: 'v1.0.0', channel: 'latest', version: '1.0.0', gitHead: '111'},
{gitTag: 'v1.1.0', channel: 'latest', version: '1.1.0', gitHead: '222'},
{gitTag: 'v2.0.0', channel: 'latest', version: '2.0.0', gitHead: '333'},
],
},
branches: [
{name: 'master', channel: 'latest'},
{name: 'next', channel: 'latest'},
{name: 'next-major', channel: 'latest'},
],
options: {tagFormat: `v\${version}`},
});
t.deepEqual(result, []);
});
test('Exclude versions merged between release branches if they all have "channel" set to "false"', t => {
const result = getReleasesToAdd({
branch: {
name: 'master',
channel: false,
tags: [
{gitTag: 'v1.0.0', version: '1.0.0', gitHead: '111'},
{gitTag: 'v1.1.0', version: '1.1.0', gitHead: '222'},
{gitTag: 'v2.0.0', version: '2.0.0', gitHead: '333'},
],
},
branches: [{name: 'master', channel: false}, {name: 'next', channel: false}, {name: 'next-major', channel: false}],
options: {tagFormat: `v\${version}`},
});
t.deepEqual(result, []);
});
+5 -5
View File
@@ -44,7 +44,7 @@ test('Throw error if the last commit sha cannot be found', async t => {
// Create a git repository, set the current working directory at the root of the repo
const {cwd} = await gitRepo();
await t.throws(getGitHead({cwd}), Error);
await t.throwsAsync(getGitHead({cwd}), Error);
});
test('Unshallow and fetch repository', async t => {
@@ -73,8 +73,8 @@ test('Do not throw error when unshallow a complete repository', async t => {
await gitCommits(['Second'], {cwd});
await gitPush(repositoryUrl, 'second-branch', {cwd});
await t.notThrows(fetch('master', {cwd}));
await t.notThrows(fetch('second-branch', {cwd}));
await t.notThrowsAsync(fetch('master', {cwd}));
await t.notThrowsAsync(fetch('second-branch', {cwd}));
});
test('Fetch all tags on a detached head repository', async t => {
@@ -108,7 +108,7 @@ test('Verify if the commit `sha` is in the direct history of the current branch'
t.true(await isRefInHistory(commits[0].hash, 'master', false, {cwd}));
t.falsy(await isRefInHistory(otherCommits[0].hash, 'master', false, {cwd}));
t.falsy(await isRefInHistory(otherCommits[0].hash, 'missing-branch', false, {cwd}));
await t.throws(isRefInHistory('non-existant-sha', 'master', false, {cwd}));
await t.throwsAsync(isRefInHistory('non-existant-sha', 'master', false, {cwd}));
});
test('Verify if a branch exists', async t => {
@@ -243,7 +243,7 @@ test('Return falsy for invalid tag names', async t => {
test('Throws error if obtaining the tags fails', async t => {
const cwd = tempy.directory();
await t.throws(getTags({cwd}));
await t.throwsAsync(getTags({cwd}));
});
test('Return "true" if repository is up to date', async t => {
+18 -16
View File
@@ -342,14 +342,14 @@ test('Plugins are called with expected values', async t => {
t.deepEqual(success.args[1][0], config);
t.deepEqual(success.args[1][1].options, options);
t.deepEqual(success.args[0][1].branch, branch);
t.deepEqual(success.args[0][1].branches, branches);
t.deepEqual(success.args[1][1].branch, branch);
t.deepEqual(success.args[1][1].branches, branches);
t.deepEqual(success.args[1][1].logger, t.context.logger);
t.deepEqual(success.args[1][1].lastRelease, lastRelease);
t.deepEqual(success.args[1][1].commits[0].hash, commits[0].hash);
t.deepEqual(success.args[1][1].commits[0].message, commits[0].message);
t.deepEqual(success.args[1][1].nextRelease, {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`});
t.deepEqual(success.args[1][1].releases, releases);
t.deepEqual(success.args[1][1].releases, [releases[1], releases[2]]);
t.deepEqual(result, {
lastRelease,
@@ -763,7 +763,7 @@ test('Call all "success" plugins even if one errors out', async t => {
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
await t.throws(
await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()})
);
@@ -799,7 +799,7 @@ test('Log all "verifyConditions" errors', async t => {
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const errors = [
...(await t.throws(
...(await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()})
)),
];
@@ -844,7 +844,7 @@ test('Log all "verifyRelease" errors', async t => {
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const errors = [
...(await t.throws(
...(await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()})
)),
];
@@ -949,7 +949,7 @@ test('Dry-run skips fail', async t => {
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const errors = [
...(await t.throws(
...(await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()})
)),
];
@@ -1203,7 +1203,7 @@ test('Accept "undefined" value returned by "generateNotes" and "false" by "publi
t.is(success.callCount, 2);
t.deepEqual(publish.args[0][1].nextRelease, {...nextRelease, notes: notes2});
t.deepEqual(success.args[0][1].releases, [{pluginName: '[Function: proxy]'}]);
t.deepEqual(success.args[1][1].releases, [{pluginName: '[Function: proxy]'}, {pluginName: '[Function: proxy]'}]);
t.deepEqual(success.args[1][1].releases, [{pluginName: '[Function: proxy]'}]);
});
test('Returns false if triggered by a PR', async t => {
@@ -1268,7 +1268,7 @@ test('Throws "EINVALIDNEXTVERSION" if next release is out of range of the curren
'env-ci': () => ({isCi: true, branch: '1.x', isPr: false}),
});
const error = await t.throws(
const error = await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}})
);
@@ -1319,7 +1319,7 @@ test('Throws "EINVALIDNEXTVERSION" if next release is out of range of the curren
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const error = await t.throws(
const error = await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}})
);
@@ -1388,7 +1388,9 @@ test('Throws "EINVALIDMAINTENANCEMERGE" if merge an out of range release in a ma
'env-ci': () => ({isCi: true, branch: '1.1.x', isPr: false}),
});
const errors = [
...(await t.throws(semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}))),
...(await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}})
)),
];
t.is(addChannel.callCount, 1);
@@ -1587,7 +1589,7 @@ test('Log both plugins errors and errors thrown by "fail" plugin', async t => {
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
await t.throws(
await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()})
);
@@ -1612,7 +1614,7 @@ test('Call "fail" only if a plugin returns a SemanticReleaseError', async t => {
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
await t.throws(
await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()})
);
@@ -1629,7 +1631,7 @@ test('Throw SemanticReleaseError if repositoryUrl is not set and cannot be found
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const errors = [
...(await t.throws(
...(await t.throwsAsync(
semanticRelease({}, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()})
)),
];
@@ -1668,7 +1670,7 @@ test('Throw an Error if plugin returns an unexpected value', async t => {
'./lib/get-logger': () => t.context.logger,
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const error = await t.throws(
const error = await t.throwsAsync(
semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}),
Error
);
@@ -1698,7 +1700,7 @@ test('Hide sensitive information passed to "fail" plugin', async t => {
'./lib/get-logger': () => t.context.logger,
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
await t.throws(
await t.throwsAsync(
semanticRelease(options, {cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}),
Error
);
+3 -3
View File
@@ -317,7 +317,7 @@ test('Exit with 1 if a plugin is not found', async t => {
release: {analyzeCommits: 'non-existing-path', success: false, fail: false},
});
const {code, stderr} = await t.throws(execa(cli, [], {env, cwd}));
const {code, stderr} = await t.throwsAsync(execa(cli, [], {env, cwd}));
t.is(code, 1);
t.regex(stderr, /Cannot find module/);
});
@@ -335,7 +335,7 @@ test('Exit with 1 if a shareable config is not found', async t => {
release: {extends: 'non-existing-path', success: false, fail: false},
});
const {code, stderr} = await t.throws(execa(cli, [], {env, cwd}));
const {code, stderr} = await t.throwsAsync(execa(cli, [], {env, cwd}));
t.is(code, 1);
t.regex(stderr, /Cannot find module/);
});
@@ -356,7 +356,7 @@ test('Exit with 1 if a shareable config reference a not found plugin', async t =
});
await writeJson(path.resolve(cwd, 'shareable.json'), shareable);
const {code, stderr} = await t.throws(execa(cli, [], {env, cwd}));
const {code, stderr} = await t.throwsAsync(execa(cli, [], {env, cwd}));
t.is(code, 1);
t.regex(stderr, /Cannot find module/);
});
+6 -6
View File
@@ -62,7 +62,7 @@ test('Wrap plugin in a function that add the "pluginName" to the error"', async
'./plugin-error': './test/fixtures',
});
const error = await t.throws(plugin({options: {}}));
const error = await t.throwsAsync(plugin({options: {}}));
t.is(error.pluginName, './plugin-error');
});
@@ -72,7 +72,7 @@ test('Wrap plugin in a function that add the "pluginName" to multiple errors"',
'./plugin-errors': './test/fixtures',
});
const errors = [...(await t.throws(plugin({options: {}})))];
const errors = [...(await t.throwsAsync(plugin({options: {}})))];
for (const error of errors) {
t.is(error.pluginName, './plugin-errors');
}
@@ -107,7 +107,7 @@ test('Wrap "analyzeCommits" plugin in a function that validate the output of the
{}
);
const error = await t.throws(plugin({options: {}}));
const error = await t.throwsAsync(plugin({options: {}}));
t.is(error.code, 'EANALYZECOMMITSOUTPUT');
t.is(error.name, 'SemanticReleaseError');
@@ -125,7 +125,7 @@ test('Wrap "generateNotes" plugin in a function that validate the output of the
{}
);
const error = await t.throws(plugin({options: {}}));
const error = await t.throwsAsync(plugin({options: {}}));
t.is(error.code, 'EGENERATENOTESOUTPUT');
t.is(error.name, 'SemanticReleaseError');
@@ -143,7 +143,7 @@ test('Wrap "publish" plugin in a function that validate the output of the plugin
{}
);
const error = await t.throws(plugin({options: {}}));
const error = await t.throwsAsync(plugin({options: {}}));
t.is(error.code, 'EPUBLISHOUTPUT');
t.is(error.name, 'SemanticReleaseError');
@@ -161,7 +161,7 @@ test('Wrap "addChannel" plugin in a function that validate the output of the plu
{}
);
const error = await t.throws(plugin({options: {}}));
const error = await t.throwsAsync(plugin({options: {}}));
t.is(error.code, 'EADDCHANNELOUTPUT');
t.is(error.name, 'SemanticReleaseError');
+5 -5
View File
@@ -83,7 +83,7 @@ test('Stop execution and throw error if a step rejects', async t => {
const step2 = stub().rejects(new Error('test error'));
const step3 = stub().resolves(3);
const error = await t.throws(pipeline([step1, step2, step3])(0), Error);
const error = await t.throwsAsync(pipeline([step1, step2, step3])(0), Error);
t.is(error.message, 'test error');
t.true(step1.calledWith(0));
t.true(step2.calledWith(0));
@@ -98,7 +98,7 @@ test('Throw all errors from the first step throwing an AggregateError', async t
const step2 = stub().rejects(new AggregateError([error1, error2]));
const step3 = stub().resolves(3);
const errors = await t.throws(pipeline([step1, step2, step3])(0));
const errors = await t.throwsAsync(pipeline([step1, step2, step3])(0));
t.deepEqual([...errors], [error1, error2]);
t.true(step1.calledWith(0));
@@ -113,7 +113,7 @@ test('Execute all even if a Promise rejects', async t => {
const step2 = stub().rejects(error1);
const step3 = stub().rejects(error2);
const errors = await t.throws(pipeline([step1, step2, step3], {settleAll: true})(0));
const errors = await t.throwsAsync(pipeline([step1, step2, step3], {settleAll: true})(0));
t.deepEqual([...errors], [error1, error2]);
t.true(step1.calledWith(0));
@@ -129,7 +129,7 @@ test('Throw all errors from all steps throwing an AggregateError', async t => {
const step1 = stub().rejects(new AggregateError([error1, error2]));
const step2 = stub().rejects(new AggregateError([error3, error4]));
const errors = await t.throws(pipeline([step1, step2], {settleAll: true})(0));
const errors = await t.throwsAsync(pipeline([step1, step2], {settleAll: true})(0));
t.deepEqual([...errors], [error1, error2, error3, error4]);
t.true(step1.calledWith(0));
@@ -145,7 +145,7 @@ test('Execute each function in series passing a transformed input even if a step
const step4 = stub().resolves(4);
const getNextInput = (prevResult, result) => prevResult + result;
const errors = await t.throws(pipeline([step1, step2, step3, step4], {settleAll: true, getNextInput})(0));
const errors = await t.throwsAsync(pipeline([step1, step2, step3, step4], {settleAll: true, getNextInput})(0));
t.deepEqual([...errors], [error2, error3]);
t.true(step1.calledWith(0));
+2
View File
@@ -173,6 +173,8 @@ test('getRange', t => {
test('makeTag', t => {
t.is(makeTag(`v\${version}`, '1.0.0'), 'v1.0.0');
t.is(makeTag(`v\${version}`, '1.0.0', false), 'v1.0.0');
t.is(makeTag(`v\${version}`, '1.0.0', null), 'v1.0.0');
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');
});
+7 -7
View File
@@ -7,7 +7,7 @@ test('Throw a AggregateError', async t => {
const {cwd} = await gitRepo();
const options = {branches: [{name: 'master'}, {name: ''}]};
const errors = [...(await t.throws(verify({cwd, options})))];
const errors = [...(await t.throwsAsync(verify({cwd, options})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'ENOREPOURL');
@@ -31,7 +31,7 @@ test('Throw a SemanticReleaseError if does not run on a git repository', async t
const cwd = tempy.directory();
const options = {branches: []};
const errors = [...(await t.throws(verify({cwd, options})))];
const errors = [...(await t.throwsAsync(verify({cwd, options})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'ENOGITREPO');
@@ -43,7 +43,7 @@ test('Throw a SemanticReleaseError if the "tagFormat" is not valid', async t =>
const {cwd, repositoryUrl} = await gitRepo(true);
const options = {repositoryUrl, tagFormat: `?\${version}`, branches: []};
const errors = [...(await t.throws(verify({cwd, options})))];
const errors = [...(await t.throwsAsync(verify({cwd, options})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'EINVALIDTAGFORMAT');
@@ -55,7 +55,7 @@ test('Throw a SemanticReleaseError if the "tagFormat" does not contains the "ver
const {cwd, repositoryUrl} = await gitRepo(true);
const options = {repositoryUrl, tagFormat: 'test', branches: []};
const errors = [...(await t.throws(verify({cwd, options})))];
const errors = [...(await t.throwsAsync(verify({cwd, options})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'ETAGNOVERSION');
@@ -67,7 +67,7 @@ test('Throw a SemanticReleaseError if the "tagFormat" contains multiple "version
const {cwd, repositoryUrl} = await gitRepo(true);
const options = {repositoryUrl, tagFormat: `\${version}v\${version}`, branches: []};
const errors = [...(await t.throws(verify({cwd, options})))];
const errors = [...(await t.throwsAsync(verify({cwd, options})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'ETAGNOVERSION');
@@ -83,7 +83,7 @@ test('Throw a SemanticReleaseError for each invalid branch', async t => {
branches: [{name: ''}, {name: ' '}, {name: 1}, {}, {name: ''}, 1, 'master'],
};
const errors = [...(await t.throws(verify({cwd, options})))];
const errors = [...(await t.throwsAsync(verify({cwd, options})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'EINVALIDBRANCH');
@@ -113,5 +113,5 @@ test('Return "true" if all verification pass', async t => {
const {cwd, repositoryUrl} = await gitRepo(true);
const options = {repositoryUrl, tagFormat: `v\${version}`, branches: [{name: 'master'}]};
await t.notThrows(verify({cwd, options}));
await t.notThrowsAsync(verify({cwd, options}));
});