Merge branch 'master' into beta

This commit is contained in:
Pierre Vanduynslager 2019-10-29 11:57:31 -04:00
commit 3daf78081f
No known key found for this signature in database
GPG Key ID: E7684268B8C7E0A3
20 changed files with 149 additions and 45 deletions

View File

@ -6,7 +6,7 @@ services:
node_js:
- 12
- 10
- 8.15
- 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)

View File

@ -224,7 +224,7 @@ All the [semantic-release](https://github.com/semantic-release) repositories use
Before pushing your code changes make sure there are no linting errors with `npm run lint`.
**Tips**:
- Most linting errors can be automatically fixed with `npm run lint --fix`.
- Most linting errors can be automatically fixed with `npm run lint -- --fix`.
- Install the [XO plugin](https://github.com/sindresorhus/xo#editor-plugins) for your editor to see linting errors directly in your editor and automatically fix them on save.
### Tests

View File

@ -56,7 +56,7 @@ This removes the immediate connection between human emotions and version numbers
By default **semantic-release** uses [Angular Commit Message Conventions](https://github.com/angular/angular.js/blob/master/DEVELOPERS.md#-git-commit-guidelines). The commit message format can be changed with the [`preset` or `config` options](docs/usage/configuration.md#options) of the [@semantic-release/commit-analyzer](https://github.com/semantic-release/commit-analyzer#options) and [@semantic-release/release-notes-generator](https://github.com/semantic-release/release-notes-generator#options) plugins.
Tools such as [commitizen](https://github.com/commitizen/cz-cli), [commitlint](https://github.com/conventional-changelog/commitlint) or [semantic-git-commit-cli](https://github.com/JPeer264/node-semantic-git-commit-cli) can be used to help contributors and enforce valid commit messages.
Tools such as [commitizen](https://github.com/commitizen/cz-cli) or [commitlint](https://github.com/conventional-changelog/commitlint) can be used to help contributors and enforce valid commit messages.
Here is an example of the release type that will be done based on a commit messages:

View File

@ -4,6 +4,7 @@
- [CircleCI 2.0 workflows](circleci-workflows.md)
- [Travis CI](travis.md)
- [GitLab CI](gitlab-ci.md)
- [GitHub Actions](github-actions.md)
## Git hosted services
- [Git authentication with SSH keys](git-auth-ssh-keys.md)

View File

@ -0,0 +1,68 @@
# Using semantic-release with [GitHub Actions](https://help.github.com/en/categories/automating-your-workflow-with-github-actions)
## Environment variables
The [Authentication](../usage/ci-configuration.md#authentication) environment variables can be configured with [Secret Variables](https://help.github.com/en/articles/virtual-environments-for-github-actions#creating-and-using-secrets-encrypted-variables).
In this example an [`NPM_TOKEN`](https://docs.npmjs.com/creating-and-viewing-authentication-tokens) is required to publish a package to the npm registry. GitHub Actions [automatically populate](https://help.github.com/en/articles/virtual-environments-for-github-actions#github_token-secret) a [`GITHUB_TOKEN`](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line) environment variable which can be used in Workflows.
## Node project configuration
[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).
### `.github/workflows/release.yml` configuration for Node projects
The following is a minimal configuration for [`semantic-release`](https://github.com/semantic-release/semantic-release) with a build running on Node 12 when a new commit is pushed to a `master` branch. See [Configuring a Workflow](https://help.github.com/en/articles/configuring-a-workflow) for additional configuration options.
```yaml
name: Release
on:
push:
branches:
- master
jobs:
release:
name: Release
runs-on: ubuntu-18.04
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: 12
- name: Install dependencies
run: npm ci
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
```
## Pushing `package.json` changes to a `master` branch
To keep `package.json` updated in the `master` branch, [`@semantic-release/git`](https://github.com/semantic-release/git) plugin can be used.
**Note**: Automatically populated `GITHUB_TOKEN` cannot be used if branch protection is enabled for the target branch. It is **not** advised to mitigate this limitation by overriding an automatically populated `GITHUB_TOKEN` variable with a [Personal Access Tokens](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line), as it poses a security risk. Since Secret Variables are available for Workflows triggered by any branch, it becomes a potential vector of attack, where a Workflow triggered from a non-protected branch can expose and use a token with elevated permissions, yielding branch protection insignificant. One can use Personal Access Tokens in trusted environments, where all developers should have the ability to perform administrative actions in the given repository and branch protection is enabled solely for convenience purposes, to remind about required reviews or CI checks.
## Trigger semantic-release on demand
There is a way to trigger semantic-relase on demand. Use [`repository_dispatch`](https://help.github.com/en/articles/events-that-trigger-workflows#external-events-repository_dispatch) event to have control on when to generate a release by making an HTTP request, e.g.:
```yaml
name: Release
on:
repository_dispatch:
types: [semantic-release]
jobs:
# ...
```
To trigger a release, call (with a [Personal Access Tokens](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) stored in `GITHUB_TOKEN` environment variable):
```
$ curl -v -H "Accept: application/vnd.github.everest-preview+json" -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/repos/[org-name-or-username]/[repository]/dispatches -d '{ "event_type": "semantic-release" }'
```

View File

@ -8,7 +8,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 version](../support/FAQ.md#why-does-semantic-release-require-node-version--815).
**Note**: The publish pipeline must run a [Node >= 8.16 version](../support/FAQ.md#why-does-semantic-release-require-node-version--816).
### `.gitlab-ci.yml` configuration for Node projects

View File

@ -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.15](#why-does-semantic-release-require-node-version--815) 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 >= 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.
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.15.
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.
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](#why-does-semantic-release-require-node-version--83) to execute the `semantic-release` command
- 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
See the [CI configuration recipes](../recipes/README.md#ci-configurations) for more details on specific CI environments.
@ -141,11 +141,11 @@ See the [`@semantic-release/npm`](https://github.com/semantic-release/npm#semant
If you have introduced a breaking bug in a release you have 2 options:
- If you have a fix immediately ready, commit and push it (or merge it via a pull request) to the release branch
- Otherwise [revert the commit](https://git-scm.com/docs/git-revert) that introduced the bug and push the revert commit (or merge it via a pull request) to the release branch
- Otherwise, [revert the commit](https://git-scm.com/docs/git-revert) that introduced the bug and push the revert commit (or merge it via a pull request) to the release branch
In both cases **semantic-release** will publish a new release, so your package users' will get the fixed/reverted version.
In both cases **semantic-release** will publish a new release, so your package users will get the fixed/reverted version.
Depending on the package manager you are using, you might be able to un-publish or deprecate a release, in order to prevent users from downloading it by accident. For example npm allows you to [un-publish](https://docs.npmjs.com/cli/unpublish) [within 72 hours](https://www.npmjs.com/policies/unpublish) after releasing. You may also [deprecate](https://docs.npmjs.com/cli/deprecate) a release if you would rather avoid un-publishing.
Depending on the package manager you are using, you might be able to un-publish or deprecate a release, in order to prevent users from downloading it by accident. For example, npm allows you to [un-publish](https://docs.npmjs.com/cli/unpublish) [within 72 hours](https://www.npmjs.com/policies/unpublish) after release. You may also [deprecate](https://docs.npmjs.com/cli/deprecate) a release if you would rather avoid un-publishing.
In any case **do not remove the Git tag associated with the buggy version**, otherwise **semantic-release** will later try to republish that version. Publishing a version after un-publishing is not supported by most package managers.
@ -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.15?
## Why does semantic-release require Node version >= 8.16?
**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.15 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 8.16 or higher**.
See [Node version requirement](./node-version.md#node-version-requirement) for more details and solutions.

View File

@ -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.15 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 8.16 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.15
### Run at least one CI job with Node >= 8.16
The recommended approach is to run the `semantic-release` command from a CI job running on Node 8.15 or higher. This can either be a job used by your project to test on Node >= 8.15 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 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.
See [CI configuration](../usage/ci-configuration.md) and [CI configuration recipes](../recipes/README.md#ci-configurations) for more details.

View File

@ -6,6 +6,7 @@ The `semantic-release` command must be executed only after all the tests in the
Here is a few example of the CI services that can be used to achieve this:
- [Travis Build Stages](https://docs.travis-ci.com/user/build-stages)
- [CircleCI Workflows](https://circleci.com/docs/2.0/workflows)
- [GitHub Actions](https://github.com/features/actions)
- [Codeship Deployment Pipelines](https://documentation.codeship.com/basic/builds-and-configuration/deployment-pipelines)
- [GitLab Pipelines](https://docs.gitlab.com/ee/ci/pipelines.html#introduction-to-pipelines-and-jobs)
- [Codefresh Pipelines](https://codefresh.io/docs/docs/configure-ci-cd-pipeline/introduction-to-codefresh-pipelines)

View File

@ -29,14 +29,15 @@ Please make sure to add the \`repositoryUrl\` to the [semantic-release configura
)}).`,
}),
EGITNOPERMISSION: ({options: {repositoryUrl}, branch: {name}}) => ({
message: 'The push permission to the Git repository is required.',
details: `**semantic-release** cannot push the version tag to the branch \`${name}\` on remote Git repository with URL \`${repositoryUrl}\`.
message: 'Cannot push to the Git repository.',
details: `**semantic-release** cannot push the version tag to the branch \`${name}\` on the remote Git repository with URL \`${repositoryUrl}\`.
Please refer to the [authentication configuration documentation](${linkify(
'docs/usage/ci-configuration.md#authentication'
)}) to configure the Git credentials on your CI environment and make sure the [repositoryUrl](${linkify(
'docs/usage/configuration.md#repositoryurl'
)}) is configured with a [valid Git URL](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols).`,
This can be caused by:
- a misconfiguration of the [repositoryUrl](${linkify('docs/usage/configuration.md#repositoryurl')}) option
- the repository being unavailable
- or missing push permission for the user configured via the [Git credentials on your CI environment](${linkify(
'docs/usage/ci-configuration.md#authentication'
)})`,
}),
EINVALIDTAGFORMAT: ({options: {tagFormat}}) => ({
message: 'Invalid `tagFormat` option.',
@ -183,7 +184,7 @@ Your configuration for the problematic branches is \`${stringify(branches)}\`.`,
details: `A minimum of 1 and a maximum of 3 release branches are required in the [branches configuration](${linkify(
'docs/usage/configuration.md#branches'
)}).
This may occur if your repository does not have a release branch, such as \`master\`.
Your configuration for the problematic branches is \`${stringify(branches)}\`.`,

View File

@ -1,3 +1,5 @@
/* eslint require-atomic-updates: off */
const {isString, isPlainObject} = require('lodash');
const {getGitHead} = require('../git');
const hideSensitive = require('../hide-sensitive');

View File

@ -93,6 +93,6 @@ module.exports = async (context, opts) => {
};
async function pkgRepoUrl(opts) {
const {package: pkg} = (await readPkgUp(opts)) || {};
return pkg && (isPlainObject(pkg.repository) ? pkg.repository.url : pkg.repository);
const {packageJson} = (await readPkgUp(opts)) || {};
return packageJson && (isPlainObject(packageJson.repository) ? packageJson.repository.url : packageJson.repository);
}

View File

@ -41,16 +41,21 @@ module.exports = async ({cwd, env, branch, options: {repositoryUrl}}) => {
// Test if push is allowed without transforming the URL (e.g. is ssh keys are set up)
try {
await verifyAuth(repositoryUrl, branch.name, {cwd, env});
} catch (error) {
} catch (_) {
const envVar = Object.keys(GIT_TOKENS).find(envVar => !isNil(env[envVar]));
const gitCredentials = `${GIT_TOKENS[envVar] || ''}${env[envVar] || ''}`;
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 {port, hostname, ...parsed} = parse(
match ? `ssh://${auth ? `${auth}@` : ''}${host}/${path}` : repositoryUrl
);
return format({
...parse(match ? `ssh://${auth ? `${auth}@` : ''}${host}/${path}` : repositoryUrl),
...parsed,
auth: gitCredentials,
host: `${hostname}${protocol === 'ssh:' ? '' : port ? `:${port}` : ''}`,
protocol: protocol && /http[^s]/.test(protocol) ? 'http' : 'https',
});
}

View File

@ -147,7 +147,7 @@ async function fetch(repositoryUrl, branch, execaOpts) {
],
execaOpts
);
} catch (error) {
} catch (_) {
await execa(
'git',
[

View File

@ -31,7 +31,7 @@
"cosmiconfig": "^5.0.1",
"debug": "^4.0.0",
"env-ci": "^4.0.0",
"execa": "^3.0.0",
"execa": "^3.2.0",
"figures": "^3.0.0",
"find-versions": "^3.0.0",
"get-stream": "^5.0.0",
@ -44,7 +44,7 @@
"micromatch": "3.1.5",
"p-each-series": "^1.0.0",
"p-reduce": "^2.0.0",
"read-pkg-up": "^6.0.0",
"read-pkg-up": "^7.0.0",
"resolve-from": "^5.0.0",
"semver": "^6.0.0",
"semver-diff": "^2.1.0",
@ -56,7 +56,7 @@
"clear-module": "^4.0.0",
"codecov": "^3.0.0",
"delay": "^4.0.0",
"dockerode": "^2.5.2",
"dockerode": "^3.0.0",
"file-url": "^3.0.0",
"fs-extra": "^8.0.0",
"got": "^9.0.0",
@ -69,10 +69,10 @@
"sinon": "^7.2.7",
"stream-buffers": "^3.0.2",
"tempy": "^0.3.0",
"xo": "^0.24.0"
"xo": "^0.25.0"
},
"engines": {
"node": ">=8.15"
"node": ">=8.16"
},
"files": [
"bin",

View File

@ -175,7 +175,7 @@ test.serial('Display help', async t => {
t.is(exitCode, 0);
});
test.serial('Return error code and prints help if called with a command', 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}});
@ -187,7 +187,7 @@ test.serial('Return error code and prints help if called with a command', async
t.is(exitCode, 1);
});
test.serial('Return error code if multiple plugin are set for single plugin', async t => {
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}});
@ -199,7 +199,7 @@ test.serial('Return error code if multiple plugin are set for single plugin', as
t.is(exitCode, 1);
});
test.serial('Return error code if semantic-release throw error', async t => {
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}});

View File

@ -86,9 +86,9 @@ test('Convert shorthand URL', async t => {
cwd,
env,
branch: {name: 'master'},
options: {repositoryUrl: 'semanitc-release/semanitc-release'},
options: {repositoryUrl: 'semantic-release/semantic-release'},
}),
'https://github.com/semanitc-release/semanitc-release.git'
'https://github.com/semantic-release/semantic-release.git'
);
});
@ -100,9 +100,9 @@ test('Convert GitLab shorthand URL', async t => {
cwd,
env,
branch: {name: 'master'},
options: {repositoryUrl: 'gitlab:semanitc-release/semanitc-release'},
options: {repositoryUrl: 'gitlab:semantic-release/semantic-release'},
}),
'https://gitlab.com/semanitc-release/semanitc-release.git'
'https://gitlab.com/semantic-release/semantic-release.git'
);
});
@ -161,6 +161,19 @@ test('Return the "http" formatted URL if "gitCredentials" is defined and reposit
);
});
test('Return the "http" formatted URL if "gitCredentials" is defined and repositoryUrl is a "http" URL with custom port', async t => {
const {cwd} = await gitRepo();
t.is(
await getAuthUrl({
cwd,
env: {...env, GIT_CREDENTIALS: 'user:pass'},
options: {branch: 'master', repositoryUrl: 'http://host.null:8080/owner/repo.git'},
}),
'http://user:pass@host.null:8080/owner/repo.git'
);
});
test('Return the "https" formatted URL if "gitCredentials" is defined and repositoryUrl is a "git+https" URL', async t => {
const {cwd} = await gitRepo();
@ -189,6 +202,19 @@ test('Return the "http" formatted URL if "gitCredentials" is defined and reposit
);
});
test('Return the "http" formatted URL if "gitCredentials" is defined and repositoryUrl is a "ssh" URL', async t => {
const {cwd} = await gitRepo();
t.is(
await getAuthUrl({
cwd,
env: {...env, GIT_CREDENTIALS: 'user:pass'},
options: {branch: 'master', repositoryUrl: 'ssh://git@host.null:2222/owner/repo.git'},
}),
'https://user:pass@host.null/owner/repo.git'
);
});
test('Return the "https" formatted URL if "gitCredentials" is defined with "GH_TOKEN"', async t => {
const {cwd} = await gitRepo();

View File

@ -99,10 +99,10 @@ export async function gitGetCommits(from, execaOpts) {
* Checkout a branch on the current git repository.
*
* @param {String} branch Branch name.
* @param {Boolean} create `true` to create the branch, `false` to checkout an existing branch.
* @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 = true, execaOpts) {
export async function gitCheckout(branch, create, execaOpts) {
await execa('git', create ? ['checkout', '-b', branch] : ['checkout', branch], execaOpts);
}
@ -223,7 +223,7 @@ export async function gitCommitTag(gitHead, execaOpts) {
*
* @throws {Error} if the push failed.
*/
export async function gitPush(repositoryUrl = 'origin', branch = 'master', execaOpts) {
export async function gitPush(repositoryUrl, branch, execaOpts) {
await execa('git', ['push', '--tags', repositoryUrl, `HEAD:${branch}`], execaOpts);
}

View File

@ -30,7 +30,7 @@ async function start() {
minTimeout: 1000,
factor: 2,
});
} catch (error) {
} catch (_) {
throw new Error(`Couldn't start mock-server after 2 min`);
}
}

View File

@ -39,7 +39,7 @@ async function start() {
minTimeout: 1000,
factor: 2,
});
} catch (error) {
} catch (_) {
throw new Error(`Couldn't start npm-registry-docker after 2 min`);
}