Compare commits
22
Commits
@@ -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)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Bad news: We have to write plain ES5 in this file
|
||||
// Good news: It's the only file of the entire project
|
||||
|
||||
/* eslint-disable no-var, promise/prefer-await-to-then, prefer-destructuring */
|
||||
/* eslint-disable no-var */
|
||||
|
||||
var semver = require('semver');
|
||||
var execa = require('execa');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {argv, env, stderr} = require('process');
|
||||
const {argv, env, stderr} = require('process'); // eslint-disable-line node/prefer-global/process
|
||||
const util = require('util');
|
||||
const hideSensitive = require('./lib/hide-sensitive');
|
||||
|
||||
@@ -51,12 +51,14 @@ Usage:
|
||||
// Debug must be enabled before other requires in order to work
|
||||
require('debug').enable('semantic-release:*');
|
||||
}
|
||||
|
||||
await require('.')(opts);
|
||||
return 0;
|
||||
} catch (error) {
|
||||
if (error.name !== 'YError') {
|
||||
stderr.write(hideSensitive(env)(util.inspect(error, {colors: true})));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ try {
|
||||
const result = await semanticRelease({
|
||||
// Core options
|
||||
branches: [
|
||||
'+([1-9])?(.{+([1-9]),x}).x',
|
||||
'+([0-9])?(.{+([0-9]),x}).x',
|
||||
'master',
|
||||
'next',
|
||||
'next-major',
|
||||
|
||||
@@ -71,3 +71,5 @@
|
||||
- `verifyRelease`: Checks and warns (does not error by default) if the version numbers found on maven central and within the Git project differ by quite a bit
|
||||
- `prepare`: Changes the version number in the `pom.xml` (or all `pom.xml` files in maven projects with multiple `pom.xml` files) and optionally creates a commit with this version number and pushes it to `master`
|
||||
- `publish`: Runs `mvn deploy` to deploy to maven central and optionally will update to next snapshot version and merge changes to development branch
|
||||
- [semantic-release-ado](https://github.com/lluchmk/semantic-release-ado)
|
||||
- `prepare`: Stores the version number as an Azure DevOps pipeline variable availabe to downstream steps on the job
|
||||
@@ -3,7 +3,7 @@
|
||||
This recipe will walk you through a simple example that uses distribution channels to make releases available only to a subset of users, in order to collect feedbacks before distributing the release to all users.
|
||||
|
||||
This example uses the **semantic-release** default configuration:
|
||||
- [branches](../usage/configuration.md#branches): `['+([1-9])?(.{+([1-9]),x}).x', 'master', 'next', 'next-major', {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}]`
|
||||
- [branches](../usage/configuration.md#branches): `['+([0-9])?(.{+([0-9]),x}).x', 'master', 'next', 'next-major', {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}]`
|
||||
- [plugins](../usage/configuration.md#plugins): `['@semantic-release/commit-analyzer', '@semantic-release/release-notes-generator', '@semantic-release/npm', '@semantic-release/github']`
|
||||
|
||||
## Initial release
|
||||
|
||||
@@ -158,6 +158,6 @@ Commit the encrypted private key and the `.circleci/config.yml` file to your rep
|
||||
|
||||
```bash
|
||||
$ git add git_deploy_key.enc .circleci/config.yml
|
||||
$ git commit -m "ci(cicle): Add the encrypted private ssh key"
|
||||
$ git commit -m "ci(circle): Add the encrypted private ssh key"
|
||||
$ git push
|
||||
```
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
This recipe will walk you through a simple example that uses Git branches and distribution channels to publish fixes and features for old versions of a package.
|
||||
|
||||
This example uses the **semantic-release** default configuration:
|
||||
- [branches](../usage/configuration.md#branches): `['+([1-9])?(.{+([1-9]),x}).x', 'master', 'next', 'next-major', {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}]`
|
||||
- [branches](../usage/configuration.md#branches): `['+([0-9])?(.{+([0-9]),x}).x', 'master', 'next', 'next-major', {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}]`
|
||||
- [plugins](../usage/configuration.md#plugins): `['@semantic-release/commit-analyzer', '@semantic-release/release-notes-generator', '@semantic-release/npm', '@semantic-release/github']`
|
||||
|
||||
## Initial release
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
This recipe will walk you through a simple example that uses pre-releases to publish beta versions while working on a future major release and then make only one release on the default distribution.
|
||||
|
||||
This example uses the **semantic-release** default configuration:
|
||||
- [branches](../usage/configuration.md#branches): `['+([1-9])?(.{+([1-9]),x}).x', 'master', 'next', 'next-major', {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}]`
|
||||
- [branches](../usage/configuration.md#branches): `['+([0-9])?(.{+([0-9]),x}).x', 'master', 'next', 'next-major', {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}]`
|
||||
- [plugins](../usage/configuration.md#plugins): `['@semantic-release/commit-analyzer', '@semantic-release/release-notes-generator', '@semantic-release/npm', '@semantic-release/github']`
|
||||
|
||||
## Initial release
|
||||
|
||||
+2
-2
@@ -145,7 +145,7 @@ If you have introduced a breaking bug in a release you have 2 options:
|
||||
|
||||
In both cases **semantic-release** will publish a new release, so your package users' will get the fixed/reverted version.
|
||||
|
||||
Depending on the package manager you are using, you might be able to un-publish or deprecate a release, in order to prevent users to download it by accident. For example npm allows you to [un-publish](https://docs.npmjs.com/cli/unpublish) in [next 72 hours](https://www.npmjs.com/policies/unpublish) after releasing or to [deprecate](https://docs.npmjs.com/cli/deprecate) a release.
|
||||
Depending on the package manager you are using, you might be able to un-publish or deprecate a release, in order to prevent users from downloading it by accident. For example npm allows you to [un-publish](https://docs.npmjs.com/cli/unpublish) [within 72 hours](https://www.npmjs.com/policies/unpublish) after releasing. You may also [deprecate](https://docs.npmjs.com/cli/deprecate) a release if you would rather avoid un-publishing.
|
||||
|
||||
In any case **do not remove the Git tag associated with the buggy version**, otherwise **semantic-release** will later try to republish that version. Publishing a version after un-publishing is not supported by most package managers.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ npm ERR! You do not have permission to publish "<package-name>". Are you logged
|
||||
|
||||
This is most likely related to a misconfiguration of the [npm registry authentication](https://github.com/semantic-release/npm#npm-registry-authentication) or to your user [missing permission](https://docs.npmjs.com/cli/team) for publishing.
|
||||
|
||||
It might also happen if the package name you are trying to publish already exists (in such case npm consider you are trying to publish a new version of a package that is not yours, hence the permission error).
|
||||
It might also happen if the package name you are trying to publish already exists (in the case of npm, you may be trying to publish a new version of a package that is not yours, hence the permission error).
|
||||
|
||||
To verify if your package name is available you can use [npm-name-cli](https://github.com/sindresorhus/npm-name-cli):
|
||||
```bash
|
||||
|
||||
@@ -26,7 +26,7 @@ Most **semantic-release** [plugins](plugins.md) require setting up authenticatio
|
||||
| `NPM_TOKEN` | npm token created via [npm token create](https://docs.npmjs.com/getting-started/working_with_tokens#how-to-create-new-tokens).<br/>**Note**: Only the `auth-only` [level of npm two-factor authentication](https://docs.npmjs.com/getting-started/using-two-factor-authentication#levels-of-authentication) is supported. |
|
||||
| `GH_TOKEN` | GitHub authentication token.<br/>**Note**: Only the [personal token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line) authentication is supported. |
|
||||
|
||||
See each plugin documentation for the environment variables to set up.
|
||||
See each plugin's documentation for the environment variables required.
|
||||
|
||||
The authentication token/credentials have to be made available in the CI service via environment variables.
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ List of modules or file paths containing a [shareable configuration](shareable-c
|
||||
### branches
|
||||
|
||||
Type: `Array`, `String`, `Object`<br>
|
||||
Default: `['+([1-9])?(.{+([1-9]),x}).x', 'master', 'next', 'next-major', {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}]`<br>
|
||||
Default: `['+([0-9])?(.{+([0-9]),x}).x', 'master', 'next', 'next-major', {name: 'beta', prerelease: true}, {name: 'alpha', prerelease: true}]`<br>
|
||||
CLI arguments: `--branches`
|
||||
|
||||
The branches on which releases should happen. By default **semantic-release** will release:
|
||||
@@ -81,6 +81,8 @@ The branches on which releases should happen. By default **semantic-release** wi
|
||||
- prereleases to the `beta` distribution channel from the branch `beta` if it exists
|
||||
- prereleases to the `alpha` distribution channel from the branch `alpha` if it exists
|
||||
|
||||
**Note**: If your repository does not have a release branch, then **semantic-release** will fail with an `ERELEASEBRANCHES` error message. If you are using the default configuration, you can fix this error by pushing a `master` branch.
|
||||
|
||||
**Note**: Once **semantic-release** is configured, any user with the permission to push commits on one of those branches will be able to publish a release. It is recommended to protect those branches, for example with [GitHub protected branches](https://help.github.com/articles/about-protected-branches).
|
||||
|
||||
See [Plugins configuration](plugins.md#plugins) for more details.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Shareable configurations
|
||||
|
||||
A sharable configuration is an [npm](https://www.npmjs.com/) package that exports a **semantic-release** configuration object. It allows for use of the same configuration across several projects.
|
||||
A shareable configuration is an [npm](https://www.npmjs.com/) package that exports a **semantic-release** configuration object. It allows for use of the same configuration across several projects.
|
||||
|
||||
The shareable configurations to use can be set with the [extends](configuration.md#extends) option.
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ It can be defined as a [glob](https://github.com/micromatch/micromatch#matching-
|
||||
|
||||
If `name` doesn't match to any branch existing in the repository, the definition will be ignored. For example the default configuration includes the definition `next` and `next-major` which will become active only when the branches `next` and/or `next-major` are created in the repository. This allow to define your workflow once with all potential branches you might use and have the effective configuration evolving as you create new branches.
|
||||
|
||||
For example the configuration `['+([1-9])?(.{+([1-9]),x}).x', 'master', 'next']` will be expanded as:
|
||||
For example the configuration `['+([0-9])?(.{+([0-9]),x}).x', 'master', 'next']` will be expanded as:
|
||||
```js
|
||||
{
|
||||
branches: [
|
||||
|
||||
@@ -53,7 +53,8 @@ async function run(context, plugins) {
|
||||
// Verify config
|
||||
await verify(context);
|
||||
|
||||
context.branches = await getBranches(context);
|
||||
options.repositoryUrl = await getGitAuthUrl(context);
|
||||
context.branches = await getBranches(options.repositoryUrl, context);
|
||||
context.branch = context.branches.find(({name}) => name === ciBranch);
|
||||
|
||||
if (!context.branch) {
|
||||
@@ -64,17 +65,16 @@ async function run(context, plugins) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
logger[options.dryRun ? 'warn' : 'success'](
|
||||
`Run automated release from branch ${ciBranch}${options.dryRun ? ' in dry-run mode' : ''}`
|
||||
);
|
||||
|
||||
options.repositoryUrl = await getGitAuthUrl(context);
|
||||
|
||||
try {
|
||||
try {
|
||||
await verifyAuth(options.repositoryUrl, context.branch.name, {cwd, env});
|
||||
} catch (error) {
|
||||
if (!(await isBranchUpToDate(context.branch.name, {cwd, env}))) {
|
||||
if (!(await isBranchUpToDate(options.repositoryUrl, context.branch.name, {cwd, env}))) {
|
||||
logger.log(
|
||||
`The local branch ${
|
||||
context.branch.name
|
||||
@@ -82,11 +82,12 @@ async function run(context, plugins) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
} 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 +99,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ const {isString, remove, omit, mapValues, template} = require('lodash');
|
||||
const micromatch = require('micromatch');
|
||||
const {getBranches} = require('../git');
|
||||
|
||||
module.exports = async ({cwd}, branches) => {
|
||||
const gitBranches = await getBranches({cwd});
|
||||
module.exports = async (repositoryUrl, {cwd}, branches) => {
|
||||
const gitBranches = await getBranches(repositoryUrl, {cwd});
|
||||
|
||||
return branches.reduce(
|
||||
(branches, branch) => [
|
||||
|
||||
@@ -8,16 +8,17 @@ const expand = require('./expand');
|
||||
const getTags = require('./get-tags');
|
||||
const normalize = require('./normalize');
|
||||
|
||||
module.exports = async context => {
|
||||
module.exports = async (repositoryUrl, context) => {
|
||||
const {cwd, env} = context;
|
||||
|
||||
const remoteBranches = await expand(
|
||||
repositoryUrl,
|
||||
context,
|
||||
context.options.branches.map(branch => (isString(branch) || isRegExp(branch) ? {name: branch} : branch))
|
||||
);
|
||||
|
||||
await pEachSeries(remoteBranches, async ({name}) => {
|
||||
await fetch(name, {cwd, env});
|
||||
await fetch(repositoryUrl, name, {cwd, env});
|
||||
});
|
||||
|
||||
const branches = await getTags(context, remoteBranches);
|
||||
|
||||
@@ -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)),
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -60,6 +60,7 @@ function release({release}) {
|
||||
if (release.length === 0) {
|
||||
return release;
|
||||
}
|
||||
|
||||
const breakpoints = release.length > 2 ? ['minor', 'major'] : ['major'];
|
||||
|
||||
// The intial bound is the last release from the base branch of `FIRST_RELEASE` (1.0.0)
|
||||
@@ -80,6 +81,7 @@ function release({release}) {
|
||||
// The upper bound is the lowest version between `nextFirstVersion` and the default upper bound
|
||||
bound = lowest(nextFirstVersion, upperBound);
|
||||
}
|
||||
|
||||
const diff = bound ? semverDiff(min, bound) : null;
|
||||
return {
|
||||
...rest,
|
||||
|
||||
+16
-31
@@ -1,10 +1,9 @@
|
||||
const url = require('url');
|
||||
const {inspect} = require('util');
|
||||
const {toLower, isString, trim} = require('lodash');
|
||||
const pkg = require('../../package.json');
|
||||
const {RELEASE_TYPE} = require('./constants');
|
||||
|
||||
const homepage = url.format({...url.parse(pkg.homepage), hash: null});
|
||||
const [homepage] = pkg.homepage.split('#');
|
||||
const stringify = obj => (isString(obj) ? obj : inspect(obj, {breakLength: Infinity, depth: 2, maxArrayLength: 5}));
|
||||
const linkify = file => `${homepage}/blob/master/${file}`;
|
||||
const wordsList = words =>
|
||||
@@ -29,11 +28,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 +38,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 +46,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'
|
||||
@@ -186,6 +183,8 @@ Your configuration for the problematic branches is \`${stringify(branches)}\`.`,
|
||||
details: `A minimum of 1 and a maximum of 3 release branches are required in the [branches configuration](${linkify(
|
||||
'docs/usage/configuration.md#branches'
|
||||
)}).
|
||||
|
||||
This may occur if your repository does not have a release branch, such as \`master\`.
|
||||
|
||||
Your configuration for the problematic branches is \`${stringify(branches)}\`.`,
|
||||
}),
|
||||
@@ -205,40 +204,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).
|
||||
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 \`${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.`,
|
||||
}),
|
||||
|
||||
@@ -59,6 +59,7 @@ module.exports = {
|
||||
// Regenerate the release notes
|
||||
context.nextRelease.notes = await generateNotes(context);
|
||||
}
|
||||
|
||||
// Call the next prepare plugin with the updated `nextRelease`
|
||||
return context;
|
||||
},
|
||||
|
||||
+2
-1
@@ -30,6 +30,7 @@ module.exports = async (context, opts) => {
|
||||
if (options.ci === false) {
|
||||
options.noCi = true;
|
||||
}
|
||||
|
||||
const pluginsPath = {};
|
||||
let extendPaths;
|
||||
({extends: extendPaths, ...options} = options);
|
||||
@@ -66,7 +67,7 @@ module.exports = async (context, opts) => {
|
||||
// Set default options values if not defined yet
|
||||
options = {
|
||||
branches: [
|
||||
'+([1-9])?(.{+([1-9]),x}).x',
|
||||
'+([0-9])?(.{+([0-9]),x}).x',
|
||||
'master',
|
||||
'next',
|
||||
'next-major',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {parse, format} = require('url');
|
||||
const {parse, format} = require('url'); // eslint-disable-line node/no-deprecated-api
|
||||
const {isNil} = require('lodash');
|
||||
const hostedGitInfo = require('hosted-git-info');
|
||||
const {verifyAuth} = require('./git');
|
||||
@@ -44,7 +44,7 @@ module.exports = async ({cwd, env, branch, options: {repositoryUrl}}) => {
|
||||
const gitCredentials = `${GIT_TOKENS[envVar] || ''}${env[envVar] || ''}`;
|
||||
|
||||
if (gitCredentials) {
|
||||
// If credentials are set via anvironment variables, convert the URL to http/https and add basic auth, otherwise return `repositoryUrl` as is
|
||||
// If credentials are set via environment variables, convert the URL to http/https and add basic auth, otherwise return `repositoryUrl` as is
|
||||
const [match, auth, host, path] = /^(?!.+:\/\/)(?:(.*)@)?(.*?):(.*)$/.exec(repositoryUrl) || [];
|
||||
return format({
|
||||
...parse(match ? `ssh://${auth ? `${auth}@` : ''}${host}/${path}` : repositoryUrl),
|
||||
|
||||
@@ -23,9 +23,9 @@ const {makeTag} = require('./utils');
|
||||
*
|
||||
* @return {LastRelease} The last tagged release or empty object if none is found.
|
||||
*/
|
||||
module.exports = ({branch: {tags, type}, options: {tagFormat}}, {before} = {}) => {
|
||||
const [{version, gitTag, gitHead, channel} = {}] = tags
|
||||
.filter(tag => type === 'prerelease' || !semver.prerelease(tag.version))
|
||||
module.exports = ({branch, options: {tagFormat}}, {before} = {}) => {
|
||||
const [{version, gitTag, gitHead, channel} = {}] = branch.tags
|
||||
.filter(tag => (branch.type === 'prerelease' && branch.channel === tag.channel) || !semver.prerelease(tag.version))
|
||||
.filter(tag => isUndefined(before) || semver.lt(tag.version, before))
|
||||
.sort((a, b) => semver.rcompare(a.version, b.version));
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -34,7 +34,7 @@ module.exports = context => {
|
||||
({channel, version}) =>
|
||||
channel === higherBranch.channel &&
|
||||
channel !== branch.channel &&
|
||||
(branch.type !== 'maintenance' || semver.gte(version, getLowerBound(branch['merge-range'])))
|
||||
(branch.type !== 'maintenance' || semver.gte(version, getLowerBound(branch.mergeRange)))
|
||||
)
|
||||
)
|
||||
// Find ones that are not released on the building branch channel
|
||||
|
||||
+15
-7
@@ -57,13 +57,14 @@ async function getCommits(from, to, execaOpts) {
|
||||
/**
|
||||
* Get all the repository branches.
|
||||
*
|
||||
* @param {String} repositoryUrl The remote repository URL.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*
|
||||
* @return {Array<String>} List of git branches.
|
||||
* @throws {Error} If the `git` command fails.
|
||||
*/
|
||||
async function getBranches(execaOpts) {
|
||||
return (await execa.stdout('git', ['ls-remote', '--heads', 'origin'], execaOpts))
|
||||
async function getBranches(repositoryUrl, execaOpts) {
|
||||
return (await execa.stdout('git', ['ls-remote', '--heads', repositoryUrl], execaOpts))
|
||||
.split('\n')
|
||||
.map(branch => branch.match(/^.+refs\/heads\/(.+)$/)[1])
|
||||
.filter(Boolean);
|
||||
@@ -99,6 +100,7 @@ async function isRefInHistory(ref, branch, findRebasedTags, execaOpts) {
|
||||
);
|
||||
return (await getBranchCommits(branch, execaOpts)).some(matches(pick(tagCommit, ['message', 'author'])));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,10 +128,11 @@ async function isRefExists(ref, execaOpts) {
|
||||
/**
|
||||
* Unshallow the git repository if necessary and fetch all the tags.
|
||||
*
|
||||
* @param {String} repositoryUrl The remote repository URL.
|
||||
* @param {String} branch The repository branch to fetch.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
async function fetch(branch, execaOpts) {
|
||||
async function fetch(repositoryUrl, branch, execaOpts) {
|
||||
const isLocalExists =
|
||||
(await execa('git', ['rev-parse', '--verify', branch], {...execaOpts, reject: false})).code === 0;
|
||||
|
||||
@@ -140,14 +143,18 @@ async function fetch(branch, execaOpts) {
|
||||
'fetch',
|
||||
'--unshallow',
|
||||
'--tags',
|
||||
...(isLocalExists ? [] : ['origin', `+refs/heads/${branch}:refs/heads/${branch}`]),
|
||||
...(isLocalExists ? [repositoryUrl] : [repositoryUrl, `+refs/heads/${branch}:refs/remotes/upstream/${branch}`]),
|
||||
],
|
||||
execaOpts
|
||||
);
|
||||
} catch (error) {
|
||||
await execa(
|
||||
'git',
|
||||
['fetch', '--tags', ...(isLocalExists ? [] : ['origin', `+refs/heads/${branch}:refs/heads/${branch}`])],
|
||||
[
|
||||
'fetch',
|
||||
'--tags',
|
||||
...(isLocalExists ? [repositoryUrl] : [repositoryUrl, `+refs/heads/${branch}:refs/remotes/upstream/${branch}`]),
|
||||
],
|
||||
execaOpts
|
||||
);
|
||||
}
|
||||
@@ -272,13 +279,14 @@ async function verifyBranchName(branch, execaOpts) {
|
||||
/**
|
||||
* Verify the local branch is up to date with the remote one.
|
||||
*
|
||||
* @param {String} repositoryUrl The remote repository URL.
|
||||
* @param {String} branch The repository branch for which to verify status.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*
|
||||
* @return {Boolean} `true` is the HEAD of the current local branch is the same as the HEAD of the remote branch, falsy otherwise.
|
||||
*/
|
||||
async function isBranchUpToDate(branch, execaOpts) {
|
||||
const remoteHead = await execa.stdout('git', ['ls-remote', '--heads', 'origin', branch], execaOpts);
|
||||
async function isBranchUpToDate(repositoryUrl, branch, execaOpts) {
|
||||
const remoteHead = await execa.stdout('git', ['ls-remote', '--heads', repositoryUrl, branch], execaOpts);
|
||||
try {
|
||||
return await isRefInHistory(remoteHead.match(/^(\w+)?/)[1], branch, false, execaOpts);
|
||||
} catch (error) {
|
||||
|
||||
@@ -57,10 +57,12 @@ module.exports = (context, pluginsPath) => {
|
||||
plugin ? [plugin[0], Object.assign(plugin[1], options[type])] : plugin
|
||||
);
|
||||
}
|
||||
|
||||
if (!validateStep({required}, options[type])) {
|
||||
errors.push(getError('EPLUGINCONF', {type, required, pluginConf: options[type]}));
|
||||
return pluginsConf;
|
||||
}
|
||||
|
||||
pluginOpts = options[type];
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,11 @@ module.exports = (context, type, pluginOpt, pluginsPath) => {
|
||||
if (outputValidator && !outputValidator(result)) {
|
||||
throw getError(`E${type.toUpperCase()}OUTPUT`, {result, pluginName});
|
||||
}
|
||||
|
||||
logger.success(`Completed step "${type}" of plugin "${pluginName}"`);
|
||||
return result;
|
||||
}
|
||||
|
||||
logger.warn(`Skip step "${type}" of plugin "${pluginName}" in dry-run mode`);
|
||||
} catch (error) {
|
||||
logger.error(`Failed step "${type}" of plugin "${pluginName}"`);
|
||||
|
||||
@@ -4,7 +4,7 @@ const AggregateError = require('aggregate-error');
|
||||
const {extractErrors} = require('../utils');
|
||||
|
||||
/**
|
||||
* A Function that execute a list of function sequencially. If at least one Function ins the pipeline throw an Error or rejects, the pipeline function rejects as well.
|
||||
* A Function that execute a list of function sequencially. If at least one Function ins the pipeline throws an Error or rejects, the pipeline function rejects as well.
|
||||
*
|
||||
* @typedef {Function} Pipeline
|
||||
* @param {Any} input Argument to pass to the first step in the pipeline.
|
||||
@@ -44,6 +44,7 @@ module.exports = (steps, {settleAll = false, getNextInput = identity, transform
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare input for the next step, passing the input of the last iteration (or initial parameter for the first iteration) and the result of the current one
|
||||
return getNextInput(lastInput, result);
|
||||
},
|
||||
@@ -52,5 +53,6 @@ module.exports = (steps, {settleAll = false, getNextInput = identity, transform
|
||||
if (errors.length > 0) {
|
||||
throw new AggregateError(errors);
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ const validateSteps = conf => {
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
conf = castArray(conf);
|
||||
|
||||
if (conf.length !== 1) {
|
||||
@@ -39,6 +40,7 @@ function validateStep({required}, conf) {
|
||||
if (required) {
|
||||
return conf.length >= 1 && validateSteps(conf);
|
||||
}
|
||||
|
||||
return conf.length === 0 || validateSteps(conf);
|
||||
}
|
||||
|
||||
@@ -59,6 +61,7 @@ function parseConfig(plugin) {
|
||||
} else {
|
||||
path = plugin;
|
||||
}
|
||||
|
||||
return [path, config || {}];
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ function getFirstVersion(versions, lowerBranches) {
|
||||
if (lowerVersion[0]) {
|
||||
return versions.sort(semver.compare).find(version => semver.gt(version, lowerVersion[0]));
|
||||
}
|
||||
|
||||
return getEarliestVersion(versions);
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -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 => {
|
||||
|
||||
+7
-7
@@ -21,10 +21,10 @@
|
||||
"dependencies": {
|
||||
"@semantic-release/commit-analyzer": "^7.0.0-beta.1",
|
||||
"@semantic-release/error": "^2.2.0",
|
||||
"@semantic-release/github": "^5.3.0-beta.5",
|
||||
"@semantic-release/npm": "^5.2.0-beta.4",
|
||||
"@semantic-release/github": "^5.4.0-beta.1",
|
||||
"@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",
|
||||
@@ -36,8 +36,8 @@
|
||||
"hook-std": "^1.1.0",
|
||||
"hosted-git-info": "^2.7.1",
|
||||
"lodash": "^4.17.4",
|
||||
"marked": "^0.5.0",
|
||||
"marked-terminal": "^3.0.0",
|
||||
"marked": "^0.6.0",
|
||||
"marked-terminal": "^3.2.0",
|
||||
"micromatch": "3.1.5",
|
||||
"p-each-series": "^1.0.0",
|
||||
"p-reduce": "^1.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",
|
||||
@@ -68,7 +68,7 @@
|
||||
"sinon": "^7.1.1",
|
||||
"stream-buffers": "^3.0.2",
|
||||
"tempy": "^0.2.1",
|
||||
"xo": "^0.23.0"
|
||||
"xo": "^0.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.3"
|
||||
|
||||
@@ -24,7 +24,7 @@ test('Enforce ranges with branching release workflow', async t => {
|
||||
];
|
||||
const getBranches = proxyquire('../../lib/branches', {'./get-tags': () => branches, './expand': () => []});
|
||||
|
||||
let result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
let result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, '1.0.x').range, '>=1.0.0 <1.0.0', 'Cannot release on 1.0.x before a releasing on master');
|
||||
t.is(getBranch(result, '1.x').range, '>=1.1.0 <1.0.0', 'Cannot release on 1.x before a releasing on master');
|
||||
t.is(getBranch(result, 'master').range, '>=1.0.0 <1.1.0', 'Can release only patch on master');
|
||||
@@ -32,43 +32,43 @@ test('Enforce ranges with branching release workflow', async t => {
|
||||
t.is(getBranch(result, 'next-major').range, '>=2.0.0', 'Can release only major on next-major');
|
||||
|
||||
release(branches, 'master', '1.0.0');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, '1.0.x').range, '>=1.0.0 <1.0.0', 'Cannot release on 1.0.x before a releasing on master');
|
||||
t.is(getBranch(result, '1.x').range, '>=1.1.0 <1.0.0', 'Cannot release on 1.x before a releasing on master');
|
||||
t.is(getBranch(result, 'master').range, '>=1.0.0 <1.1.0', 'Can release only patch on master');
|
||||
|
||||
release(branches, 'master', '1.0.1');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'master').range, '>=1.0.1 <1.1.0', 'Can release only patch, > than 1.0.1 on master');
|
||||
|
||||
merge(branches, 'master', 'next');
|
||||
merge(branches, 'master', 'next-major');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'master').range, '>=1.0.1 <1.1.0', 'Can release only patch, > than 1.0.1 on master');
|
||||
t.is(getBranch(result, 'next').range, '>=1.1.0 <2.0.0', 'Can release only minor on next');
|
||||
t.is(getBranch(result, 'next-major').range, '>=2.0.0', 'Can release only major on next-major');
|
||||
|
||||
release(branches, 'next', '1.1.0');
|
||||
release(branches, 'next', '1.1.1');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'next').range, '>=1.1.1 <2.0.0', 'Can release only patch or minor, > than 1.1.0 on next');
|
||||
|
||||
release(branches, 'next-major', '2.0.0');
|
||||
release(branches, 'next-major', '2.0.1');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'next-major').range, '>=2.0.1', 'Can release any version, > than 2.0.1 on next-major');
|
||||
|
||||
merge(branches, 'next-major', 'beta');
|
||||
release(branches, 'beta', '3.0.0-beta.1');
|
||||
merge(branches, 'beta', 'alpha');
|
||||
release(branches, 'alpha', '4.0.0-alpha.1');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'next-major').range, '>=2.0.1', 'Can release any version, > than 2.0.1 on next-major');
|
||||
|
||||
merge(branches, 'master', '1.0.x');
|
||||
merge(branches, 'master', '1.x');
|
||||
release(branches, 'master', '1.0.1');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'master').range, '>=1.0.1 <1.1.0', 'Can release only patch, > than 1.0.1 on master');
|
||||
t.is(
|
||||
getBranch(result, '1.0.x').range,
|
||||
@@ -80,7 +80,7 @@ test('Enforce ranges with branching release workflow', async t => {
|
||||
release(branches, 'master', '1.0.2');
|
||||
release(branches, 'master', '1.0.3');
|
||||
release(branches, 'master', '1.0.4');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'master').range, '>=1.0.4 <1.1.0', 'Can release only patch, > than 1.0.4 on master');
|
||||
t.is(
|
||||
getBranch(result, '1.0.x').range,
|
||||
@@ -90,7 +90,7 @@ test('Enforce ranges with branching release workflow', async t => {
|
||||
t.is(getBranch(result, '1.x').range, '>=1.1.0 <1.0.2', 'Cannot release on 1.x before >= 1.2.0 is released on master');
|
||||
|
||||
merge(branches, 'next', 'master');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'master').range, '>=1.1.1 <1.2.0', 'Can release only patch, > than 1.1.1 on master');
|
||||
t.is(getBranch(result, 'next').range, '>=1.2.0 <2.0.0', 'Can release only patch or minor, > than 1.2.0 on next');
|
||||
t.is(getBranch(result, 'next-major').range, '>=2.0.1', 'Can release any version, > than 2.0.1 on next-major');
|
||||
@@ -102,34 +102,34 @@ test('Enforce ranges with branching release workflow', async t => {
|
||||
t.is(getBranch(result, '1.x').range, '>=1.1.0 <1.0.2', 'Cannot release on 1.x before >= 2.0.0 is released on master');
|
||||
|
||||
merge(branches, 'master', '1.0.x', '1.0.4');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'master').range, '>=1.1.1 <1.2.0', 'Can release only patch, > than 1.1.1 on master');
|
||||
t.is(getBranch(result, '1.0.x').range, '>=1.0.4 <1.1.0', 'Can release on 1.0.x only within range');
|
||||
t.is(getBranch(result, '1.x').range, '>=1.1.0 <1.1.0', 'Cannot release on 1.x before >= 2.0.0 is released on master');
|
||||
|
||||
merge(branches, 'master', '1.x');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'master').range, '>=1.1.1 <1.2.0', 'Can release only patch, > than 1.1.1 on master');
|
||||
t.is(getBranch(result, '1.0.x').range, '>=1.0.4 <1.1.0', 'Can release on 1.0.x only within range');
|
||||
t.is(getBranch(result, '1.x').range, '>=1.1.1 <1.1.1', 'Cannot release on 1.x before >= 2.0.0 is released on master');
|
||||
|
||||
merge(branches, 'next-major', 'next');
|
||||
merge(branches, 'next', 'master');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'master').range, '>=2.0.1 <2.1.0', 'Can release only patch, > than 2.0.1 on master');
|
||||
t.is(getBranch(result, 'next').range, '>=2.1.0 <3.0.0', 'Can release only minor on next');
|
||||
t.is(getBranch(result, 'next-major').range, '>=3.0.0', 'Can release only major on next-major');
|
||||
t.is(getBranch(result, '1.x').range, '>=1.1.1 <2.0.0', 'Can release on 1.x only within range');
|
||||
|
||||
merge(branches, 'beta', 'master');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, 'master').range, '>=2.0.1 <2.1.0', 'Can release only patch, > than 2.0.1 on master');
|
||||
t.is(getBranch(result, 'next').range, '>=2.1.0 <3.0.0', 'Can release only minor on next');
|
||||
t.is(getBranch(result, 'next-major').range, '>=3.0.0', 'Can release only major on next-major');
|
||||
|
||||
branches.push({name: '1.1.x', tags: []});
|
||||
merge(branches, '1.x', '1.1.x');
|
||||
result = (await getBranches({options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
result = (await getBranches('repositoryUrl', {options: {branches}})).map(({name, range}) => ({name, range}));
|
||||
t.is(getBranch(result, '1.0.x').range, '>=1.0.4 <1.1.0', 'Can release on 1.0.x only within range');
|
||||
t.is(getBranch(result, '1.1.x').range, '>=1.1.1 <1.2.0', 'Can release on 1.1.x only within range');
|
||||
t.is(getBranch(result, '1.x').range, '>=1.2.0 <2.0.0', 'Can release on 1.x only within range');
|
||||
@@ -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('repositoryUrl', {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('repositoryUrl', {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('repositoryUrl', {options: {branches}})))];
|
||||
|
||||
t.is(errors[0].name, 'SemanticReleaseError');
|
||||
t.is(errors[0].code, 'EINVALIDBRANCHNAME');
|
||||
|
||||
@@ -6,9 +6,9 @@ test('Expand branches defined with globs', async t => {
|
||||
const {cwd, repositoryUrl} = await gitRepo(true);
|
||||
await gitCommits(['First'], {cwd});
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
await gitCheckout('1.1.x', true, {cwd});
|
||||
await gitCheckout('1.0.x', true, {cwd});
|
||||
await gitCommits(['Second'], {cwd});
|
||||
await gitPush(repositoryUrl, '1.1.x', {cwd});
|
||||
await gitPush(repositoryUrl, '1.0.x', {cwd});
|
||||
await gitCheckout('1.x.x', true, {cwd});
|
||||
await gitCommits(['Third'], {cwd});
|
||||
await gitPush(repositoryUrl, '1.x.x', {cwd});
|
||||
@@ -30,7 +30,7 @@ test('Expand branches defined with globs', async t => {
|
||||
|
||||
const branches = [
|
||||
// Should match all maintenance type branches
|
||||
{name: '+([1-9])?(.{+([1-9]),x}).x'},
|
||||
{name: '+([0-9])?(.{+([0-9]),x}).x'},
|
||||
{name: 'master', channel: 'latest'},
|
||||
{name: 'next'},
|
||||
{name: 'pre/{foo,bar}', channel: `\${name.replace(/^pre\\//g, '')}`, prerelease: true},
|
||||
@@ -41,8 +41,8 @@ test('Expand branches defined with globs', async t => {
|
||||
{name: 'beta', channel: `channel-\${name}`, prerelease: true},
|
||||
];
|
||||
|
||||
t.deepEqual(await expand({cwd}, branches), [
|
||||
{name: '1.1.x'},
|
||||
t.deepEqual(await expand(repositoryUrl, {cwd}, branches), [
|
||||
{name: '1.0.x'},
|
||||
{name: '1.x.x'},
|
||||
{name: '2.x'},
|
||||
{name: 'master', channel: 'latest'},
|
||||
|
||||
@@ -7,16 +7,14 @@ test('Maintenance branches - initial state', t => {
|
||||
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,7 +137,7 @@ 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',
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
@@ -36,7 +36,7 @@ test('Default values, reading repositoryUrl from package.json', async t => {
|
||||
|
||||
// Verify the default options are set
|
||||
t.deepEqual(result.branches, [
|
||||
'+([1-9])?(.{+([1-9]),x}).x',
|
||||
'+([0-9])?(.{+([0-9]),x}).x',
|
||||
'master',
|
||||
'next',
|
||||
'next-major',
|
||||
@@ -57,7 +57,7 @@ test('Default values, reading repositoryUrl from repo if not set in package.json
|
||||
|
||||
// Verify the default options are set
|
||||
t.deepEqual(result.branches, [
|
||||
'+([1-9])?(.{+([1-9]),x}).x',
|
||||
'+([0-9])?(.{+([0-9]),x}).x',
|
||||
'master',
|
||||
'next',
|
||||
'next-major',
|
||||
@@ -79,7 +79,7 @@ test('Default values, reading repositoryUrl (http url) from package.json if not
|
||||
|
||||
// Verify the default options are set
|
||||
t.deepEqual(result.branches, [
|
||||
'+([1-9])?(.{+([1-9]),x}).x',
|
||||
'+([0-9])?(.{+([0-9]),x}).x',
|
||||
'master',
|
||||
'next',
|
||||
'next-major',
|
||||
@@ -511,8 +511,8 @@ 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.regex(error.message, /Cannot find module 'non-existing-path'/);
|
||||
t.is(error.code, 'MODULE_NOT_FOUND');
|
||||
});
|
||||
|
||||
@@ -18,6 +18,31 @@ test('Get the highest non-prerelease valid tag', t => {
|
||||
t.deepEqual(result, {version: '2.0.0', gitTag: 'v2.0.0', name: 'v2.0.0', gitHead: '222', channel: undefined});
|
||||
});
|
||||
|
||||
test('Get the highest prerelease valid tag, ignoring other tags from other prerelease channels', t => {
|
||||
const result = getLastRelease({
|
||||
branch: {
|
||||
name: 'beta',
|
||||
prerelease: 'beta',
|
||||
channel: 'beta',
|
||||
tags: [
|
||||
{version: '1.0.0-beta.1', gitTag: 'v1.0.0-beta.1@beta', gitHead: '111', channel: 'beta'},
|
||||
{version: '1.0.0-beta.2', gitTag: 'v1.0.0-beta.2@beta', gitHead: '222', channel: 'beta'},
|
||||
{version: '1.0.0-alpha.1', gitTag: 'v1.0.0-alpha.1@alpha', gitHead: '333', channel: 'alpha'},
|
||||
],
|
||||
type: 'prerelease',
|
||||
},
|
||||
options: {tagFormat: `v\${version}`},
|
||||
});
|
||||
|
||||
t.deepEqual(result, {
|
||||
version: '1.0.0-beta.2',
|
||||
gitTag: 'v1.0.0-beta.2@beta',
|
||||
name: 'v1.0.0-beta.2',
|
||||
gitHead: '222',
|
||||
channel: 'beta',
|
||||
});
|
||||
});
|
||||
|
||||
test('Return empty object if no valid tag is found', t => {
|
||||
const result = getLastRelease({
|
||||
branch: {
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -7,7 +7,7 @@ test('Return versions merged from release to maintenance branch, excluding lower
|
||||
name: '2.x',
|
||||
channel: '2.x',
|
||||
type: 'maintenance',
|
||||
'merge-range': '>=2.0.0 <3.0.0',
|
||||
mergeRange: '>=2.0.0 <3.0.0',
|
||||
tags: [
|
||||
{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'},
|
||||
@@ -255,7 +255,7 @@ test('Exclude versions merged from release to maintenance branch if they have th
|
||||
name: '2.x',
|
||||
channel: 'latest',
|
||||
type: 'maintenance',
|
||||
'merge-range': '>=2.0.0 <3.0.0',
|
||||
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'},
|
||||
|
||||
+12
-12
@@ -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 => {
|
||||
@@ -58,7 +58,7 @@ test('Unshallow and fetch repository', async t => {
|
||||
// Verify the shallow clone contains only one commit
|
||||
t.is((await gitGetCommits(undefined, {cwd})).length, 1);
|
||||
|
||||
await fetch('master', {cwd});
|
||||
await fetch(repositoryUrl, 'master', {cwd});
|
||||
|
||||
// Verify the shallow clone contains all the commits
|
||||
t.is((await gitGetCommits(undefined, {cwd})).length, 2);
|
||||
@@ -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(repositoryUrl, 'master', {cwd}));
|
||||
await t.notThrowsAsync(fetch(repositoryUrl, 'second-branch', {cwd}));
|
||||
});
|
||||
|
||||
test('Fetch all tags on a detached head repository', async t => {
|
||||
@@ -89,7 +89,7 @@ test('Fetch all tags on a detached head repository', async t => {
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
cwd = await gitDetachedHead(repositoryUrl, commit.hash);
|
||||
|
||||
await fetch('master', {cwd});
|
||||
await fetch(repositoryUrl, 'master', {cwd});
|
||||
|
||||
t.deepEqual((await getTags({cwd})).sort(), ['v1.0.0', 'v1.0.1', 'v1.1.0'].sort());
|
||||
});
|
||||
@@ -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 => {
|
||||
@@ -137,7 +137,7 @@ test('Get all branches', async t => {
|
||||
await gitCommits(['Third'], {cwd});
|
||||
await gitPush(repositoryUrl, 'third-branch', {cwd});
|
||||
|
||||
t.deepEqual((await getBranches({cwd})).sort(), ['master', 'second-branch', 'third-branch'].sort());
|
||||
t.deepEqual((await getBranches(repositoryUrl, {cwd})).sort(), ['master', 'second-branch', 'third-branch'].sort());
|
||||
});
|
||||
|
||||
test('Get the commit sha for a given tag or falsy if the tag does not 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 => {
|
||||
@@ -251,7 +251,7 @@ test('Return "true" if repository is up to date', async t => {
|
||||
await gitCommits(['First'], {cwd});
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
|
||||
t.true(await isBranchUpToDate('master', {cwd}));
|
||||
t.true(await isBranchUpToDate(repositoryUrl, 'master', {cwd}));
|
||||
});
|
||||
|
||||
test('Return falsy if repository is not up to date', async t => {
|
||||
@@ -260,13 +260,13 @@ test('Return falsy if repository is not up to date', async t => {
|
||||
await gitCommits(['Second'], {cwd});
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
|
||||
t.true(await isBranchUpToDate('master', {cwd}));
|
||||
t.true(await isBranchUpToDate(repositoryUrl, 'master', {cwd}));
|
||||
|
||||
const tmpRepo = await gitShallowClone(repositoryUrl);
|
||||
await gitCommits(['Third'], {cwd: tmpRepo});
|
||||
await gitPush('origin', 'master', {cwd: tmpRepo});
|
||||
|
||||
t.falsy(await isBranchUpToDate('master', {cwd}));
|
||||
t.falsy(await isBranchUpToDate(repositoryUrl, 'master', {cwd}));
|
||||
});
|
||||
|
||||
test('Return "true" if local repository is ahead', async t => {
|
||||
@@ -275,5 +275,5 @@ test('Return "true" if local repository is ahead', async t => {
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
await gitCommits(['Second'], {cwd});
|
||||
|
||||
t.true(await isBranchUpToDate('master', {cwd}));
|
||||
t.true(await isBranchUpToDate(repositoryUrl, 'master', {cwd}));
|
||||
});
|
||||
|
||||
+33
-26
@@ -83,7 +83,7 @@ test('Plugins are called with expected values', async t => {
|
||||
const prepare = stub().resolves();
|
||||
const publish = stub().resolves(release2);
|
||||
const success = stub().resolves();
|
||||
const env = {...process.env};
|
||||
const env = {};
|
||||
const config = {
|
||||
branches: [{name: 'master'}, {name: 'next'}],
|
||||
repositoryUrl,
|
||||
@@ -131,9 +131,9 @@ test('Plugins are called with expected values', async t => {
|
||||
channel: undefined,
|
||||
gitTag: 'v1.0.0',
|
||||
notes: `${notes1}\n\n${notes2}\n\n${notes3}`,
|
||||
pluginName: '[Function: proxy]',
|
||||
pluginName: '[Function: functionStub]',
|
||||
},
|
||||
{...nextRelease, ...release2, notes: `${notes1}\n\n${notes2}\n\n${notes3}`, pluginName: '[Function: proxy]'},
|
||||
{...nextRelease, ...release2, notes: `${notes1}\n\n${notes2}\n\n${notes3}`, pluginName: '[Function: functionStub]'},
|
||||
{...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`, pluginName: pluginNoop},
|
||||
];
|
||||
|
||||
@@ -353,7 +353,7 @@ test('Plugins are called with expected values', async t => {
|
||||
|
||||
t.deepEqual(result, {
|
||||
lastRelease,
|
||||
commits: [{...commits[0], gitTags: '(HEAD -> master, origin/master, origin/HEAD, next)'}],
|
||||
commits: [{...commits[0], gitTags: '(HEAD -> master, next)'}],
|
||||
nextRelease: {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`},
|
||||
releases,
|
||||
});
|
||||
@@ -562,7 +562,7 @@ test('Publish a pre-release version', async t => {
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'beta', isPr: false}),
|
||||
});
|
||||
let {releases} = await semanticRelease(options, {cwd, stdout: {write: () => {}}, stderr: {write: () => {}}});
|
||||
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');
|
||||
@@ -571,6 +571,7 @@ test('Publish a pre-release version', async t => {
|
||||
await gitCommits(['fix: a fix'], {cwd});
|
||||
({releases} = await semanticRelease(options, {
|
||||
cwd,
|
||||
env: {},
|
||||
stdout: {write: () => {}},
|
||||
stderr: {write: () => {}},
|
||||
}));
|
||||
@@ -694,10 +695,10 @@ async function addChannelMacro(t, mergeFunction) {
|
||||
const result = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}});
|
||||
|
||||
t.deepEqual(result.releases, [
|
||||
{...nextRelease1, ...release1, notes, pluginName: '[Function: proxy]'},
|
||||
{...nextRelease1, notes, pluginName: '[Function: proxy]'},
|
||||
{...nextRelease2, ...release1, notes, pluginName: '[Function: proxy]'},
|
||||
{...nextRelease2, notes, pluginName: '[Function: proxy]'},
|
||||
{...nextRelease1, ...release1, notes, pluginName: '[Function: functionStub]'},
|
||||
{...nextRelease1, notes, pluginName: '[Function: functionStub]'},
|
||||
{...nextRelease2, ...release1, notes, pluginName: '[Function: functionStub]'},
|
||||
{...nextRelease2, notes, pluginName: '[Function: functionStub]'},
|
||||
]);
|
||||
|
||||
// Verify the tag has been created on the local and remote repo and reference
|
||||
@@ -763,16 +764,20 @@ 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()})
|
||||
);
|
||||
|
||||
t.is(success1.callCount, 1);
|
||||
t.deepEqual(success1.args[0][0], config);
|
||||
t.deepEqual(success1.args[0][1].releases, [{...nextRelease, ...release, notes, pluginName: '[Function: proxy]'}]);
|
||||
t.deepEqual(success1.args[0][1].releases, [
|
||||
{...nextRelease, ...release, notes, pluginName: '[Function: functionStub]'},
|
||||
]);
|
||||
|
||||
t.is(success2.callCount, 1);
|
||||
t.deepEqual(success2.args[0][1].releases, [{...nextRelease, ...release, notes, pluginName: '[Function: proxy]'}]);
|
||||
t.deepEqual(success2.args[0][1].releases, [
|
||||
{...nextRelease, ...release, notes, pluginName: '[Function: functionStub]'},
|
||||
]);
|
||||
});
|
||||
|
||||
test('Log all "verifyConditions" errors', async t => {
|
||||
@@ -799,7 +804,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 +849,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 +954,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()})
|
||||
)),
|
||||
];
|
||||
@@ -1202,8 +1207,8 @@ test('Accept "undefined" value returned by "generateNotes" and "false" by "publi
|
||||
t.is(publish.callCount, 1);
|
||||
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]'}]);
|
||||
t.deepEqual(success.args[0][1].releases, [{pluginName: '[Function: functionStub]'}]);
|
||||
t.deepEqual(success.args[1][1].releases, [{pluginName: '[Function: functionStub]'}]);
|
||||
});
|
||||
|
||||
test('Returns false if triggered by a PR', async t => {
|
||||
@@ -1268,7 +1273,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 +1324,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 +1393,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);
|
||||
@@ -1397,7 +1404,7 @@ test('Throws "EINVALIDMAINTENANCEMERGE" if merge an out of range release in a ma
|
||||
t.is(publish.callCount, 0);
|
||||
|
||||
t.is(success.callCount, 1);
|
||||
t.deepEqual(success.args[0][1].releases, [{...nextRelease, notes, pluginName: '[Function: proxy]'}]);
|
||||
t.deepEqual(success.args[0][1].releases, [{...nextRelease, notes, pluginName: '[Function: functionStub]'}]);
|
||||
|
||||
t.is(fail.callCount, 1);
|
||||
t.deepEqual(fail.args[0][1].errors, errors);
|
||||
@@ -1587,7 +1594,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 +1619,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 +1636,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 +1675,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 +1705,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
|
||||
);
|
||||
|
||||
@@ -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/);
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
@@ -273,6 +273,6 @@ test('Throws an error if the plugin is not found', t => {
|
||||
Error
|
||||
);
|
||||
|
||||
t.is(error.message, "Cannot find module 'non-existing-path'");
|
||||
t.regex(error.message, /Cannot find module 'non-existing-path'/);
|
||||
t.is(error.code, 'MODULE_NOT_FOUND');
|
||||
});
|
||||
|
||||
@@ -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));
|
||||
|
||||
+7
-7
@@ -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}));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user