Compare commits
43
Commits
+7
-32
@@ -1,36 +1,11 @@
|
||||
language: node_js
|
||||
version: ~> 1.0
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
node_js:
|
||||
- 12
|
||||
- 10
|
||||
- 8.16
|
||||
|
||||
# Trigger a push build on release and greenkeeper branches + PRs build on every branches
|
||||
# Avoid double build on PRs (See https://github.com/travis-ci/travis-ci/issues/1147)
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- next
|
||||
- beta
|
||||
- /^\d+\.(\d+|x)(\.x)?$/
|
||||
- /^greenkeeper.*$/
|
||||
|
||||
# Retry install on fail to avoid failing a build on network/disk/external errors
|
||||
install:
|
||||
- travis_retry npm install
|
||||
|
||||
script:
|
||||
- npm run test
|
||||
|
||||
after_success:
|
||||
- npm run codecov
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: release
|
||||
node_js: lts/*
|
||||
script:
|
||||
- npm run semantic-release
|
||||
import:
|
||||
- .travis/node.yml
|
||||
- .travis/node-versions.yml
|
||||
- .travis/semantic-release.yml
|
||||
- .travis/greenkeeper.yml
|
||||
- .travis/codecov.yml
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
after_success:
|
||||
- npm run codecov
|
||||
@@ -0,0 +1,3 @@
|
||||
branches:
|
||||
only:
|
||||
- /^greenkeeper.*$/
|
||||
@@ -0,0 +1,3 @@
|
||||
node_js:
|
||||
- 12
|
||||
- 10.18
|
||||
@@ -0,0 +1,11 @@
|
||||
language: node_js
|
||||
|
||||
cache:
|
||||
npm: false
|
||||
|
||||
# Retry install on fail to avoid failing a build on network/disk/external errors
|
||||
install:
|
||||
- travis_retry npm install
|
||||
|
||||
script:
|
||||
- npm run test
|
||||
@@ -0,0 +1,15 @@
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- next
|
||||
- beta
|
||||
- /^\d+\.(\d+|x)(\.x)?$/
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: release
|
||||
node_js: lts/*
|
||||
install:
|
||||
- travis_retry npm install
|
||||
script:
|
||||
- npm run semantic-release
|
||||
@@ -101,7 +101,7 @@ In order to use **semantic-release** you need:
|
||||
- To host your code in a [Git repository](https://git-scm.com)
|
||||
- Use a Continuous Integration service that allows you to [securely set up credentials](docs/usage/ci-configuration.md#authentication)
|
||||
- Git CLI version [2.7.1 or higher](docs/support/FAQ.md#why-does-semantic-release-require-git-version--271) installed in your Continuous Integration environment
|
||||
- [Node.js](https://nodejs.org) version [8.16.0 or higher](docs/support/FAQ.md#why-does-semantic-release-require-node-version--816) installed in your Continuous Integration environment
|
||||
- [Node.js](https://nodejs.org) version [10.18 or higher](docs/support/FAQ.md#why-does-semantic-release-require-node-version--1018) installed in your Continuous Integration environment
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ execa('git', ['--version'])
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Node 8+ from this point on
|
||||
// Node 10+ from this point on
|
||||
require('../cli')()
|
||||
.then(exitCode => {
|
||||
process.exitCode = exitCode;
|
||||
|
||||
@@ -65,10 +65,10 @@
|
||||
- `verifyConditions`: Verify the presence of the authentication (set via environment variables)
|
||||
- `prepare`: Write the correct version to the `manifest.json` and creates a zip file of the whole dist folder
|
||||
- `publish`: Uploads the generated zip file to the webstore, and publish the item
|
||||
- [semantic-release-firefox](https://github.com/felixfbecker/semantic-release-firefox)
|
||||
- `verifyConditions`: Verify the presence of the authentication (set via environment variables)
|
||||
- `prepare`: Write the correct version to the `manifest.json`, creates a `xpi` file of the dist folder and a zip of the sources
|
||||
- `publish`: Submit the generated archives to the webstore for review, and publish the item including release notes
|
||||
- [semantic-release-firefox-add-on](https://github.com/tophat/semantic-release-firefox-add-on)
|
||||
- `verifyConditions`: Verify that all required options are present and authentication is set via environment variables
|
||||
- `prepare`: Write the correct version to the `manifest.json`
|
||||
- `publish`: Creates an unsigned `.xpi` file, and submits it to the Mozilla Add On store for signing. Once the package is signed, downloads the signed `.xpi` to a local directory
|
||||
- [semantic-release-gerrit](https://github.com/pascalMN/semantic-release-gerrit)
|
||||
- `generateNotes`: Generate release notes with Gerrit reviews URL
|
||||
- [semantic-release-expo](https://github.com/bycedric/semantic-release-expo)
|
||||
@@ -95,3 +95,7 @@
|
||||
- `verifyConditions`: Checks the project.clj is syntactically valid.
|
||||
- `prepare`: Update the project.clj version and package the output jar file.
|
||||
- `publish`: Publish the jar (and generated Maven metadata) to a maven repository (or clojars).
|
||||
- [@saithodev/semantic-release-gitea](https://github.com/saitho/semantic-release-gitea)
|
||||
- `verifyConditions`: Verify the presence and the validity of the authentication and the assets option configuration.
|
||||
- `publish`: Publish a Gitea release, optionally uploading file assets.
|
||||
- `addChannel`: Update a Gitea release's pre-release field.
|
||||
|
||||
@@ -10,7 +10,7 @@ In this example an [`NPM_TOKEN`](https://docs.npmjs.com/creating-and-viewing-aut
|
||||
|
||||
[GitHub Actions](https://github.com/features/actions) support [Workflows](https://help.github.com/en/articles/configuring-workflows), allowing to run tests on multiple Node versions and publish a release only when all test pass.
|
||||
|
||||
**Note**: The publish pipeline must run on [Node version >= 8.16](../support/FAQ.md#why-does-semantic-release-require-node-version--816).
|
||||
**Note**: The publish pipeline must run on [Node version >= 10.18](../support/FAQ.md#why-does-semantic-release-require-node-version--1018).
|
||||
|
||||
### `.github/workflows/release.yml` configuration for Node projects
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ The [Authentication](../usage/ci-configuration.md#authentication) environment va
|
||||
|
||||
GitLab CI supports [Pipelines](https://docs.gitlab.com/ee/ci/pipelines.html) allowing to test on multiple Node versions and publishing a release only when all test pass.
|
||||
|
||||
**Note**: The publish pipeline must run a [Node >= 8.16 version](../support/FAQ.md#why-does-semantic-release-require-node-version--816).
|
||||
**Note**: The publish pipeline must run a [Node >= 10.18 version](../support/FAQ.md#why-does-semantic-release-require-node-version--1018).
|
||||
|
||||
### `.gitlab-ci.yml` configuration for Node projects
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ The Git history of the repository is now:
|
||||
|
||||
We can now start to work on a new future major release, version `4.0.0`, on the `@beta` distribution channel.
|
||||
|
||||
To do so we fist need to update the `beta` branch with all the changes from `master` (the commits `fix: a fix`). As `beta` and `master` branches have diverged, this merge might require to resolve conflicts.
|
||||
To do so we first need to update the `beta` branch with all the changes from `master` (the commits `fix: a fix`). As `beta` and `master` branches have diverged, this merge might require to resolve conflicts.
|
||||
|
||||
We can now commit our new feature on `beta`. When pushing that commit, **semantic-release** will publish the pre-release version `3.1.0-beta.1` on the dist-tag `@beta`. That allow us to run integration tests by installing our module with `npm install example-module@beta`. Other users installing with `npm install example-module` will still receive the version `3.0.0`.
|
||||
|
||||
|
||||
@@ -92,4 +92,6 @@ jobs:
|
||||
# Use nvm to install and use the Node LTS version (nvm is installed on all Travis images)
|
||||
- nvm install lts/*
|
||||
- npx semantic-release
|
||||
on:
|
||||
all_branches: true
|
||||
```
|
||||
|
||||
+5
-5
@@ -38,7 +38,7 @@ Yes with the [dry-run options](../usage/configuration.md#dryrun) which prints to
|
||||
|
||||
## Can I use semantic-release with Yarn?
|
||||
|
||||
If you are using a [local](../usage/installation.md#local-installation) **semantic-release** installation and run multiple CI jobs with different versions, the `yarn install` command will fail on jobs running with Node < 8 as **semantic-release** requires [Node >= 8.16](#why-does-semantic-release-require-node-version--816) and specifies it in its `package.json`s [`engines`](https://docs.npmjs.com/files/package.json#engines) key.
|
||||
If you are using a [local](../usage/installation.md#local-installation) **semantic-release** installation and run multiple CI jobs with different versions, the `yarn install` command will fail on jobs running with Node < 8 as **semantic-release** requires [Node >= 10.18](#why-does-semantic-release-require-node-version--1018) and specifies it in its `package.json`s [`engines`](https://docs.npmjs.com/files/package.json#engines) key.
|
||||
|
||||
The recommended solution is to use the [Yarn](https://yarnpkg.com) [--ignore-engines](https://yarnpkg.com/en/docs/cli/install#toc-yarn-install-ignore-engines) option to install the project dependencies on the CI environment, so Yarn will ignore the **semantic-release**'s `engines` key:
|
||||
|
||||
@@ -48,7 +48,7 @@ $ yarn install --ignore-engines
|
||||
|
||||
**Note**: Several CI services use Yarn by default if your repository contains a `yarn.lock` file. So you should override the install step to specify `yarn install --ignore-engines`.
|
||||
|
||||
Alternatively you can use a [global](../usage/installation.md#global-installation) **semantic-release** installation and make sure to install and run the `semantic-release` command only in a CI jobs running with Node >= 8.16.
|
||||
Alternatively you can use a [global](../usage/installation.md#global-installation) **semantic-release** installation and make sure to install and run the `semantic-release` command only in a CI jobs running with Node >= 10.18.
|
||||
|
||||
If your CI environment provides [nvm](https://github.com/creationix/nvm) you can switch to Node 8 before installing and running the `semantic-release` command:
|
||||
|
||||
@@ -73,7 +73,7 @@ Yes, **semantic-release** is a Node CLI application but it can be used to publis
|
||||
To publish a non-Node package (without a `package.json`) you would need to:
|
||||
- Use a [global](../usage/installation.md#global-installation) **semantic-release** installation
|
||||
- Set **semantic-release** [options](../usage/configuration.md#options) via [CLI arguments or rc file](../usage/configuration.md#configuration)
|
||||
- Make sure your CI job executing the `semantic-release` command has access to [Node >= 8.16](#why-does-semantic-release-require-node-version--816) to execute the `semantic-release` command
|
||||
- Make sure your CI job executing the `semantic-release` command has access to [Node >= 10.18](#why-does-semantic-release-require-node-version--1018) to execute the `semantic-release` command
|
||||
|
||||
See the [CI configuration recipes](../recipes/README.md#ci-configurations) for more details on specific CI environments.
|
||||
|
||||
@@ -232,9 +232,9 @@ See [“Introduction to SemVer” - Irina Gebauer](https://blog.greenkeeper.io/i
|
||||
|
||||
In addition the [verify conditions step](../../README.md#release-steps) verifies that all necessary conditions for proceeding with a release are met, and a new release will be performed [only if all your tests pass](../usage/ci-configuration.md#run-semantic-release-only-after-all-tests-succeeded).
|
||||
|
||||
## Why does semantic-release require Node version >= 8.16?
|
||||
## Why does semantic-release require Node version >= 10.18?
|
||||
|
||||
**semantic-release** is written using the latest [ECMAScript 2017](https://www.ecma-international.org/publications/standards/Ecma-262.htm) features, without transpilation which **requires Node version 8.16 or higher**.
|
||||
**semantic-release** is written using the latest [ECMAScript 2017](https://www.ecma-international.org/publications/standards/Ecma-262.htm) features, without transpilation which **requires Node version 10.18 or higher**.
|
||||
|
||||
See [Node version requirement](./node-version.md#node-version-requirement) for more details and solutions.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Node version requirement
|
||||
|
||||
**semantic-release** is written using the latest [ECMAScript 2017](https://www.ecma-international.org/publications/standards/Ecma-262.htm) features, without transpilation which requires **requires Node version 8.16 or higher**.
|
||||
**semantic-release** is written using the latest [ECMAScript 2017](https://www.ecma-international.org/publications/standards/Ecma-262.htm) features, without transpilation which requires **requires Node version 10 or higher**.
|
||||
|
||||
**semantic-release** is meant to be used in a CI environment as a development support tool, not as a production dependency. Therefore the only constraint is to run the `semantic-release` in a CI environment providing Node 8 or higher.
|
||||
|
||||
@@ -8,9 +8,9 @@ See our [Node Support Policy](node-support-policy.md) for our long-term promise
|
||||
|
||||
## Recommended solution
|
||||
|
||||
### Run at least one CI job with Node >= 8.16
|
||||
### Run at least one CI job with Node >= 10.18
|
||||
|
||||
The recommended approach is to run the `semantic-release` command from a CI job running on Node 8.16 or higher. This can either be a job used by your project to test on Node >= 8.16 or a dedicated job for the release steps.
|
||||
The recommended approach is to run the `semantic-release` command from a CI job running on Node 10.18 or higher. This can either be a job used by your project to test on Node >= 10.18 or a dedicated job for the release steps.
|
||||
|
||||
See [CI configuration](../usage/ci-configuration.md) and [CI configuration recipes](../recipes/README.md#ci-configurations) for more details.
|
||||
|
||||
|
||||
@@ -54,3 +54,16 @@ $ git branch --contains <tag name>
|
||||
$ git tag -d <tag name>
|
||||
$ git push origin :refs/tags/<tag name>
|
||||
```
|
||||
|
||||
## release not found release branch after `git push --force`
|
||||
|
||||
**semantic-release** is using both [git tags](https://git-scm.com/docs/git-tag) and [git notes](https://git-scm.com/docs/git-notes) to store information about which releases happened in which branch.
|
||||
|
||||
After a git history rewrite due to a `git push --force`, the git tags and notes referencing the commits that were rewritten are lost.
|
||||
|
||||
To recover from that situation, do the following:
|
||||
|
||||
1. Delete the tag(s) for the release(s) that have been lost from the git history. You can delete each tag from remote using `git push origin :[TAG NAME]`, e.g. `git push origin :v2.0.0-beta.1`. You can delete tags locally using `git tag -d [TAG NAME]`, e.g. `git tag -d v2.0.0-beta.1`.
|
||||
2. Re-create the tags locally: `git tag [TAG NAME] [COMMIT HASH]`, where `[COMMIT HASH]` is the new commit that created the release for the lost tag. E.g. `git tag v2.0.0-beta.1 abcdef0`
|
||||
3. Re-create the git notes for each release tag, e.g. `git notes --ref semantic-release add -f -m '{"channels":["beta"]}' v3.0.0-beta.1`. If the release was also published in the default channel (usually `master`), then set the first channel to `null`, e.g. `git notes --ref semantic-release add -f -m '{"channels":[null, "beta"]}'
|
||||
4. Push the local notes: `git push --force origin refs/notes/semantic-release`. The `--force` is needed after the rebase. Be careful.
|
||||
|
||||
@@ -38,7 +38,7 @@ The following three examples are the same.
|
||||
|
||||
- Via CLI argument:
|
||||
```bash
|
||||
$ semantic-release --branch next
|
||||
$ semantic-release --branches next
|
||||
```
|
||||
|
||||
**Note**: CLI arguments take precedence over options configured in the configuration file.
|
||||
|
||||
@@ -65,8 +65,8 @@ For each [release step](../../README.md#release-steps) the plugins that implemen
|
||||
With this configuration **semantic-release** will:
|
||||
- execute the `verifyConditions` implementation of `@semantic-release/npm` then `@semantic-release/git`
|
||||
- execute the `analyzeCommits` implementation of `@semantic-release/commit-analyzer`
|
||||
- execute the `prepare` implementation of `@semantic-release/npm` then `@semantic-release/git`
|
||||
- execute the `generateNotes` implementation of `@semantic-release/release-notes-generator`
|
||||
- execute the `prepare` implementation of `@semantic-release/npm` then `@semantic-release/git`
|
||||
- execute the `publish` implementation of `@semantic-release/npm`
|
||||
|
||||
## Plugin options configuration
|
||||
|
||||
@@ -26,7 +26,7 @@ marked.setOptions({renderer: new TerminalRenderer()});
|
||||
/* eslint complexity: off */
|
||||
async function run(context, plugins) {
|
||||
const {cwd, env, options, logger} = context;
|
||||
const {isCi, branch: ciBranch, isPr} = envCi({env, cwd});
|
||||
const {isCi, branch: ciBranch, isPr} = context.envCi;
|
||||
|
||||
if (!isCi && !options.dryRun && !options.noCi) {
|
||||
logger.warn('This run was not triggered in a known CI environment, running in dry-run mode.');
|
||||
@@ -52,7 +52,7 @@ async function run(context, plugins) {
|
||||
// Verify config
|
||||
await verify(context);
|
||||
|
||||
options.repositoryUrl = await getGitAuthUrl(context);
|
||||
options.repositoryUrl = await getGitAuthUrl({...context, branch: {name: ciBranch}});
|
||||
context.branches = await getBranches(options.repositoryUrl, ciBranch, context);
|
||||
context.branch = context.branches.find(({name}) => name === ciBranch);
|
||||
|
||||
@@ -66,7 +66,9 @@ async function run(context, plugins) {
|
||||
}
|
||||
|
||||
logger[options.dryRun ? 'warn' : 'success'](
|
||||
`Run automated release from branch ${ciBranch}${options.dryRun ? ' in dry-run mode' : ''}`
|
||||
`Run automated release from branch ${ciBranch} on repository ${options.repositoryUrl}${
|
||||
options.dryRun ? ' in dry-run mode' : ''
|
||||
}`
|
||||
);
|
||||
|
||||
try {
|
||||
@@ -112,7 +114,11 @@ async function run(context, plugins) {
|
||||
await addNote({channels: [...currentRelease.channels, nextRelease.channel]}, nextRelease.gitHead, {cwd, env});
|
||||
await push(options.repositoryUrl, {cwd, env});
|
||||
await pushNotes(options.repositoryUrl, {cwd, env});
|
||||
logger.success(`Add channel ${nextRelease.channel} to tag ${nextRelease.gitTag}`);
|
||||
logger.success(
|
||||
`Add ${nextRelease.channel ? `channel ${nextRelease.channel}` : 'default channel'} to tag ${
|
||||
nextRelease.gitTag
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
context.branch.tags.push({
|
||||
@@ -132,7 +138,7 @@ async function run(context, plugins) {
|
||||
throw new AggregateError(errors);
|
||||
}
|
||||
|
||||
context.lastRelease = await getLastRelease(context);
|
||||
context.lastRelease = getLastRelease(context);
|
||||
if (context.lastRelease.gitHead) {
|
||||
context.lastRelease.gitHead = await getTagHead(context.lastRelease.gitHead, {cwd, env});
|
||||
}
|
||||
@@ -237,7 +243,13 @@ module.exports = async (opts = {}, {cwd = process.cwd(), env = process.env, stdo
|
||||
{silent: false, streams: [process.stdout, process.stderr, stdout, stderr].filter(Boolean)},
|
||||
hideSensitive(env)
|
||||
);
|
||||
const context = {cwd, env, stdout: stdout || process.stdout, stderr: stderr || process.stderr};
|
||||
const context = {
|
||||
cwd,
|
||||
env,
|
||||
stdout: stdout || process.stdout,
|
||||
stderr: stderr || process.stderr,
|
||||
envCi: envCi({env, cwd}),
|
||||
};
|
||||
context.logger = getLogger(context);
|
||||
context.logger.log(`Running ${pkg.name} version ${pkg.version}`);
|
||||
try {
|
||||
|
||||
@@ -50,7 +50,7 @@ module.exports = async (repositoryUrl, ciBranch, context) => {
|
||||
const duplicates = [...branches]
|
||||
.map(branch => branch.name)
|
||||
.sort()
|
||||
.filter((val, idx, arr) => arr[idx] === arr[idx + 1] && arr[idx] !== arr[idx - 1]);
|
||||
.filter((_, idx, arr) => arr[idx] === arr[idx + 1] && arr[idx] !== arr[idx - 1]);
|
||||
|
||||
if (duplicates.length > 0) {
|
||||
errors.push(getError('EDUPLICATEBRANCHES', {duplicates}));
|
||||
|
||||
@@ -47,7 +47,8 @@ module.exports = async ({cwd, env, branch, options: {repositoryUrl}}) => {
|
||||
|
||||
if (gitCredentials) {
|
||||
// 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) || [];
|
||||
const [match, auth, host, path] =
|
||||
/^(?!.+:\/\/)(?:(?<auth>.*)@)?(?<host>.*?):(?<path>.*)$/.exec(repositoryUrl) || [];
|
||||
const {port, hostname, ...parsed} = parse(
|
||||
match ? `ssh://${auth ? `${auth}@` : ''}${host}/${path}` : repositoryUrl
|
||||
);
|
||||
|
||||
+20
-8
@@ -1,18 +1,30 @@
|
||||
const semver = require('semver');
|
||||
const {FIRST_RELEASE, FIRSTPRERELEASE} = require('./definitions/constants');
|
||||
const {isSameChannel} = require('./utils');
|
||||
const {isSameChannel, getLatestVersion, tagsToVersions, highest} = require('./utils');
|
||||
|
||||
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) &&
|
||||
lastRelease.channels.some(lastReleaseChannel => isSameChannel(lastReleaseChannel, channel))
|
||||
? semver.inc(lastRelease.version, 'prerelease')
|
||||
: `${semver.inc(`${major}.${minor}.${patch}`, type)}-${branch.prerelease}.${FIRSTPRERELEASE}`
|
||||
: semver.inc(lastRelease.version, type);
|
||||
|
||||
if (branch.type === 'prerelease') {
|
||||
if (
|
||||
semver.prerelease(lastRelease.version) &&
|
||||
lastRelease.channels.some(lastReleaseChannel => isSameChannel(lastReleaseChannel, channel))
|
||||
) {
|
||||
version = highest(
|
||||
semver.inc(lastRelease.version, 'prerelease'),
|
||||
`${semver.inc(getLatestVersion(tagsToVersions(branch.tags), {withPrerelease: true}), type)}-${
|
||||
branch.prerelease
|
||||
}.${FIRSTPRERELEASE}`
|
||||
);
|
||||
} else {
|
||||
version = `${semver.inc(`${major}.${minor}.${patch}`, type)}-${branch.prerelease}.${FIRSTPRERELEASE}`;
|
||||
}
|
||||
} else {
|
||||
version = semver.inc(lastRelease.version, type);
|
||||
}
|
||||
|
||||
logger.log('The next release version is %s', version);
|
||||
} else {
|
||||
version = branch.type === 'prerelease' ? `${FIRST_RELEASE}-${branch.prerelease}.${FIRSTPRERELEASE}` : FIRST_RELEASE;
|
||||
|
||||
+19
-42
@@ -65,35 +65,8 @@ async function getCommits(from, to, execaOpts) {
|
||||
async function getBranches(repositoryUrl, execaOpts) {
|
||||
return (await execa('git', ['ls-remote', '--heads', repositoryUrl], execaOpts)).stdout
|
||||
.split('\n')
|
||||
.map(branch => branch.match(/^.+refs\/heads\/(.+)$/)[1])
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the `ref` is in the direct history of a given branch.
|
||||
*
|
||||
* @param {String} ref The reference to look for.
|
||||
* @param {String} branch The branch for which to check if the `ref` is in history.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*
|
||||
* @return {Boolean} `true` if the reference is in the history of the current branch, falsy otherwise.
|
||||
*/
|
||||
async function isRefInHistory(ref, branch, execaOpts) {
|
||||
if (!(await isRefExists(branch, execaOpts))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await execa('git', ['merge-base', '--is-ancestor', ref, branch], execaOpts);
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (error.exitCode === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
debug(error);
|
||||
throw error;
|
||||
}
|
||||
.filter(Boolean)
|
||||
.map(branch => branch.match(/^.+refs\/heads\/(?<branch>.+)$/)[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,15 +86,22 @@ async function isRefExists(ref, execaOpts) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshallow the git repository if necessary and fetch all the tags.
|
||||
* Fetch all the tags from a branch. Unshallow if necessary.
|
||||
* This will update the local branch from the latest on the remote if:
|
||||
* - The branch is not the one that triggered the CI
|
||||
* - The CI created a detached head
|
||||
*
|
||||
* Otherwise it just calls `git fetch` without specifying the `refspec` option to avoid overwritting the head commit set by the CI.
|
||||
*
|
||||
* The goal is to retrieve the informations on all the release branches without "disturbing" the CI, leaving the trigger branch or the detached head intact.
|
||||
*
|
||||
* @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(repositoryUrl, branch, ciBranch, execaOpts) {
|
||||
const isLocalExists =
|
||||
(await execa('git', ['rev-parse', '--verify', branch], {...execaOpts, reject: false})).exitCode === 0;
|
||||
const isDetachedHead =
|
||||
(await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {...execaOpts, reject: false})).stdout === 'HEAD';
|
||||
|
||||
try {
|
||||
await execa(
|
||||
@@ -130,7 +110,7 @@ async function fetch(repositoryUrl, branch, ciBranch, execaOpts) {
|
||||
'fetch',
|
||||
'--unshallow',
|
||||
'--tags',
|
||||
...(branch === ciBranch && isLocalExists
|
||||
...(branch === ciBranch && !isDetachedHead
|
||||
? [repositoryUrl]
|
||||
: ['--update-head-ok', repositoryUrl, `+refs/heads/${branch}:refs/heads/${branch}`]),
|
||||
],
|
||||
@@ -142,7 +122,7 @@ async function fetch(repositoryUrl, branch, ciBranch, execaOpts) {
|
||||
[
|
||||
'fetch',
|
||||
'--tags',
|
||||
...(branch === ciBranch && isLocalExists
|
||||
...(branch === ciBranch && !isDetachedHead
|
||||
? [repositoryUrl]
|
||||
: ['--update-head-ok', repositoryUrl, `+refs/heads/${branch}:refs/heads/${branch}`]),
|
||||
],
|
||||
@@ -224,7 +204,7 @@ async function isGitRepo(execaOpts) {
|
||||
*/
|
||||
async function verifyAuth(repositoryUrl, branch, execaOpts) {
|
||||
try {
|
||||
await execa('git', ['push', '--dry-run', repositoryUrl, `HEAD:${branch}`], execaOpts);
|
||||
await execa('git', ['push', '--dry-run', '--no-verify', repositoryUrl, `HEAD:${branch}`], execaOpts);
|
||||
} catch (error) {
|
||||
debug(error);
|
||||
throw error;
|
||||
@@ -310,12 +290,10 @@ async function verifyBranchName(branch, execaOpts) {
|
||||
* @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(repositoryUrl, branch, execaOpts) {
|
||||
const {stdout: remoteHead} = await execa('git', ['ls-remote', '--heads', repositoryUrl, branch], execaOpts);
|
||||
try {
|
||||
return await isRefInHistory(remoteHead.match(/^(\w+)?/)[1], branch, execaOpts);
|
||||
} catch (error) {
|
||||
debug(error);
|
||||
}
|
||||
return (
|
||||
(await getGitHead(execaOpts)) ===
|
||||
(await execa('git', ['ls-remote', '--heads', repositoryUrl, branch], execaOpts)).stdout.match(/^(?<ref>\w+)?/)[1]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,7 +333,6 @@ module.exports = {
|
||||
getTags,
|
||||
getCommits,
|
||||
getBranches,
|
||||
isRefInHistory,
|
||||
isRefExists,
|
||||
fetch,
|
||||
fetchNotes,
|
||||
|
||||
+4
-2
@@ -31,11 +31,13 @@ function isMaintenanceRange(range) {
|
||||
}
|
||||
|
||||
function getUpperBound(range) {
|
||||
return semver.valid(range) ? range : ((semver.validRange(range) || '').match(/<(\d+\.\d+\.\d+)$/) || [])[1];
|
||||
return semver.valid(range)
|
||||
? range
|
||||
: ((semver.validRange(range) || '').match(/<(?<upperBound>\d+\.\d+\.\d+)$/) || [])[1];
|
||||
}
|
||||
|
||||
function getLowerBound(range) {
|
||||
return ((semver.validRange(range) || '').match(/(\d+\.\d+\.\d+)/) || [])[1];
|
||||
return ((semver.validRange(range) || '').match(/(?<lowerBound>\d+\.\d+\.\d+)/) || [])[1];
|
||||
}
|
||||
|
||||
function highest(version1, version2) {
|
||||
|
||||
+18
-20
@@ -7,9 +7,7 @@
|
||||
"files": [
|
||||
"test/**/*.test.js"
|
||||
],
|
||||
"helpers": [
|
||||
"test/helpers/**/*"
|
||||
]
|
||||
"timeout": "2m"
|
||||
},
|
||||
"bin": {
|
||||
"semantic-release": "bin/semantic-release.js"
|
||||
@@ -22,16 +20,16 @@
|
||||
"Pierre Vanduynslager (https://twitter.com/@pvdlg_)"
|
||||
],
|
||||
"dependencies": {
|
||||
"@semantic-release/commit-analyzer": "^7.0.0-beta",
|
||||
"@semantic-release/commit-analyzer": "^8.0.0",
|
||||
"@semantic-release/error": "^2.2.0",
|
||||
"@semantic-release/github": "^5.6.0-beta",
|
||||
"@semantic-release/npm": "^6.0.0-beta",
|
||||
"@semantic-release/release-notes-generator": "^7.1.2",
|
||||
"@semantic-release/github": "^7.0.0",
|
||||
"@semantic-release/npm": "^7.0.0",
|
||||
"@semantic-release/release-notes-generator": "^9.0.0",
|
||||
"aggregate-error": "^3.0.0",
|
||||
"cosmiconfig": "^6.0.0",
|
||||
"debug": "^4.0.0",
|
||||
"env-ci": "^4.0.0",
|
||||
"execa": "^3.2.0",
|
||||
"env-ci": "^5.0.0",
|
||||
"execa": "^4.0.0",
|
||||
"figures": "^3.0.0",
|
||||
"find-versions": "^3.0.0",
|
||||
"get-stream": "^5.0.0",
|
||||
@@ -39,40 +37,40 @@
|
||||
"hook-std": "^2.0.0",
|
||||
"hosted-git-info": "^3.0.0",
|
||||
"lodash": "^4.17.15",
|
||||
"marked": "^0.7.0",
|
||||
"marked-terminal": "^3.2.0",
|
||||
"marked": "^0.8.0",
|
||||
"marked-terminal": "^4.0.0",
|
||||
"micromatch": "^4.0.2",
|
||||
"p-each-series": "^2.1.0",
|
||||
"p-reduce": "^2.0.0",
|
||||
"read-pkg-up": "^7.0.0",
|
||||
"resolve-from": "^5.0.0",
|
||||
"semver": "^6.0.0",
|
||||
"semver": "^7.1.1",
|
||||
"semver-diff": "^3.1.1",
|
||||
"signale": "^1.2.1",
|
||||
"yargs": "^15.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "^2.0.0",
|
||||
"ava": "^3.1.0",
|
||||
"clear-module": "^4.0.0",
|
||||
"codecov": "^3.0.0",
|
||||
"delay": "^4.0.0",
|
||||
"dockerode": "^3.0.0",
|
||||
"file-url": "^3.0.0",
|
||||
"fs-extra": "^8.0.0",
|
||||
"got": "^9.0.0",
|
||||
"got": "^10.5.2",
|
||||
"js-yaml": "^3.10.0",
|
||||
"mockserver-client": "^5.1.1",
|
||||
"nock": "^11.1.0",
|
||||
"nyc": "^14.0.0",
|
||||
"nock": "^12.0.0",
|
||||
"nyc": "^15.0.0",
|
||||
"p-retry": "^4.0.0",
|
||||
"proxyquire": "^2.0.0",
|
||||
"sinon": "^7.2.7",
|
||||
"sinon": "^8.0.4",
|
||||
"stream-buffers": "^3.0.2",
|
||||
"tempy": "^0.3.0",
|
||||
"xo": "^0.25.0"
|
||||
"tempy": "^0.4.0",
|
||||
"xo": "^0.26.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.16"
|
||||
"node": ">=10.18"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import test from 'ava';
|
||||
import {union} from 'lodash';
|
||||
import semver from 'semver';
|
||||
import proxyquire from 'proxyquire';
|
||||
const test = require('ava');
|
||||
const {union} = require('lodash');
|
||||
const semver = require('semver');
|
||||
const proxyquire = require('proxyquire');
|
||||
|
||||
const getBranch = (branches, branch) => branches.find(({name}) => name === branch);
|
||||
const release = (branches, name, version) => getBranch(branches, name).tags.push({version});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import test from 'ava';
|
||||
import expand from '../../lib/branches/expand';
|
||||
import {gitRepo, gitCommits, gitCheckout, gitPush} from '../helpers/git-utils';
|
||||
const test = require('ava');
|
||||
const expand = require('../../lib/branches/expand');
|
||||
const {gitRepo, gitCommits, gitCheckout, gitPush} = require('../helpers/git-utils');
|
||||
|
||||
test('Expand branches defined with globs', async t => {
|
||||
const {cwd, repositoryUrl} = await gitRepo(true);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import test from 'ava';
|
||||
import getTags from '../../lib/branches/get-tags';
|
||||
import {gitRepo, gitCommits, gitTagVersion, gitCheckout, gitAddNote} from '../helpers/git-utils';
|
||||
const test = require('ava');
|
||||
const getTags = require('../../lib/branches/get-tags');
|
||||
const {gitRepo, gitCommits, gitTagVersion, gitCheckout, gitAddNote} = require('../helpers/git-utils');
|
||||
|
||||
test('Get the valid tags', async t => {
|
||||
const {cwd} = await gitRepo();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import test from 'ava';
|
||||
import normalize from '../../lib/branches/normalize';
|
||||
const test = require('ava');
|
||||
const normalize = require('../../lib/branches/normalize');
|
||||
|
||||
const toTags = versions => versions.map(version => ({version}));
|
||||
|
||||
|
||||
+15
-17
@@ -1,10 +1,8 @@
|
||||
import test from 'ava';
|
||||
import {escapeRegExp} from 'lodash';
|
||||
import proxyquire from 'proxyquire';
|
||||
import {stub} from 'sinon';
|
||||
import {SECRET_REPLACEMENT} from '../lib/definitions/constants';
|
||||
|
||||
const requireNoCache = proxyquire.noPreserveCache();
|
||||
const test = require('ava');
|
||||
const {escapeRegExp} = require('lodash');
|
||||
const proxyquire = require('proxyquire').noPreserveCache();
|
||||
const {stub} = require('sinon');
|
||||
const {SECRET_REPLACEMENT} = require('../lib/definitions/constants');
|
||||
|
||||
test.beforeEach(t => {
|
||||
t.context.logs = '';
|
||||
@@ -65,7 +63,7 @@ test.serial('Pass options to semantic-release API', async t => {
|
||||
'--debug',
|
||||
'-d',
|
||||
];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv}});
|
||||
|
||||
const exitCode = await cli();
|
||||
|
||||
@@ -107,7 +105,7 @@ test.serial('Pass options to semantic-release API with alias arguments', async t
|
||||
'config2',
|
||||
'--dry-run',
|
||||
];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv}});
|
||||
|
||||
const exitCode = await cli();
|
||||
|
||||
@@ -124,7 +122,7 @@ test.serial('Pass options to semantic-release API with alias arguments', async t
|
||||
test.serial('Pass unknown options to semantic-release API', async t => {
|
||||
const run = stub().resolves(true);
|
||||
const argv = ['', '', '--bool', '--first-option', 'value1', '--second-option', 'value2', '--second-option', 'value3'];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv}});
|
||||
|
||||
const exitCode = await cli();
|
||||
|
||||
@@ -138,7 +136,7 @@ test.serial('Pass unknown options to semantic-release API', async t => {
|
||||
test.serial('Pass empty Array to semantic-release API for list option set to "false"', async t => {
|
||||
const run = stub().resolves(true);
|
||||
const argv = ['', '', '--publish', 'false'];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv}});
|
||||
|
||||
const exitCode = await cli();
|
||||
|
||||
@@ -150,7 +148,7 @@ test.serial('Pass empty Array to semantic-release API for list option set to "fa
|
||||
test.serial('Do not set properties in option for which arg is not in command line', async t => {
|
||||
const run = stub().resolves(true);
|
||||
const argv = ['', '', '-b', 'master'];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv}});
|
||||
|
||||
await cli();
|
||||
|
||||
@@ -167,7 +165,7 @@ test.serial('Do not set properties in option for which arg is not in command lin
|
||||
test.serial('Display help', async t => {
|
||||
const run = stub().resolves(true);
|
||||
const argv = ['', '', '--help'];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv}});
|
||||
|
||||
const exitCode = await cli();
|
||||
|
||||
@@ -178,7 +176,7 @@ test.serial('Display help', async t => {
|
||||
test.serial('Return error exitCode and prints help if called with a command', async t => {
|
||||
const run = stub().resolves(true);
|
||||
const argv = ['', '', 'pre'];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv}});
|
||||
|
||||
const exitCode = await cli();
|
||||
|
||||
@@ -190,7 +188,7 @@ test.serial('Return error exitCode and prints help if called with a command', as
|
||||
test.serial('Return error exitCode if multiple plugin are set for single plugin', async t => {
|
||||
const run = stub().resolves(true);
|
||||
const argv = ['', '', '--analyze-commits', 'analyze1', 'analyze2'];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv}});
|
||||
|
||||
const exitCode = await cli();
|
||||
|
||||
@@ -202,7 +200,7 @@ test.serial('Return error exitCode if multiple plugin are set for single plugin'
|
||||
test.serial('Return error exitCode if semantic-release throw error', async t => {
|
||||
const run = stub().rejects(new Error('semantic-release error'));
|
||||
const argv = ['', ''];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv}});
|
||||
|
||||
const exitCode = await cli();
|
||||
|
||||
@@ -214,7 +212,7 @@ test.serial('Hide sensitive environment variable values from the logs', async t
|
||||
const env = {MY_TOKEN: 'secret token'};
|
||||
const run = stub().rejects(new Error(`Throw error: Exposing token ${env.MY_TOKEN}`));
|
||||
const argv = ['', ''];
|
||||
const cli = requireNoCache('../cli', {'.': run, process: {...process, argv, env: {...process.env, ...env}}});
|
||||
const cli = proxyquire('../cli', {'.': run, process: {...process, argv, env: {...process.env, ...env}}});
|
||||
|
||||
const exitCode = await cli();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import test from 'ava';
|
||||
import {maintenance, prerelease, release} from '../../lib/definitions/branches';
|
||||
const test = require('ava');
|
||||
const {maintenance, prerelease, release} = require('../../lib/definitions/branches');
|
||||
|
||||
test('A "maintenance" branch is identified by having a "range" property or a "name" formatted like "N.x", "N.x.x" or "N.N.x"', t => {
|
||||
t.true(maintenance.filter({name: '1.x.x'}));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import test from 'ava';
|
||||
import plugins from '../../lib/definitions/plugins';
|
||||
import {RELEASE_NOTES_SEPARATOR, SECRET_REPLACEMENT} from '../../lib/definitions/constants';
|
||||
const test = require('ava');
|
||||
const plugins = require('../../lib/definitions/plugins');
|
||||
const {RELEASE_NOTES_SEPARATOR, SECRET_REPLACEMENT} = require('../../lib/definitions/constants');
|
||||
|
||||
test('The "analyzeCommits" plugin output must be either undefined or a valid semver release type', t => {
|
||||
t.false(plugins.analyzeCommits.outputValidator('invalid'));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import test from 'ava';
|
||||
import {stub} from 'sinon';
|
||||
import getCommits from '../lib/get-commits';
|
||||
import {gitRepo, gitCommits, gitDetachedHead} from './helpers/git-utils';
|
||||
const test = require('ava');
|
||||
const {stub} = require('sinon');
|
||||
const getCommits = require('../lib/get-commits');
|
||||
const {gitRepo, gitCommits, gitDetachedHead} = require('./helpers/git-utils');
|
||||
|
||||
test.beforeEach(t => {
|
||||
// Stub the logger functions
|
||||
@@ -82,7 +82,7 @@ test('Get all commits between lastRelease.gitHead and a shas', async t => {
|
||||
|
||||
// Verify the commits created and retrieved by the module are identical
|
||||
t.is(result.length, 1);
|
||||
t.deepEqual(result, commits.slice(1, commits.length - 1));
|
||||
t.deepEqual(result, commits.slice(1, -1));
|
||||
});
|
||||
|
||||
test('Return empty array if lastRelease.gitHead is the last commit', async t => {
|
||||
|
||||
+13
-13
@@ -1,12 +1,12 @@
|
||||
import path from 'path';
|
||||
import {format} from 'util';
|
||||
import test from 'ava';
|
||||
import {writeFile, outputJson} from 'fs-extra';
|
||||
import {omit} from 'lodash';
|
||||
import proxyquire from 'proxyquire';
|
||||
import {stub} from 'sinon';
|
||||
import yaml from 'js-yaml';
|
||||
import {gitRepo, gitTagVersion, gitCommits, gitShallowClone, gitAddConfig} from './helpers/git-utils';
|
||||
const path = require('path');
|
||||
const {format} = require('util');
|
||||
const test = require('ava');
|
||||
const {writeFile, outputJson} = require('fs-extra');
|
||||
const {omit} = require('lodash');
|
||||
const proxyquire = require('proxyquire');
|
||||
const {stub} = require('sinon');
|
||||
const yaml = require('js-yaml');
|
||||
const {gitRepo, gitTagVersion, gitCommits, gitShallowClone, gitAddConfig} = require('./helpers/git-utils');
|
||||
|
||||
const DEFAULT_PLUGINS = [
|
||||
'@semantic-release/commit-analyzer',
|
||||
@@ -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.throwsAsync(t.context.getConfig({cwd}), Error);
|
||||
|
||||
t.regex(error.message, /Cannot find module 'non-existing-path'/);
|
||||
t.is(error.code, 'MODULE_NOT_FOUND');
|
||||
await t.throwsAsync(t.context.getConfig({cwd}), {
|
||||
message: /Cannot find module 'non-existing-path'/,
|
||||
code: 'MODULE_NOT_FOUND',
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import test from 'ava';
|
||||
import getAuthUrl from '../lib/get-git-auth-url';
|
||||
import {gitRepo} from './helpers/git-utils';
|
||||
const test = require('ava');
|
||||
const getAuthUrl = require('../lib/get-git-auth-url');
|
||||
const {gitRepo} = require('./helpers/git-utils');
|
||||
|
||||
const env = {GIT_ASKPASS: 'echo', GIT_TERMINAL_PROMPT: 0};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import test from 'ava';
|
||||
import getLastRelease from '../lib/get-last-release';
|
||||
const test = require('ava');
|
||||
const getLastRelease = require('../lib/get-last-release');
|
||||
|
||||
test('Get the highest non-prerelease valid tag', t => {
|
||||
const result = getLastRelease({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import test from 'ava';
|
||||
import {spy} from 'sinon';
|
||||
import getLogger from '../lib/get-logger';
|
||||
const test = require('ava');
|
||||
const {spy} = require('sinon');
|
||||
const getLogger = require('../lib/get-logger');
|
||||
|
||||
test('Expose "error", "success" and "log" functions', t => {
|
||||
const stdout = spy();
|
||||
|
||||
+153
-41
@@ -1,6 +1,6 @@
|
||||
import test from 'ava';
|
||||
import {stub} from 'sinon';
|
||||
import getNextVersion from '../lib/get-next-version';
|
||||
const test = require('ava');
|
||||
const {stub} = require('sinon');
|
||||
const getNextVersion = require('../lib/get-next-version');
|
||||
|
||||
test.beforeEach(t => {
|
||||
// Stub the logger functions
|
||||
@@ -11,9 +11,9 @@ test.beforeEach(t => {
|
||||
test('Increase version for patch release', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'master', type: 'release'},
|
||||
branch: {name: 'master', type: 'release', tags: [{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]}]},
|
||||
nextRelease: {type: 'patch'},
|
||||
lastRelease: {version: '1.0.0', channels: [undefined]},
|
||||
lastRelease: {version: '1.0.0', channels: [null]},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.0.1'
|
||||
@@ -23,9 +23,9 @@ test('Increase version for patch release', t => {
|
||||
test('Increase version for minor release', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'master', type: 'release'},
|
||||
branch: {name: 'master', type: 'release', tags: [{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]}]},
|
||||
nextRelease: {type: 'minor'},
|
||||
lastRelease: {version: '1.0.0', channels: [undefined]},
|
||||
lastRelease: {version: '1.0.0', channels: [null]},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.1.0'
|
||||
@@ -35,9 +35,9 @@ test('Increase version for minor release', t => {
|
||||
test('Increase version for major release', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'master', type: 'release'},
|
||||
branch: {name: 'master', type: 'release', tags: [{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]}]},
|
||||
nextRelease: {type: 'major'},
|
||||
lastRelease: {version: '1.0.0', channels: [undefined]},
|
||||
lastRelease: {version: '1.0.0', channels: [null]},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'2.0.0'
|
||||
@@ -47,7 +47,7 @@ test('Increase version for major release', t => {
|
||||
test('Return 1.0.0 if there is no previous release', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'master', type: 'release'},
|
||||
branch: {name: 'master', type: 'release', tags: []},
|
||||
nextRelease: {type: 'minor'},
|
||||
lastRelease: {},
|
||||
logger: t.context.logger,
|
||||
@@ -59,9 +59,14 @@ test('Return 1.0.0 if there is no previous release', t => {
|
||||
test('Increase version for patch release on prerelease branch', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'beta', type: 'prerelease', prerelease: 'beta'},
|
||||
nextRelease: {type: 'patch'},
|
||||
lastRelease: {version: '1.0.0', channels: [undefined]},
|
||||
branch: {
|
||||
name: 'beta',
|
||||
type: 'prerelease',
|
||||
prerelease: 'beta',
|
||||
tags: [{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]}],
|
||||
},
|
||||
nextRelease: {type: 'patch', channel: 'beta'},
|
||||
lastRelease: {version: '1.0.0', channels: [null]},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.0.1-beta.1'
|
||||
@@ -69,31 +74,49 @@ test('Increase version for patch release on prerelease branch', t => {
|
||||
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'beta', type: 'prerelease', prerelease: 'beta'},
|
||||
nextRelease: {type: 'patch'},
|
||||
lastRelease: {version: '1.0.0-beta.1', channels: [undefined]},
|
||||
branch: {
|
||||
name: 'beta',
|
||||
type: 'prerelease',
|
||||
prerelease: 'beta',
|
||||
tags: [
|
||||
{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]},
|
||||
{gitTag: 'v1.0.1-beta.1', version: '1.0.1-beta.1', channels: ['beta']},
|
||||
],
|
||||
},
|
||||
nextRelease: {type: 'patch', channel: 'beta'},
|
||||
lastRelease: {version: '1.0.1-beta.1', channels: ['beta']},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.0.0-beta.2'
|
||||
'1.0.1-beta.2'
|
||||
);
|
||||
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'alpha', type: 'prerelease', prerelease: 'alpha'},
|
||||
branch: {
|
||||
name: 'alpha',
|
||||
type: 'prerelease',
|
||||
prerelease: 'alpha',
|
||||
tags: [{gitTag: 'v1.0.1-beta.1', version: '1.0.1-beta.1', channels: ['beta']}],
|
||||
},
|
||||
nextRelease: {type: 'patch', channel: 'alpha'},
|
||||
lastRelease: {version: '1.0.0-beta.1', channels: ['beta']},
|
||||
lastRelease: {version: '1.0.1-beta.1', channels: ['beta']},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.0.1-alpha.1'
|
||||
'1.0.2-alpha.1'
|
||||
);
|
||||
});
|
||||
|
||||
test('Increase version for minor release on prerelease branch', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'beta', type: 'prerelease', prerelease: 'beta'},
|
||||
nextRelease: {type: 'minor'},
|
||||
lastRelease: {version: '1.0.0', channels: [undefined]},
|
||||
branch: {
|
||||
name: 'beta',
|
||||
type: 'prerelease',
|
||||
prerelease: 'beta',
|
||||
tags: [{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]}],
|
||||
},
|
||||
nextRelease: {type: 'minor', channel: 'beta'},
|
||||
lastRelease: {version: '1.0.0', channels: [null]},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.1.0-beta.1'
|
||||
@@ -101,31 +124,49 @@ test('Increase version for minor release on prerelease branch', t => {
|
||||
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'beta', type: 'prerelease', prerelease: 'beta'},
|
||||
nextRelease: {type: 'minor'},
|
||||
lastRelease: {version: '1.0.0-beta.1', channels: [undefined]},
|
||||
branch: {
|
||||
name: 'beta',
|
||||
type: 'prerelease',
|
||||
prerelease: 'beta',
|
||||
tags: [
|
||||
{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]},
|
||||
{gitTag: 'v1.1.0-beta.1', version: '1.1.0-beta.1', channels: ['beta']},
|
||||
],
|
||||
},
|
||||
nextRelease: {type: 'minor', channel: 'beta'},
|
||||
lastRelease: {version: '1.1.0-beta.1', channels: ['beta']},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.0.0-beta.2'
|
||||
'1.1.0-beta.2'
|
||||
);
|
||||
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'alpha', type: 'prerelease', prerelease: 'alpha'},
|
||||
branch: {
|
||||
name: 'alpha',
|
||||
type: 'prerelease',
|
||||
prerelease: 'alpha',
|
||||
tags: [{gitTag: 'v1.1.0-beta.1', version: '1.1.0-beta.1', channels: ['beta']}],
|
||||
},
|
||||
nextRelease: {type: 'minor', channel: 'alpha'},
|
||||
lastRelease: {version: '1.0.0-beta.1', channels: ['beta']},
|
||||
lastRelease: {version: '1.1.0-beta.1', channels: ['beta']},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.1.0-alpha.1'
|
||||
'1.2.0-alpha.1'
|
||||
);
|
||||
});
|
||||
|
||||
test('Increase version for major release on prerelease branch', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'beta', type: 'prerelease', prerelease: 'beta'},
|
||||
nextRelease: {type: 'major'},
|
||||
lastRelease: {version: '1.0.0', channels: [undefined]},
|
||||
branch: {
|
||||
name: 'beta',
|
||||
type: 'prerelease',
|
||||
prerelease: 'beta',
|
||||
tags: [{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]}],
|
||||
},
|
||||
nextRelease: {type: 'major', channel: 'beta'},
|
||||
lastRelease: {version: '1.0.0', channels: [null]},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'2.0.0-beta.1'
|
||||
@@ -133,29 +174,42 @@ test('Increase version for major release on prerelease branch', t => {
|
||||
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'beta', type: 'prerelease', prerelease: 'beta'},
|
||||
nextRelease: {type: 'major'},
|
||||
lastRelease: {version: '1.0.0-beta.1', channels: [undefined]},
|
||||
branch: {
|
||||
name: 'beta',
|
||||
type: 'prerelease',
|
||||
prerelease: 'beta',
|
||||
tags: [
|
||||
{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]},
|
||||
{gitTag: 'v2.0.0-beta.1', version: '2.0.0-beta.1', channels: ['beta']},
|
||||
],
|
||||
},
|
||||
nextRelease: {type: 'major', channel: 'beta'},
|
||||
lastRelease: {version: '2.0.0-beta.1', channels: ['beta']},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.0.0-beta.2'
|
||||
'2.0.0-beta.2'
|
||||
);
|
||||
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'alpha', type: 'prerelease', prerelease: 'alpha'},
|
||||
branch: {
|
||||
name: 'alpha',
|
||||
type: 'prerelease',
|
||||
prerelease: 'alpha',
|
||||
tags: [{gitTag: 'v2.0.0-beta.1', version: '2.0.0-beta.1', channels: ['beta']}],
|
||||
},
|
||||
nextRelease: {type: 'major', channel: 'alpha'},
|
||||
lastRelease: {version: '1.0.0-beta.1', channels: ['beta']},
|
||||
lastRelease: {version: '2.0.0-beta.1', channels: ['beta']},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'2.0.0-alpha.1'
|
||||
'3.0.0-alpha.1'
|
||||
);
|
||||
});
|
||||
|
||||
test('Return 1.0.0 if there is no previous release on prerelease branch', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {name: 'beta', type: 'prerelease', prerelease: 'beta'},
|
||||
branch: {name: 'beta', type: 'prerelease', prerelease: 'beta', tags: []},
|
||||
nextRelease: {type: 'minor'},
|
||||
lastRelease: {},
|
||||
logger: t.context.logger,
|
||||
@@ -163,3 +217,61 @@ test('Return 1.0.0 if there is no previous release on prerelease branch', t => {
|
||||
'1.0.0-beta.1'
|
||||
);
|
||||
});
|
||||
|
||||
test('Increase version for release on prerelease branch after previous commits were merged to release branch', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {
|
||||
name: 'beta',
|
||||
type: 'prerelease',
|
||||
prerelease: 'beta',
|
||||
tags: [
|
||||
{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]},
|
||||
{gitTag: 'v1.1.0', version: '1.1.0', channels: [null]}, // Version v1.1.0 released on default branch after beta was merged into master
|
||||
{gitTag: 'v1.1.0-beta.1', version: '1.1.0-beta.1', channels: [null, 'beta']},
|
||||
],
|
||||
},
|
||||
nextRelease: {type: 'minor'},
|
||||
lastRelease: {version: '1.1.0', channels: [null]},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.2.0-beta.1'
|
||||
);
|
||||
});
|
||||
|
||||
test('Increase version for release on prerelease branch based on highest commit type since last regular release', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {
|
||||
name: 'beta',
|
||||
type: 'prerelease',
|
||||
prerelease: 'beta',
|
||||
tags: [
|
||||
{gitTag: 'v1.0.0', version: '1.0.0', channels: [null]},
|
||||
{gitTag: 'v1.1.0-beta.1', version: '1.1.0-beta.1', channels: [null, 'beta']},
|
||||
],
|
||||
},
|
||||
nextRelease: {type: 'major'},
|
||||
lastRelease: {version: 'v1.1.0-beta.1', channels: [null]},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'2.0.0-beta.1'
|
||||
);
|
||||
});
|
||||
|
||||
test('Increase version for release on prerelease branch when there is no regular releases on other branches', t => {
|
||||
t.is(
|
||||
getNextVersion({
|
||||
branch: {
|
||||
name: 'beta',
|
||||
type: 'prerelease',
|
||||
prerelease: 'beta',
|
||||
tags: [{gitTag: 'v1.0.0-beta.1', version: '1.0.0-beta.1', channels: ['beta']}],
|
||||
},
|
||||
nextRelease: {type: 'minor', channel: 'beta'},
|
||||
lastRelease: {version: 'v1.0.0-beta.1', channels: ['beta']},
|
||||
logger: t.context.logger,
|
||||
}),
|
||||
'1.0.0-beta.2'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import test from 'ava';
|
||||
import getReleaseToAdd from '../lib/get-release-to-add';
|
||||
const test = require('ava');
|
||||
const getReleaseToAdd = require('../lib/get-release-to-add');
|
||||
|
||||
test('Return versions merged from release to maintenance branch, excluding lower than branch start range', t => {
|
||||
const result = getReleaseToAdd({
|
||||
|
||||
+49
-29
@@ -1,8 +1,7 @@
|
||||
import test from 'ava';
|
||||
import tempy from 'tempy';
|
||||
import {
|
||||
const test = require('ava');
|
||||
const tempy = require('tempy');
|
||||
const {
|
||||
getTagHead,
|
||||
isRefInHistory,
|
||||
isRefExists,
|
||||
fetch,
|
||||
getGitHead,
|
||||
@@ -17,8 +16,8 @@ import {
|
||||
getNote,
|
||||
addNote,
|
||||
fetchNotes,
|
||||
} from '../lib/git';
|
||||
import {
|
||||
} = require('../lib/git');
|
||||
const {
|
||||
gitRepo,
|
||||
gitCommits,
|
||||
gitCheckout,
|
||||
@@ -33,7 +32,9 @@ import {
|
||||
gitDetachedHeadFromBranch,
|
||||
gitAddNote,
|
||||
gitGetNote,
|
||||
} from './helpers/git-utils';
|
||||
gitFetch,
|
||||
initGit,
|
||||
} = require('./helpers/git-utils');
|
||||
|
||||
test('Get the last commit sha', async t => {
|
||||
// Create a git repository, set the current working directory at the root of the repo
|
||||
@@ -50,7 +51,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.throwsAsync(getGitHead({cwd}), Error);
|
||||
await t.throwsAsync(getGitHead({cwd}));
|
||||
});
|
||||
|
||||
test('Unshallow and fetch repository', async t => {
|
||||
@@ -100,7 +101,7 @@ test('Fetch all tags on a detached head repository', async t => {
|
||||
t.deepEqual((await getTags('master', {cwd})).sort(), ['v1.0.0', 'v1.0.1', 'v1.1.0'].sort());
|
||||
});
|
||||
|
||||
test('Fetch all tags on a repository with a detached head from branch', async t => {
|
||||
test('Fetch all tags on a repository with a detached head from branch (CircleCI)', async t => {
|
||||
let {cwd, repositoryUrl} = await gitRepo();
|
||||
|
||||
await gitCommits(['First'], {cwd});
|
||||
@@ -125,21 +126,32 @@ test('Fetch all tags on a repository with a detached head from branch', async t
|
||||
t.deepEqual((await getTags('master', {cwd})).sort(), ['v1.0.0', 'v1.0.1', 'v1.1.0', 'v2.0.0'].sort());
|
||||
});
|
||||
|
||||
test('Verify if the commit `sha` is in the direct history of the current branch', async t => {
|
||||
// Create a git repository, set the current working directory at the root of the repo
|
||||
const {cwd} = await gitRepo();
|
||||
// Add commits to the master branch
|
||||
const commits = await gitCommits(['First'], {cwd});
|
||||
// Create the new branch 'other-branch' from master
|
||||
await gitCheckout('other-branch', true, {cwd});
|
||||
// Add commits to the 'other-branch' branch
|
||||
const otherCommits = await gitCommits(['Second'], {cwd});
|
||||
await gitCheckout('master', false, {cwd});
|
||||
test('Fetch all tags on a detached head repository with outdated cached repo (GitLab CI)', async t => {
|
||||
const {cwd, repositoryUrl} = await gitRepo();
|
||||
|
||||
t.true(await isRefInHistory(commits[0].hash, 'master', {cwd}));
|
||||
t.falsy(await isRefInHistory(otherCommits[0].hash, 'master', {cwd}));
|
||||
t.falsy(await isRefInHistory(otherCommits[0].hash, 'missing-branch', {cwd}));
|
||||
await t.throwsAsync(isRefInHistory('non-existant-sha', 'master', {cwd}));
|
||||
await gitCommits(['First'], {cwd});
|
||||
await gitTagVersion('v1.0.0', undefined, {cwd});
|
||||
await gitCommits(['Second'], {cwd});
|
||||
await gitTagVersion('v1.0.1', undefined, {cwd});
|
||||
let [commit] = await gitCommits(['Third'], {cwd});
|
||||
await gitTagVersion('v1.1.0', undefined, {cwd});
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
|
||||
// Create a clone (as first CI run would)
|
||||
const cloneCwd = await gitShallowClone(repositoryUrl);
|
||||
await gitFetch(repositoryUrl, {cwd: cloneCwd});
|
||||
await gitCheckout(commit.hash, false, {cwd: cloneCwd});
|
||||
|
||||
// Push tag to remote
|
||||
[commit] = await gitCommits(['Fourth'], {cwd});
|
||||
await gitTagVersion('v1.2.0', undefined, {cwd});
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
|
||||
// Fetch on the cached repo and make detached head, leaving master outdated
|
||||
await fetch(repositoryUrl, 'master', 'master', {cwd: cloneCwd});
|
||||
await gitCheckout(commit.hash, false, {cwd: cloneCwd});
|
||||
|
||||
t.deepEqual((await getTags('master', {cwd: cloneCwd})).sort(), ['v1.0.0', 'v1.0.1', 'v1.1.0', 'v1.2.0'].sort());
|
||||
});
|
||||
|
||||
test('Verify if a branch exists', async t => {
|
||||
@@ -171,6 +183,11 @@ test('Get all branches', async t => {
|
||||
t.deepEqual((await getBranches(repositoryUrl, {cwd})).sort(), ['master', 'second-branch', 'third-branch'].sort());
|
||||
});
|
||||
|
||||
test('Return empty array if there are no branches', async t => {
|
||||
const {cwd, repositoryUrl} = await initGit(true);
|
||||
t.deepEqual(await getBranches(repositoryUrl, {cwd}), []);
|
||||
});
|
||||
|
||||
test('Get the commit sha for a given tag', async t => {
|
||||
// Create a git repository, set the current working directory at the root of the repo
|
||||
const {cwd} = await gitRepo();
|
||||
@@ -299,13 +316,16 @@ test('Return falsy if repository is not up to date', async t => {
|
||||
t.falsy(await isBranchUpToDate(repositoryUrl, 'master', {cwd}));
|
||||
});
|
||||
|
||||
test('Return "true" if local repository is ahead', async t => {
|
||||
const {cwd, repositoryUrl} = await gitRepo(true);
|
||||
await gitCommits(['First'], {cwd});
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
await gitCommits(['Second'], {cwd});
|
||||
test('Return falsy if detached head repository is not up to date', async t => {
|
||||
let {cwd, repositoryUrl} = await gitRepo();
|
||||
|
||||
t.true(await isBranchUpToDate(repositoryUrl, 'master', {cwd}));
|
||||
const [commit] = await gitCommits(['First'], {cwd});
|
||||
await gitCommits(['Second'], {cwd});
|
||||
await gitPush(repositoryUrl, 'master', {cwd});
|
||||
cwd = await gitDetachedHead(repositoryUrl, commit.hash);
|
||||
await fetch(repositoryUrl, 'master', 'master', {cwd});
|
||||
|
||||
t.falsy(await isBranchUpToDate(repositoryUrl, 'master', {cwd}));
|
||||
});
|
||||
|
||||
test('Get a commit note', async t => {
|
||||
|
||||
+84
-36
@@ -1,13 +1,13 @@
|
||||
import tempy from 'tempy';
|
||||
import execa from 'execa';
|
||||
import fileUrl from 'file-url';
|
||||
import pEachSeries from 'p-each-series';
|
||||
import gitLogParser from 'git-log-parser';
|
||||
import getStream from 'get-stream';
|
||||
import {GIT_NOTE_REF} from '../../lib/definitions/constants';
|
||||
const tempy = require('tempy');
|
||||
const execa = require('execa');
|
||||
const fileUrl = require('file-url');
|
||||
const pEachSeries = require('p-each-series');
|
||||
const gitLogParser = require('git-log-parser');
|
||||
const getStream = require('get-stream');
|
||||
const {GIT_NOTE_REF} = require('../../lib/definitions/constants');
|
||||
|
||||
/**
|
||||
* Commit message informations.
|
||||
* Commit message information.
|
||||
*
|
||||
* @typedef {Object} Commit
|
||||
* @property {String} branch The commit branch.
|
||||
@@ -15,21 +15,34 @@ import {GIT_NOTE_REF} from '../../lib/definitions/constants';
|
||||
* @property {String} message The commit message.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize git repository
|
||||
* If `withRemote` is `true`, creates a bare repository and initialize it.
|
||||
* If `withRemote` is `false`, creates a regular repository and initialize it.
|
||||
*
|
||||
* @param {Boolean} withRemote `true` to create a shallow clone of a bare repository.
|
||||
* @return {String} The path of the repository
|
||||
*/
|
||||
async function initGit(withRemote) {
|
||||
const cwd = tempy.directory();
|
||||
|
||||
await execa('git', ['init', ...(withRemote ? ['--bare'] : [])], {cwd});
|
||||
const repositoryUrl = fileUrl(cwd);
|
||||
return {cwd, repositoryUrl};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a temporary git repository.
|
||||
* If `withRemote` is `true`, creates a bare repository, initialize it and create a shallow clone. Change the current working directory to the clone root.
|
||||
* If `withRemote` is `false`, creates a regular repository and initialize it. Change the current working directory to the repository root.
|
||||
* If `withRemote` is `true`, creates a shallow clone. Change the current working directory to the clone root.
|
||||
* If `withRemote` is `false`, just change the current working directory to the repository root.
|
||||
*
|
||||
*
|
||||
* @param {Boolean} withRemote `true` to create a shallow clone of a bare repository.
|
||||
* @param {String} [branch='master'] The branch to initialize.
|
||||
* @return {String} The path of the clone if `withRemote` is `true`, the path of the repository otherwise.
|
||||
*/
|
||||
export async function gitRepo(withRemote, branch = 'master') {
|
||||
let cwd = tempy.directory();
|
||||
|
||||
await execa('git', ['init', ...(withRemote ? ['--bare'] : [])], {cwd});
|
||||
|
||||
const repositoryUrl = fileUrl(cwd);
|
||||
async function gitRepo(withRemote, branch = 'master') {
|
||||
let {cwd, repositoryUrl} = await initGit(withRemote);
|
||||
if (withRemote) {
|
||||
await initBareRepo(repositoryUrl, branch);
|
||||
cwd = await gitShallowClone(repositoryUrl, branch);
|
||||
@@ -53,7 +66,7 @@ export async function gitRepo(withRemote, branch = 'master') {
|
||||
* @param {String} repositoryUrl The URL of the bare repository.
|
||||
* @param {String} [branch='master'] the branch to initialize.
|
||||
*/
|
||||
export async function initBareRepo(repositoryUrl, branch = 'master') {
|
||||
async function initBareRepo(repositoryUrl, branch = 'master') {
|
||||
const cwd = tempy.directory();
|
||||
await execa('git', ['clone', '--no-hardlinks', repositoryUrl, cwd], {cwd});
|
||||
await gitCheckout(branch, true, {cwd});
|
||||
@@ -69,7 +82,7 @@ export async function initBareRepo(repositoryUrl, branch = 'master') {
|
||||
*
|
||||
* @returns {Array<Commit>} The created commits, in reverse order (to match `git log` order).
|
||||
*/
|
||||
export async function gitCommits(messages, execaOpts) {
|
||||
async function gitCommits(messages, execaOpts) {
|
||||
await pEachSeries(
|
||||
messages,
|
||||
async message => (await execa('git', ['commit', '-m', message, '--allow-empty', '--no-gpg-sign'], execaOpts)).stdout
|
||||
@@ -85,7 +98,7 @@ export async function gitCommits(messages, execaOpts) {
|
||||
*
|
||||
* @return {Array<Object>} The list of parsed commits.
|
||||
*/
|
||||
export async function gitGetCommits(from, execaOpts) {
|
||||
async function gitGetCommits(from, execaOpts) {
|
||||
Object.assign(gitLogParser.fields, {hash: 'H', message: 'B', gitTags: 'd', committerDate: {key: 'ci', type: Date}});
|
||||
return (
|
||||
await getStream.array(
|
||||
@@ -105,10 +118,20 @@ export async function gitGetCommits(from, execaOpts) {
|
||||
* @param {Boolean} create to create the branch, `false` to checkout an existing branch.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
export async function gitCheckout(branch, create, execaOpts) {
|
||||
async function gitCheckout(branch, create, execaOpts) {
|
||||
await execa('git', create ? ['checkout', '-b', branch] : ['checkout', branch], execaOpts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch current git repository.
|
||||
*
|
||||
* @param {String} repositoryUrl The repository remote URL.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
async function gitFetch(repositoryUrl, execaOpts) {
|
||||
await execa('git', ['fetch', repositoryUrl], execaOpts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HEAD sha.
|
||||
*
|
||||
@@ -116,7 +139,7 @@ export async function gitCheckout(branch, create, execaOpts) {
|
||||
*
|
||||
* @return {String} The sha of the head commit in the current git repository.
|
||||
*/
|
||||
export async function gitHead(execaOpts) {
|
||||
async function gitHead(execaOpts) {
|
||||
return (await execa('git', ['rev-parse', 'HEAD'], execaOpts)).stdout;
|
||||
}
|
||||
|
||||
@@ -127,7 +150,7 @@ export async function gitHead(execaOpts) {
|
||||
* @param {String} [sha] The commit on which to create the tag. If undefined the tag is created on the last commit.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
export async function gitTagVersion(tagName, sha, execaOpts) {
|
||||
async function gitTagVersion(tagName, sha, execaOpts) {
|
||||
await execa('git', sha ? ['tag', '-f', tagName, sha] : ['tag', tagName], execaOpts);
|
||||
}
|
||||
|
||||
@@ -140,7 +163,7 @@ export async function gitTagVersion(tagName, sha, execaOpts) {
|
||||
* @param {Number} [depth=1] The number of commit to clone.
|
||||
* @return {String} The path of the cloned repository.
|
||||
*/
|
||||
export async function gitShallowClone(repositoryUrl, branch = 'master', depth = 1) {
|
||||
async function gitShallowClone(repositoryUrl, branch = 'master', depth = 1) {
|
||||
const cwd = tempy.directory();
|
||||
|
||||
await execa('git', ['clone', '--no-hardlinks', '--no-tags', '-b', branch, '--depth', depth, repositoryUrl, cwd], {
|
||||
@@ -156,7 +179,7 @@ export async function gitShallowClone(repositoryUrl, branch = 'master', depth =
|
||||
* @param {Number} head A commit sha of the remote repo that will become the detached head of the new one.
|
||||
* @return {String} The path of the new repository.
|
||||
*/
|
||||
export async function gitDetachedHead(repositoryUrl, head) {
|
||||
async function gitDetachedHead(repositoryUrl, head) {
|
||||
const cwd = tempy.directory();
|
||||
|
||||
await execa('git', ['init'], {cwd});
|
||||
@@ -166,7 +189,7 @@ export async function gitDetachedHead(repositoryUrl, head) {
|
||||
return cwd;
|
||||
}
|
||||
|
||||
export async function gitDetachedHeadFromBranch(repositoryUrl, branch, head) {
|
||||
async function gitDetachedHeadFromBranch(repositoryUrl, branch, head) {
|
||||
const cwd = tempy.directory();
|
||||
|
||||
await execa('git', ['init'], {cwd});
|
||||
@@ -184,7 +207,7 @@ export async function gitDetachedHeadFromBranch(repositoryUrl, branch, head) {
|
||||
* @param {String} value Config value.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
export async function gitAddConfig(name, value, execaOpts) {
|
||||
async function gitAddConfig(name, value, execaOpts) {
|
||||
await execa('git', ['config', '--add', name, value], execaOpts);
|
||||
}
|
||||
|
||||
@@ -196,7 +219,7 @@ export async function gitAddConfig(name, value, execaOpts) {
|
||||
*
|
||||
* @return {String} The sha of the commit associated with `tagName` on the local repository.
|
||||
*/
|
||||
export async function gitTagHead(tagName, execaOpts) {
|
||||
async function gitTagHead(tagName, execaOpts) {
|
||||
return (await execa('git', ['rev-list', '-1', tagName], execaOpts)).stdout;
|
||||
}
|
||||
|
||||
@@ -209,11 +232,11 @@ export async function gitTagHead(tagName, execaOpts) {
|
||||
*
|
||||
* @return {String} The sha of the commit associated with `tagName` on the remote repository.
|
||||
*/
|
||||
export async function gitRemoteTagHead(repositoryUrl, tagName, execaOpts) {
|
||||
async function gitRemoteTagHead(repositoryUrl, tagName, execaOpts) {
|
||||
return (await execa('git', ['ls-remote', '--tags', repositoryUrl, tagName], execaOpts)).stdout
|
||||
.split('\n')
|
||||
.filter(tag => Boolean(tag))
|
||||
.map(tag => tag.match(/^(\S+)/)[1])[0];
|
||||
.map(tag => tag.match(/^(?<tag>\S+)/)[1])[0];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -224,7 +247,7 @@ export async function gitRemoteTagHead(repositoryUrl, tagName, execaOpts) {
|
||||
*
|
||||
* @return {String} The tag associatedwith the sha in parameter or `null`.
|
||||
*/
|
||||
export async function gitCommitTag(gitHead, execaOpts) {
|
||||
async function gitCommitTag(gitHead, execaOpts) {
|
||||
return (await execa('git', ['describe', '--tags', '--exact-match', gitHead], execaOpts)).stdout;
|
||||
}
|
||||
|
||||
@@ -237,7 +260,7 @@ export async function gitCommitTag(gitHead, execaOpts) {
|
||||
*
|
||||
* @throws {Error} if the push failed.
|
||||
*/
|
||||
export async function gitPush(repositoryUrl, branch, execaOpts) {
|
||||
async function gitPush(repositoryUrl, branch, execaOpts) {
|
||||
await execa('git', ['push', '--tags', repositoryUrl, `HEAD:${branch}`], execaOpts);
|
||||
}
|
||||
|
||||
@@ -247,7 +270,7 @@ export async function gitPush(repositoryUrl, branch, execaOpts) {
|
||||
* @param {String} ref The ref to merge.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
export async function merge(ref, execaOpts) {
|
||||
async function merge(ref, execaOpts) {
|
||||
await execa('git', ['merge', '--no-ff', ref], execaOpts);
|
||||
}
|
||||
|
||||
@@ -257,7 +280,7 @@ export async function merge(ref, execaOpts) {
|
||||
* @param {String} ref The ref to merge.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
export async function mergeFf(ref, execaOpts) {
|
||||
async function mergeFf(ref, execaOpts) {
|
||||
await execa('git', ['merge', '--ff', ref], execaOpts);
|
||||
}
|
||||
|
||||
@@ -267,7 +290,7 @@ export async function mergeFf(ref, execaOpts) {
|
||||
* @param {String} ref The ref to merge.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
export async function rebase(ref, execaOpts) {
|
||||
async function rebase(ref, execaOpts) {
|
||||
await execa('git', ['rebase', ref], execaOpts);
|
||||
}
|
||||
|
||||
@@ -278,7 +301,7 @@ export async function rebase(ref, execaOpts) {
|
||||
* @param {String} ref The ref to add the note to.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
export async function gitAddNote(note, ref, execaOpts) {
|
||||
async function gitAddNote(note, ref, execaOpts) {
|
||||
await execa('git', ['notes', '--ref', GIT_NOTE_REF, 'add', '-m', note, ref], execaOpts);
|
||||
}
|
||||
|
||||
@@ -288,6 +311,31 @@ export async function gitAddNote(note, ref, execaOpts) {
|
||||
* @param {String} ref The ref to get the note from.
|
||||
* @param {Object} [execaOpts] Options to pass to `execa`.
|
||||
*/
|
||||
export async function gitGetNote(ref, execaOpts) {
|
||||
async function gitGetNote(ref, execaOpts) {
|
||||
return (await execa('git', ['notes', '--ref', GIT_NOTE_REF, 'show', ref], execaOpts)).stdout;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
initGit,
|
||||
gitRepo,
|
||||
initBareRepo,
|
||||
gitCommits,
|
||||
gitGetCommits,
|
||||
gitCheckout,
|
||||
gitFetch,
|
||||
gitHead,
|
||||
gitTagVersion,
|
||||
gitShallowClone,
|
||||
gitDetachedHead,
|
||||
gitDetachedHeadFromBranch,
|
||||
gitAddConfig,
|
||||
gitTagHead,
|
||||
gitRemoteTagHead,
|
||||
gitCommitTag,
|
||||
gitPush,
|
||||
merge,
|
||||
mergeFf,
|
||||
rebase,
|
||||
gitAddNote,
|
||||
gitGetNote,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Docker from 'dockerode';
|
||||
import getStream from 'get-stream';
|
||||
import pRetry from 'p-retry';
|
||||
import {initBareRepo, gitShallowClone} from './git-utils';
|
||||
const Docker = require('dockerode');
|
||||
const getStream = require('get-stream');
|
||||
const pRetry = require('p-retry');
|
||||
const {initBareRepo, gitShallowClone} = require('./git-utils');
|
||||
|
||||
const IMAGE = 'pvdlg/docker-gitbox:latest';
|
||||
const SERVER_PORT = 80;
|
||||
@@ -69,4 +69,4 @@ async function createRepo(name, branch = 'master', description = `Repository ${n
|
||||
return {cwd, repositoryUrl, authUrl};
|
||||
}
|
||||
|
||||
export default {start, stop, gitCredential, createRepo};
|
||||
module.exports = {start, stop, gitCredential, createRepo};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Docker from 'dockerode';
|
||||
import getStream from 'get-stream';
|
||||
import got from 'got';
|
||||
import pRetry from 'p-retry';
|
||||
import {mockServerClient} from 'mockserver-client';
|
||||
const Docker = require('dockerode');
|
||||
const getStream = require('get-stream');
|
||||
const got = require('got');
|
||||
const pRetry = require('p-retry');
|
||||
const {mockServerClient} = require('mockserver-client');
|
||||
|
||||
const IMAGE = 'jamesdbloom/mockserver:latest';
|
||||
const MOCK_SERVER_PORT = 1080;
|
||||
@@ -100,4 +100,4 @@ function verify(expectation) {
|
||||
return client.verify(expectation);
|
||||
}
|
||||
|
||||
export default {start, stop, mock, verify, url};
|
||||
module.exports = {start, stop, mock, verify, url};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Docker from 'dockerode';
|
||||
import getStream from 'get-stream';
|
||||
import got from 'got';
|
||||
import delay from 'delay';
|
||||
import pRetry from 'p-retry';
|
||||
const Docker = require('dockerode');
|
||||
const getStream = require('get-stream');
|
||||
const got = require('got');
|
||||
const delay = require('delay');
|
||||
const pRetry = require('p-retry');
|
||||
|
||||
const IMAGE = 'semanticrelease/npm-registry-docker:latest';
|
||||
const SERVER_PORT = 15986;
|
||||
@@ -45,10 +45,10 @@ async function start() {
|
||||
|
||||
// Create user
|
||||
await got(`http://${SERVER_HOST}:${SERVER_PORT}/_users/org.couchdb.user:${NPM_USERNAME}`, {
|
||||
json: true,
|
||||
auth: `${COUCHDB_USER}:${COUCHDB_PASSWORD}`,
|
||||
username: COUCHDB_USER,
|
||||
password: COUCHDB_PASSWORD,
|
||||
method: 'PUT',
|
||||
body: {
|
||||
json: {
|
||||
_id: `org.couchdb.user:${NPM_USERNAME}`,
|
||||
name: NPM_USERNAME,
|
||||
roles: [],
|
||||
@@ -76,4 +76,4 @@ async function stop() {
|
||||
await container.remove();
|
||||
}
|
||||
|
||||
export default {start, stop, authEnv, url};
|
||||
module.exports = {start, stop, authEnv, url};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import execa from 'execa';
|
||||
const execa = require('execa');
|
||||
|
||||
export async function npmView(packageName, env) {
|
||||
async function npmView(packageName, env) {
|
||||
return JSON.parse((await execa('npm', ['view', packageName, '--json'], {env})).stdout);
|
||||
}
|
||||
|
||||
module.exports = {npmView};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import test from 'ava';
|
||||
import {repeat} from 'lodash';
|
||||
import hideSensitive from '../lib/hide-sensitive';
|
||||
import {SECRET_REPLACEMENT, SECRET_MIN_SIZE} from '../lib/definitions/constants';
|
||||
const test = require('ava');
|
||||
const {repeat} = require('lodash');
|
||||
const hideSensitive = require('../lib/hide-sensitive');
|
||||
const {SECRET_REPLACEMENT, SECRET_MIN_SIZE} = require('../lib/definitions/constants');
|
||||
|
||||
test('Replace multiple sensitive environment variable values', t => {
|
||||
const env = {SOME_PASSWORD: 'password', SOME_TOKEN: 'secret'};
|
||||
|
||||
+44
-22
@@ -1,13 +1,13 @@
|
||||
import test from 'ava';
|
||||
import {escapeRegExp, isString, sortBy, omit} from 'lodash';
|
||||
import proxyquire from 'proxyquire';
|
||||
import {spy, stub} from 'sinon';
|
||||
import {WritableStreamBuffer} from 'stream-buffers';
|
||||
import AggregateError from 'aggregate-error';
|
||||
import SemanticReleaseError from '@semantic-release/error';
|
||||
import {COMMIT_NAME, COMMIT_EMAIL, SECRET_REPLACEMENT} from '../lib/definitions/constants';
|
||||
import {
|
||||
gitHead as getGitHead,
|
||||
const test = require('ava');
|
||||
const {escapeRegExp, isString, sortBy, omit} = require('lodash');
|
||||
const proxyquire = require('proxyquire');
|
||||
const {spy, stub} = require('sinon');
|
||||
const {WritableStreamBuffer} = require('stream-buffers');
|
||||
const AggregateError = require('aggregate-error');
|
||||
const SemanticReleaseError = require('@semantic-release/error');
|
||||
const {COMMIT_NAME, COMMIT_EMAIL, SECRET_REPLACEMENT} = require('../lib/definitions/constants');
|
||||
const {
|
||||
gitHead: getGitHead,
|
||||
gitCheckout,
|
||||
gitTagHead,
|
||||
gitRepo,
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
rebase,
|
||||
gitAddNote,
|
||||
gitGetNote,
|
||||
} from './helpers/git-utils';
|
||||
} = require('./helpers/git-utils');
|
||||
|
||||
const requireNoCache = proxyquire.noPreserveCache();
|
||||
const pluginNoop = require.resolve('./fixtures/plugin-noop');
|
||||
@@ -126,6 +126,7 @@ test('Plugins are called with expected values', async t => {
|
||||
publish: [publish, pluginNoop],
|
||||
success,
|
||||
};
|
||||
const envCi = {branch: 'master', isCi: true, isPr: false};
|
||||
|
||||
const releases = [
|
||||
{
|
||||
@@ -144,7 +145,7 @@ test('Plugins are called with expected values', async t => {
|
||||
|
||||
const semanticRelease = requireNoCache('..', {
|
||||
'./lib/get-logger': () => t.context.logger,
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
'env-ci': () => envCi,
|
||||
});
|
||||
const result = await semanticRelease(options, {
|
||||
cwd,
|
||||
@@ -160,6 +161,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(verifyConditions1.args[0][1].branch, branch);
|
||||
t.deepEqual(verifyConditions1.args[0][1].branches, branches);
|
||||
t.deepEqual(verifyConditions1.args[0][1].logger, t.context.logger);
|
||||
t.deepEqual(verifyConditions1.args[0][1].envCi, envCi);
|
||||
t.is(verifyConditions2.callCount, 1);
|
||||
t.deepEqual(verifyConditions2.args[0][0], config);
|
||||
t.deepEqual(verifyConditions2.args[0][1].cwd, cwd);
|
||||
@@ -167,6 +169,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(verifyConditions2.args[0][1].branch, branch);
|
||||
t.deepEqual(verifyConditions2.args[0][1].branches, branches);
|
||||
t.deepEqual(verifyConditions2.args[0][1].logger, t.context.logger);
|
||||
t.deepEqual(verifyConditions2.args[0][1].envCi, envCi);
|
||||
|
||||
t.is(generateNotes1.callCount, 2);
|
||||
t.is(generateNotes2.callCount, 2);
|
||||
@@ -188,6 +191,7 @@ test('Plugins are called with expected values', async t => {
|
||||
gitTag: 'v1.0.0',
|
||||
name: 'v1.0.0',
|
||||
});
|
||||
t.deepEqual(generateNotes2.args[0][1].envCi, envCi);
|
||||
|
||||
t.deepEqual(generateNotes2.args[0][0], config);
|
||||
t.deepEqual(generateNotes2.args[0][1].options, options);
|
||||
@@ -206,6 +210,7 @@ test('Plugins are called with expected values', async t => {
|
||||
name: 'v1.0.0',
|
||||
notes: notes1,
|
||||
});
|
||||
t.deepEqual(generateNotes2.args[0][1].envCi, envCi);
|
||||
|
||||
t.deepEqual(generateNotes3.args[0][0], config);
|
||||
t.deepEqual(generateNotes3.args[0][1].options, options);
|
||||
@@ -224,6 +229,7 @@ test('Plugins are called with expected values', async t => {
|
||||
name: 'v1.0.0',
|
||||
notes: `${notes1}\n\n${notes2}`,
|
||||
});
|
||||
t.deepEqual(generateNotes3.args[0][1].envCi, envCi);
|
||||
|
||||
branch.tags.push({
|
||||
version: '1.0.0',
|
||||
@@ -251,6 +257,7 @@ test('Plugins are called with expected values', async t => {
|
||||
});
|
||||
t.deepEqual(addChannel.args[0][1].commits[0].hash, commits[1].hash);
|
||||
t.deepEqual(addChannel.args[0][1].commits[0].message, commits[1].message);
|
||||
t.deepEqual(addChannel.args[0][1].envCi, envCi);
|
||||
|
||||
t.is(analyzeCommits.callCount, 1);
|
||||
t.deepEqual(analyzeCommits.args[0][0], config);
|
||||
@@ -261,6 +268,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(analyzeCommits.args[0][1].lastRelease, lastRelease);
|
||||
t.deepEqual(analyzeCommits.args[0][1].commits[0].hash, commits[0].hash);
|
||||
t.deepEqual(analyzeCommits.args[0][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(analyzeCommits.args[0][1].envCi, envCi);
|
||||
|
||||
t.is(verifyRelease.callCount, 1);
|
||||
t.deepEqual(verifyRelease.args[0][0], config);
|
||||
@@ -272,6 +280,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(verifyRelease.args[0][1].commits[0].hash, commits[0].hash);
|
||||
t.deepEqual(verifyRelease.args[0][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(verifyRelease.args[0][1].nextRelease, nextRelease);
|
||||
t.deepEqual(verifyRelease.args[0][1].envCi, envCi);
|
||||
|
||||
t.deepEqual(generateNotes1.args[1][0], config);
|
||||
t.deepEqual(generateNotes1.args[1][1].options, options);
|
||||
@@ -282,6 +291,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(generateNotes1.args[1][1].commits[0].hash, commits[0].hash);
|
||||
t.deepEqual(generateNotes1.args[1][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(generateNotes1.args[1][1].nextRelease, nextRelease);
|
||||
t.deepEqual(generateNotes1.args[1][1].envCi, envCi);
|
||||
|
||||
t.deepEqual(generateNotes2.args[1][0], config);
|
||||
t.deepEqual(generateNotes2.args[1][1].options, options);
|
||||
@@ -292,6 +302,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(generateNotes2.args[1][1].commits[0].hash, commits[0].hash);
|
||||
t.deepEqual(generateNotes2.args[1][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(generateNotes2.args[1][1].nextRelease, {...nextRelease, notes: notes1});
|
||||
t.deepEqual(generateNotes2.args[1][1].envCi, envCi);
|
||||
|
||||
t.deepEqual(generateNotes3.args[1][0], config);
|
||||
t.deepEqual(generateNotes3.args[1][1].options, options);
|
||||
@@ -302,6 +313,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(generateNotes3.args[1][1].commits[0].hash, commits[0].hash);
|
||||
t.deepEqual(generateNotes3.args[1][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(generateNotes3.args[1][1].nextRelease, {...nextRelease, notes: `${notes1}\n\n${notes2}`});
|
||||
t.deepEqual(generateNotes3.args[1][1].envCi, envCi);
|
||||
|
||||
t.is(prepare.callCount, 1);
|
||||
t.deepEqual(prepare.args[0][0], config);
|
||||
@@ -313,6 +325,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(prepare.args[0][1].commits[0].hash, commits[0].hash);
|
||||
t.deepEqual(prepare.args[0][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(prepare.args[0][1].nextRelease, {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`});
|
||||
t.deepEqual(prepare.args[0][1].envCi, envCi);
|
||||
|
||||
t.is(publish.callCount, 1);
|
||||
t.deepEqual(publish.args[0][0], config);
|
||||
@@ -324,6 +337,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(publish.args[0][1].commits[0].hash, commits[0].hash);
|
||||
t.deepEqual(publish.args[0][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(publish.args[0][1].nextRelease, {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`});
|
||||
t.deepEqual(publish.args[0][1].envCi, envCi);
|
||||
|
||||
t.is(success.callCount, 2);
|
||||
t.deepEqual(success.args[0][0], config);
|
||||
@@ -344,6 +358,7 @@ test('Plugins are called with expected values', async t => {
|
||||
notes: `${notes1}\n\n${notes2}\n\n${notes3}`,
|
||||
});
|
||||
t.deepEqual(success.args[0][1].releases, [releases[0]]);
|
||||
t.deepEqual(success.args[0][1].envCi, envCi);
|
||||
|
||||
t.deepEqual(success.args[1][0], config);
|
||||
t.deepEqual(success.args[1][1].options, options);
|
||||
@@ -355,6 +370,7 @@ test('Plugins are called with expected values', async t => {
|
||||
t.deepEqual(success.args[1][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(success.args[1][1].nextRelease, {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`});
|
||||
t.deepEqual(success.args[1][1].releases, [releases[1], releases[2]]);
|
||||
t.deepEqual(success.args[1][1].envCi, envCi);
|
||||
|
||||
t.deepEqual(result, {
|
||||
lastRelease,
|
||||
@@ -785,7 +801,14 @@ async function addChannelMacro(t, mergeFunction) {
|
||||
const publish = stub().resolves();
|
||||
const success = stub().resolves();
|
||||
|
||||
const config = {branches: [{name: 'master'}, {name: 'next'}], repositoryUrl, tagFormat: `v\${version}`};
|
||||
const config = {
|
||||
branches: [
|
||||
{name: 'master', channel: 'latest'},
|
||||
{name: 'next', channel: 'next'},
|
||||
],
|
||||
repositoryUrl,
|
||||
tagFormat: `v\${version}`,
|
||||
};
|
||||
const options = {
|
||||
...config,
|
||||
verifyConditions,
|
||||
@@ -796,11 +819,11 @@ async function addChannelMacro(t, mergeFunction) {
|
||||
publish,
|
||||
success,
|
||||
};
|
||||
const nextRelease2 = {
|
||||
const nextRelease = {
|
||||
name: 'v2.0.1',
|
||||
type: 'patch',
|
||||
version: '2.0.1',
|
||||
channel: null,
|
||||
channel: 'latest',
|
||||
gitTag: 'v2.0.1',
|
||||
gitHead: commits[2].hash,
|
||||
};
|
||||
@@ -812,13 +835,13 @@ async function addChannelMacro(t, mergeFunction) {
|
||||
const result = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}});
|
||||
|
||||
t.deepEqual(result.releases, [
|
||||
{...nextRelease2, ...release1, notes, pluginName: '[Function: functionStub]'},
|
||||
{...nextRelease2, notes, pluginName: '[Function: functionStub]'},
|
||||
{...nextRelease, ...release1, notes, pluginName: '[Function: functionStub]'},
|
||||
{...nextRelease, notes, pluginName: '[Function: functionStub]'},
|
||||
]);
|
||||
|
||||
// Verify the tag has been created on the local and remote repo and reference
|
||||
t.is(await gitTagHead(nextRelease2.gitTag, {cwd}), nextRelease2.gitHead);
|
||||
t.is(await gitRemoteTagHead(repositoryUrl, nextRelease2.gitTag, {cwd}), nextRelease2.gitHead);
|
||||
t.is(await gitTagHead(nextRelease.gitTag, {cwd}), nextRelease.gitHead);
|
||||
t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag, {cwd}), nextRelease.gitHead);
|
||||
}
|
||||
|
||||
addChannelMacro.title = providedTitle => `Add version to a channel after a merge (${providedTitle})`;
|
||||
@@ -1784,7 +1807,7 @@ test('Throw an Error if plugin returns an unexpected value', async t => {
|
||||
});
|
||||
const error = await t.throwsAsync(
|
||||
semanticRelease(options, {cwd, env: {}, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}),
|
||||
Error
|
||||
{instanceOf: SemanticReleaseError}
|
||||
);
|
||||
t.regex(error.details, /string/);
|
||||
});
|
||||
@@ -1813,8 +1836,7 @@ test('Hide sensitive information passed to "fail" plugin', async t => {
|
||||
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
|
||||
});
|
||||
await t.throwsAsync(
|
||||
semanticRelease(options, {cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()}),
|
||||
Error
|
||||
semanticRelease(options, {cwd, env, stdout: new WritableStreamBuffer(), stderr: new WritableStreamBuffer()})
|
||||
);
|
||||
|
||||
const error = fail.args[0][1].errors[0];
|
||||
|
||||
+15
-15
@@ -1,13 +1,13 @@
|
||||
import path from 'path';
|
||||
import proxyquire from 'proxyquire';
|
||||
import test from 'ava';
|
||||
import {escapeRegExp} from 'lodash';
|
||||
import {writeJson, readJson} from 'fs-extra';
|
||||
import execa from 'execa';
|
||||
import {WritableStreamBuffer} from 'stream-buffers';
|
||||
import delay from 'delay';
|
||||
import {SECRET_REPLACEMENT} from '../lib/definitions/constants';
|
||||
import {
|
||||
const path = require('path');
|
||||
const test = require('ava');
|
||||
const proxyquire = require('proxyquire');
|
||||
const {escapeRegExp} = require('lodash');
|
||||
const {writeJson, readJson} = require('fs-extra');
|
||||
const execa = require('execa');
|
||||
const {WritableStreamBuffer} = require('stream-buffers');
|
||||
const delay = require('delay');
|
||||
const {SECRET_REPLACEMENT} = require('../lib/definitions/constants');
|
||||
const {
|
||||
gitHead,
|
||||
gitTagHead,
|
||||
gitRepo,
|
||||
@@ -17,11 +17,11 @@ import {
|
||||
gitCheckout,
|
||||
merge,
|
||||
gitGetNote,
|
||||
} from './helpers/git-utils';
|
||||
import {npmView} from './helpers/npm-utils';
|
||||
import gitbox from './helpers/gitbox';
|
||||
import mockServer from './helpers/mockserver';
|
||||
import npmRegistry from './helpers/npm-registry';
|
||||
} = require('./helpers/git-utils');
|
||||
const {npmView} = require('./helpers/npm-utils');
|
||||
const gitbox = require('./helpers/gitbox');
|
||||
const mockServer = require('./helpers/mockserver');
|
||||
const npmRegistry = require('./helpers/npm-registry');
|
||||
|
||||
/* eslint camelcase: ["error", {properties: "never"}] */
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import test from 'ava';
|
||||
import {noop} from 'lodash';
|
||||
import {stub} from 'sinon';
|
||||
import normalize from '../../lib/plugins/normalize';
|
||||
const test = require('ava');
|
||||
const {noop} = require('lodash');
|
||||
const {stub} = require('sinon');
|
||||
const normalize = require('../../lib/plugins/normalize');
|
||||
|
||||
const cwd = process.cwd();
|
||||
|
||||
@@ -268,11 +268,9 @@ test('Throws an error if the plugin return an object without the expected plugin
|
||||
});
|
||||
|
||||
test('Throws an error if the plugin is not found', t => {
|
||||
const error = t.throws(
|
||||
() => normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', 'non-existing-path', {}),
|
||||
Error
|
||||
);
|
||||
|
||||
t.regex(error.message, /Cannot find module 'non-existing-path'/);
|
||||
t.is(error.code, 'MODULE_NOT_FOUND');
|
||||
t.throws(() => normalize({cwd, options: {}, logger: t.context.logger}, 'inexistantPlugin', 'non-existing-path', {}), {
|
||||
message: /Cannot find module 'non-existing-path'/,
|
||||
code: 'MODULE_NOT_FOUND',
|
||||
instanceOf: Error,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import test from 'ava';
|
||||
import {stub} from 'sinon';
|
||||
import AggregateError from 'aggregate-error';
|
||||
import pipeline from '../../lib/plugins/pipeline';
|
||||
const test = require('ava');
|
||||
const {stub} = require('sinon');
|
||||
const AggregateError = require('aggregate-error');
|
||||
const pipeline = require('../../lib/plugins/pipeline');
|
||||
|
||||
test('Execute each function in series passing the same input', async t => {
|
||||
const step1 = stub().resolves(1);
|
||||
@@ -98,7 +98,10 @@ 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.throwsAsync(pipeline([step1, step2, step3])(0), Error);
|
||||
const error = await t.throwsAsync(pipeline([step1, step2, step3])(0), {
|
||||
instanceOf: Error,
|
||||
message: 'test error',
|
||||
});
|
||||
t.is(error.message, 'test error');
|
||||
t.true(step1.calledWith(0));
|
||||
t.true(step2.calledWith(0));
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import path from 'path';
|
||||
import test from 'ava';
|
||||
import {copy, outputFile} from 'fs-extra';
|
||||
import {stub} from 'sinon';
|
||||
import tempy from 'tempy';
|
||||
import getPlugins from '../../lib/plugins';
|
||||
const path = require('path');
|
||||
const test = require('ava');
|
||||
const {copy, outputFile} = require('fs-extra');
|
||||
const {stub} = require('sinon');
|
||||
const tempy = require('tempy');
|
||||
const getPlugins = require('../../lib/plugins');
|
||||
|
||||
// Save the current working diretory
|
||||
const cwd = process.cwd();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import test from 'ava';
|
||||
import {validatePlugin, validateStep, loadPlugin, parseConfig} from '../../lib/plugins/utils';
|
||||
const test = require('ava');
|
||||
const {validatePlugin, validateStep, loadPlugin, parseConfig} = require('../../lib/plugins/utils');
|
||||
|
||||
test('validatePlugin', t => {
|
||||
const path = 'plugin-module';
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
import test from 'ava';
|
||||
import AggregateError from 'aggregate-error';
|
||||
import {
|
||||
const test = require('ava');
|
||||
const AggregateError = require('aggregate-error');
|
||||
const {
|
||||
extractErrors,
|
||||
tagsToVersions,
|
||||
isMajorRange,
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
getRange,
|
||||
makeTag,
|
||||
isSameChannel,
|
||||
} from '../lib/utils';
|
||||
} = require('../lib/utils');
|
||||
|
||||
test('extractErrors', t => {
|
||||
const errors = [new Error('Error 1'), new Error('Error 2')];
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
import test from 'ava';
|
||||
import tempy from 'tempy';
|
||||
import verify from '../lib/verify';
|
||||
import {gitRepo} from './helpers/git-utils';
|
||||
const test = require('ava');
|
||||
const tempy = require('tempy');
|
||||
const verify = require('../lib/verify');
|
||||
const {gitRepo} = require('./helpers/git-utils');
|
||||
|
||||
test('Throw a AggregateError', async t => {
|
||||
const {cwd} = await gitRepo();
|
||||
|
||||
Reference in New Issue
Block a user