Compare commits
15
Commits
@@ -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
|
||||
|
||||
+1
-1
@@ -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.
|
||||
|
||||
|
||||
@@ -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,6 +82,7 @@ async function run(context, plugins) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 =>
|
||||
@@ -184,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)}\`.`,
|
||||
}),
|
||||
@@ -211,8 +212,8 @@ The following commit${commits.length > 1 ? 's are' : ' is'} responsible for the
|
||||
${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 \`${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}\``))}.
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
+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/heads/${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/heads/${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);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -21,7 +21,7 @@
|
||||
"dependencies": {
|
||||
"@semantic-release/commit-analyzer": "^7.0.0-beta.1",
|
||||
"@semantic-release/error": "^2.2.0",
|
||||
"@semantic-release/github": "^5.3.0-beta.6",
|
||||
"@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": "^2.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",
|
||||
@@ -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.throwsAsync(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.throwsAsync(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.throwsAsync(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'},
|
||||
|
||||
@@ -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',
|
||||
@@ -513,6 +513,6 @@ test('Throw an Error if one of the shareable config cannot be found', async t =>
|
||||
|
||||
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: {
|
||||
|
||||
+9
-9
@@ -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.notThrowsAsync(fetch('master', {cwd}));
|
||||
await t.notThrowsAsync(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());
|
||||
});
|
||||
@@ -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 => {
|
||||
@@ -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}));
|
||||
});
|
||||
|
||||
+19
-14
@@ -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
|
||||
@@ -769,10 +770,14 @@ test('Call all "success" plugins even if one errors out', async t => {
|
||||
|
||||
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 => {
|
||||
@@ -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 => {
|
||||
@@ -1399,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);
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user