semantic-release 13.2.0 → 13.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/cli.js +53 -48
- package/docs/README.md +1 -1
- package/docs/extending/plugins-list.md +5 -1
- package/docs/recipes/circleci-workflows.md +65 -1
- package/docs/recipes/gitlab-ci.md +2 -8
- package/docs/recipes/travis-build-stages.md +94 -0
- package/docs/recipes/travis.md +5 -22
- package/docs/support/FAQ.md +1 -1
- package/docs/usage/configuration.md +26 -2
- package/docs/usage/plugins.md +12 -0
- package/index.js +77 -35
- package/lib/definitions/errors.js +118 -0
- package/lib/definitions/plugins.js +61 -0
- package/lib/definitions/release-types.js +1 -0
- package/lib/get-config.js +5 -5
- package/lib/get-error.js +7 -0
- package/lib/git.js +0 -1
- package/lib/plugins/index.js +14 -13
- package/lib/plugins/normalize.js +26 -17
- package/lib/plugins/pipeline.js +38 -16
- package/lib/utils.js +7 -0
- package/lib/verify.js +7 -22
- package/package.json +6 -6
- package/lib/plugins/definitions.js +0 -55
package/README.md
CHANGED
|
@@ -37,10 +37,11 @@ This removes the immediate connection between human emotions and version numbers
|
|
|
37
37
|
- Fully automated release
|
|
38
38
|
- Enforce [Semantic Versioning](https://semver.org) specification
|
|
39
39
|
- New features and fixes are immediately available to users
|
|
40
|
+
- Notify maintainers and users of new releases
|
|
40
41
|
- Use formalized commit message convention to document changes in the codebase
|
|
41
42
|
- Integrate with your [continuous integration workflow](docs/recipes/README.md#ci-configurations)
|
|
42
43
|
- Avoid potential errors associated with manual releases
|
|
43
|
-
- Support any
|
|
44
|
+
- Support any [package managers and languages](docs/recipes/README.md#package-managers-and-languages) via [plugins](docs/usage/plugins.md)
|
|
44
45
|
- Simple and reusable configuration via [shareable configurations](docs/usage/shareable-configurations.md)
|
|
45
46
|
|
|
46
47
|
## How does it work?
|
|
@@ -67,7 +68,7 @@ Here is an example of the release type that will be done based on a commit messa
|
|
|
67
68
|
|
|
68
69
|
### Triggering a release
|
|
69
70
|
|
|
70
|
-
When pushing new commits to the release branch (i.e. `master`) with `git push` or by merging a pull request or merging from another branch, a CI build is triggered and runs the `semantic-release` command to make a release if there
|
|
71
|
+
When pushing new commits to the release branch (i.e. `master`) with `git push` or by merging a pull request or merging from another branch, a CI build is triggered and runs the `semantic-release` command to make a release if there are relevant codebase changes since the last release.
|
|
71
72
|
|
|
72
73
|
By default a release will be done for each push to the release branch that contains relevant code changes. If you need more control over the timing of releases you have a couple of options:
|
|
73
74
|
- Publish releases on a distribution channel (for example npm’s [dist-tags](https://docs.npmjs.com/cli/dist-tag)). This way you can keep control over what your users end up using by default, and you can decide when to make an automatically released version available to the stable channel, and promote it.
|
|
@@ -86,6 +87,7 @@ After running the tests the command `semantic-release` will execute the followin
|
|
|
86
87
|
| Generate notes | Generate release notes with the [generate notes plugin](docs/usage/plugins.md#generatenotes-plugin) for the commits added since the last release. |
|
|
87
88
|
| Create Git tag | Create a Git tag corresponding the new release version |
|
|
88
89
|
| Publish | Publish the release with the [publish plugins](docs/usage/plugins.md#publish-plugin). |
|
|
90
|
+
| Notify | Notify of new releases or errors with the [success](docs/usage/plugins.md#success-plugin) and [fail](docs/usage/plugins.md#fail-plugin) plugins. |
|
|
89
91
|
|
|
90
92
|
## Documentation
|
|
91
93
|
|
package/cli.js
CHANGED
|
@@ -1,59 +1,64 @@
|
|
|
1
|
-
const program = require('commander');
|
|
2
1
|
const {pickBy, isUndefined} = require('lodash');
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
const stringList = {
|
|
4
|
+
type: 'string',
|
|
5
|
+
array: true,
|
|
6
|
+
coerce: values =>
|
|
7
|
+
values.length === 1 && values[0].trim() === 'false'
|
|
8
|
+
? []
|
|
9
|
+
: values.reduce((values, value) => values.concat(value.split(',').map(value => value.trim())), []),
|
|
10
|
+
};
|
|
7
11
|
|
|
8
12
|
module.exports = async () => {
|
|
9
|
-
|
|
10
|
-
.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.option('
|
|
16
|
-
.option(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
)
|
|
21
|
-
.option('
|
|
22
|
-
.option(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)
|
|
27
|
-
.option('
|
|
28
|
-
.option('
|
|
29
|
-
.option(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
.option('--debug', 'Output debugging information')
|
|
34
|
-
.option(
|
|
35
|
-
'-d, --dry-run',
|
|
36
|
-
'Dry-run mode, skipping verifyConditions, publishing and release, printing next version and release notes'
|
|
37
|
-
)
|
|
38
|
-
.parse(process.argv);
|
|
39
|
-
|
|
40
|
-
if (program.debug) {
|
|
41
|
-
// Debug must be enabled before other requires in order to work
|
|
42
|
-
require('debug').enable('semantic-release:*');
|
|
43
|
-
}
|
|
13
|
+
const cli = require('yargs')
|
|
14
|
+
.command('$0', 'Run automated package publishing', yargs => {
|
|
15
|
+
yargs.demandCommand(0, 0).usage(`Run automated package publishing
|
|
16
|
+
Usage:
|
|
17
|
+
semantic-release [options] [plugins]`);
|
|
18
|
+
})
|
|
19
|
+
.option('b', {alias: 'branch', describe: 'Git branch to release from', type: 'string', group: 'Options'})
|
|
20
|
+
.option('r', {alias: 'repository-url', describe: 'Git repository URL', type: 'string', group: 'Options'})
|
|
21
|
+
.option('t', {alias: 'tag-format', describe: 'Git tag format', type: 'string', group: 'Options'})
|
|
22
|
+
.option('e', {alias: 'extends', describe: 'Shareable configurations', ...stringList, group: 'Options'})
|
|
23
|
+
.option('ci', {describe: 'Toggle CI verifications', default: true, type: 'boolean', group: 'Options'})
|
|
24
|
+
.option('verify-conditions', {...stringList, group: 'Plugins'})
|
|
25
|
+
.option('analyze-commits', {type: 'string', group: 'Plugins'})
|
|
26
|
+
.option('verify-release', {...stringList, group: 'Plugins'})
|
|
27
|
+
.option('generate-notes', {type: 'string', group: 'Plugins'})
|
|
28
|
+
.option('publish', {...stringList, group: 'Plugins'})
|
|
29
|
+
.option('success', {...stringList, group: 'Plugins'})
|
|
30
|
+
.option('fail', {...stringList, group: 'Plugins'})
|
|
31
|
+
.option('debug', {describe: 'Output debugging information', default: false, type: 'boolean', group: 'Options'})
|
|
32
|
+
.option('d', {alias: 'dry-run', describe: 'Skip publishing', default: false, type: 'boolean', group: 'Options'})
|
|
33
|
+
.option('h', {alias: 'help', group: 'Options'})
|
|
34
|
+
.option('v', {alias: 'version', group: 'Options'})
|
|
35
|
+
.strict(false)
|
|
36
|
+
.exitProcess(false);
|
|
44
37
|
|
|
45
38
|
try {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
process.exitCode =
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
const {help, version, ...opts} = cli.argv;
|
|
40
|
+
if (Boolean(help) || Boolean(version)) {
|
|
41
|
+
process.exitCode = 0;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Set the `noCi` options as yargs sets the `ci` options instead (because arg starts with `--no`)
|
|
46
|
+
if (opts.ci === false) {
|
|
47
|
+
opts.noCi = true;
|
|
55
48
|
}
|
|
49
|
+
|
|
50
|
+
if (opts.debug) {
|
|
51
|
+
// Debug must be enabled before other requires in order to work
|
|
52
|
+
require('debug').enable('semantic-release:*');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Remove option with undefined values, as yargs sets non defined options as `undefined`
|
|
56
|
+
await require('.')(pickBy(opts, value => !isUndefined(value)));
|
|
57
|
+
process.exitCode = 0;
|
|
56
58
|
} catch (err) {
|
|
59
|
+
if (err.name !== 'YError') {
|
|
60
|
+
console.error(err);
|
|
61
|
+
}
|
|
57
62
|
process.exitCode = 1;
|
|
58
63
|
}
|
|
59
64
|
};
|
package/docs/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# semantic-release documentation
|
|
2
2
|
|
|
3
3
|
- [Usage](usage/README.md) - **semantic-release** installation and configuration
|
|
4
|
-
- [Extending]
|
|
4
|
+
- [Extending](extending/README.md)- Extending **semantic-release** with plugins and shareable configurations
|
|
5
5
|
- [Recipes](recipes/README.md) - Community written recipes for common **semantic-release** use-cases
|
|
6
6
|
- [Developer Guide](developer-guide/README.md) - The essentials of writing a **semantic-release** plugin or shareable configurations
|
|
7
7
|
- [Resources](resources.md) - Videos, articles and tutorials
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
- [@semantic-release/github](https://github.com/semantic-release/github)
|
|
6
6
|
- [verifyConditions](https://github.com/semantic-release/github#verifyconditions): Verify the presence and the validity of the GitHub authentication and release configuration
|
|
7
7
|
- [publish](https://github.com/semantic-release/github#publish): Publish a [GitHub release](https://help.github.com/articles/about-releases)
|
|
8
|
+
- [success](https://github.com/semantic-release/github#success): Add a comment to GitHub issues and pull requests resolved in the release
|
|
9
|
+
- [fail](https://github.com/semantic-release/github#fail): Open a GitHub issue when a release fails
|
|
8
10
|
- [@semantic-release/npm](https://github.com/semantic-release/npm)
|
|
9
11
|
- [verifyConditions](https://github.com/semantic-release/npm#verifyconditions): Verify the presence and the validity of the npm authentication and release configuration
|
|
10
12
|
- [publish](https://github.com/semantic-release/npm#publish): Publish the package on the npm registry
|
|
@@ -25,6 +27,8 @@
|
|
|
25
27
|
- [analyzeCommits](https://github.com/semantic-release/exec#analyzecommits): Execute a shell command to determine the type of release
|
|
26
28
|
- [verifyRelease](https://github.com/semantic-release/exec#verifyrelease): Execute a shell command to verifying a release that was determined before and is about to be published.
|
|
27
29
|
- [generateNotes](https://github.com/semantic-release/exec#analyzecommits): Execute a shell command to generate the release note
|
|
28
|
-
- [publish](https://github.com/semantic-release/exec#publish): Execute a shell command to publish the release
|
|
30
|
+
- [publish](https://github.com/semantic-release/exec#publish): Execute a shell command to publish the release
|
|
31
|
+
- [success](https://github.com/semantic-release/exec#success): Execute a shell command to notify of a new release
|
|
32
|
+
- [fail](https://github.com/semantic-release/exec#fail): Execute a shell command to notify of a failed release
|
|
29
33
|
|
|
30
34
|
## Community plugins
|
|
@@ -1 +1,65 @@
|
|
|
1
|
-
# CircleCI 2.0 workflows
|
|
1
|
+
# Using semantic-release with [CircleCI 2.0 workflows](https://circleci.com/docs/2.0/workflows)
|
|
2
|
+
|
|
3
|
+
## Environment variables
|
|
4
|
+
|
|
5
|
+
The [Authentication](../usage/ci-configuration.md#authentication) environment variables can be configured in [CircleCi Project Settings](https://circleci.com/docs/2.0/env-vars/#adding-environment-variables-in-the-app)..
|
|
6
|
+
|
|
7
|
+
Alternatively, the default `NPM_TOKEN` and `GH_TOKEN` can be easily [setup with semantic-release-cli](../usage/ci-configuration.md#automatic-setup-with-semantic-release-cli).
|
|
8
|
+
|
|
9
|
+
## Multiple Node jobs configuration
|
|
10
|
+
|
|
11
|
+
### `.circleci/config.yml` configuration for multiple Node jobs
|
|
12
|
+
|
|
13
|
+
This example is a minimal configuration for **semantic-release** with a build running Node 6 and 8. See [CircleCI documentation](https://circleci.com/docs/2.0) for additional configuration options.
|
|
14
|
+
|
|
15
|
+
This example create the workflows `test_node_4`, `test_node_6`, `test_node_8` and `release`. The release workflows will [run `semantic-release` only after the all the `test_node_*` are successful](../usage/ci-configuration.md#run-semantic-release-only-after-all-tests-succeeded).
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
version: 2
|
|
19
|
+
jobs:
|
|
20
|
+
test_node_6:
|
|
21
|
+
docker:
|
|
22
|
+
- image: circleci/node:6
|
|
23
|
+
steps:
|
|
24
|
+
# Configure your test steps here (checkout, npm install, cache management, tests etc...)
|
|
25
|
+
|
|
26
|
+
test_node_8:
|
|
27
|
+
docker:
|
|
28
|
+
- image: circleci/node:8
|
|
29
|
+
steps:
|
|
30
|
+
# Configure your test steps here (checkout, npm install, cache management, tests etc...)
|
|
31
|
+
|
|
32
|
+
release:
|
|
33
|
+
docker:
|
|
34
|
+
- image: circleci/node:8
|
|
35
|
+
steps:
|
|
36
|
+
- checkout
|
|
37
|
+
- run: npm install
|
|
38
|
+
# Run optional required steps before releasing
|
|
39
|
+
# - run: npm run build-script
|
|
40
|
+
- run: npx semantic-release
|
|
41
|
+
|
|
42
|
+
workflows:
|
|
43
|
+
version: 2
|
|
44
|
+
test_and_release:
|
|
45
|
+
# Run the test jobs first, then the release only when all the test jobs are successful
|
|
46
|
+
jobs:
|
|
47
|
+
- test_node_6
|
|
48
|
+
- test_node_8
|
|
49
|
+
- release:
|
|
50
|
+
requires:
|
|
51
|
+
- test_node_6
|
|
52
|
+
- test_node_8
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `package.json` configuration for multiple Node jobs
|
|
56
|
+
|
|
57
|
+
A `package.json` is required only for [local](../usage/installation.md#local-installation) **semantic-release** installation.
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"semantic-release": "^12.0.0"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
@@ -8,11 +8,11 @@ The [Authentication](../usage/ci-configuration.md#authentication) environment va
|
|
|
8
8
|
|
|
9
9
|
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.
|
|
10
10
|
|
|
11
|
-
**Note**: The publish pipeline must run a [Node >= 8 version](../support/FAQ.md#why-does-semantic-release-require-node-version--
|
|
11
|
+
**Note**: The publish pipeline must run a [Node >= 8 version](../support/FAQ.md#why-does-semantic-release-require-node-version--83).
|
|
12
12
|
|
|
13
13
|
### `.gitlab-ci.yml` configuration for Node projects
|
|
14
14
|
|
|
15
|
-
This example is a minimal configuration for **semantic-release** with a build running Node
|
|
15
|
+
This example is a minimal configuration for **semantic-release** with a build running Node 6 and 8. See [GitLab CI - Configuration of your jobs with .gitlab-ci.yml](https://docs.gitlab.com/ee/ci/yaml/README.html) for additional configuration options.
|
|
16
16
|
|
|
17
17
|
**Note**: The`semantic-release` execution command varies depending if you are using a [local](../usage/installation.md#local-installation) or [global](../usage/installation.md#global-installation) **semantic-release** installation.
|
|
18
18
|
|
|
@@ -25,12 +25,6 @@ stages:
|
|
|
25
25
|
before_script:
|
|
26
26
|
- npm install
|
|
27
27
|
|
|
28
|
-
node:4:
|
|
29
|
-
image: node:4
|
|
30
|
-
stage: test
|
|
31
|
-
script:
|
|
32
|
-
- npm test
|
|
33
|
-
|
|
34
28
|
node:6:
|
|
35
29
|
image: node:6
|
|
36
30
|
stage: test
|
|
@@ -1 +1,95 @@
|
|
|
1
1
|
# Using semantic-release with [Travis CI build stages](https://docs.travis-ci.com/user/build-stages)
|
|
2
|
+
|
|
3
|
+
## Environment variables
|
|
4
|
+
|
|
5
|
+
The [Authentication](../usage/ci-configuration.md#authentication) environment variables can be configured in [Travis Repository Settings](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-Settings) or with the [travis env set CLI](https://github.com/travis-ci/travis.rb#env).
|
|
6
|
+
|
|
7
|
+
Alternatively, the default `NPM_TOKEN` and `GH_TOKEN` can be easily [setup with semantic-release-cli](../usage/ci-configuration.md#automatic-setup-with-semantic-release-cli).
|
|
8
|
+
|
|
9
|
+
## Multiple Node jobs configuration
|
|
10
|
+
|
|
11
|
+
### `.travis.yml` configuration for multiple Node jobs
|
|
12
|
+
|
|
13
|
+
This example is a minimal configuration for **semantic-release** with a build running Node 6 and 8. See [Travis - Customizing the Build](https://docs.travis-ci.com/user/customizing-the-build) for additional configuration options.
|
|
14
|
+
|
|
15
|
+
This example creates a `release` [build stage](https://docs.travis-ci.com/user/build-stages) that [runs `semantic-release` only after all test jobs are successful](../usage/ci-configuration.md#run-semantic-release-only-after-all-tests-succeeded).
|
|
16
|
+
|
|
17
|
+
It's recommended to run the `semantic-release` command in the [Travis `deploy` step](https://docs.travis-ci.com/user/customizing-the-build/#The-Build-Lifecycle) so if an error occurs the build will fail and Travis will send a notification.
|
|
18
|
+
|
|
19
|
+
**Note**: It's not recommended to run the `semantic-release` command in the Travis `script` step as each script in this step will be executed regardless of the outcome of the previous one. See [travis-ci/travis-ci#1066](https://github.com/travis-ci/travis-ci/issues/1066).
|
|
20
|
+
|
|
21
|
+
**Advanced configuration**: Running the tests in the `script` step of the `release` stage is not necessary as the previous stage(s) already ran them. To increase speed, the `script` step of the `release` stage can be overwritten to skip the tests. Note that other commands such as build or compilation might still be required.
|
|
22
|
+
|
|
23
|
+
```yaml
|
|
24
|
+
language: node_js
|
|
25
|
+
|
|
26
|
+
node_js:
|
|
27
|
+
- 8
|
|
28
|
+
- 6
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
include:
|
|
32
|
+
# Define the release stage that runs semantic-release
|
|
33
|
+
- stage: release
|
|
34
|
+
node_js: lts/*
|
|
35
|
+
# Advanced: optionally overwrite your default `script` step to skip the tests
|
|
36
|
+
# script: skip
|
|
37
|
+
deploy:
|
|
38
|
+
provider: script
|
|
39
|
+
skip_cleanup: true
|
|
40
|
+
script:
|
|
41
|
+
- npx semantic-release
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### `package.json` configuration for multiple Node jobs
|
|
45
|
+
|
|
46
|
+
A `package.json` is required only for [local](../usage/installation.md#local-installation) **semantic-release** installation.
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"semantic-release": "^12.0.0"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Non-JavaScript projects configuration
|
|
57
|
+
|
|
58
|
+
For projects that require to be tested with one or multiple version of a Non-JavaScript [language](https://docs.travis-ci.com/user/languages), optionally on multiple [Operating Systems](https://docs.travis-ci.com/user/multi-os).
|
|
59
|
+
|
|
60
|
+
This recipe cover the Travis specifics only. See [Non JavaScript projects recipe](../support/FAQ.md#can-i-use-semantic-release-to-publish-non-javascript-packages) for more information on the **semantic-release** configuration.
|
|
61
|
+
|
|
62
|
+
### `.travis.yml` configuration for non-JavaScript projects
|
|
63
|
+
|
|
64
|
+
This example is a minimal configuration for **semantic-release** with a build running [Go 1.6 and 1.7](https://docs.travis-ci.com/user/languages/go). See [Travis - Customizing the Build](https://docs.travis-ci.com/user/customizing-the-build) for additional configuration options.
|
|
65
|
+
|
|
66
|
+
This example creates a `release` [build stage](https://docs.travis-ci.com/user/build-stages) that [runs `semantic-release` only after all test jobs are successful](../usage/ci-configuration.md#run-semantic-release-only-after-all-tests-succeeded).
|
|
67
|
+
|
|
68
|
+
It's recommended to run the `semantic-release` command in the [Travis `deploy` step](https://docs.travis-ci.com/user/customizing-the-build/#The-Build-Lifecycle) so if an error occurs the build will fail and Travis will send a notification.
|
|
69
|
+
|
|
70
|
+
**Note**: It's not recommended to run the `semantic-release` command in the Travis `script` step as each script in this step will be executed regardless of the outcome of the previous one. See [travis-ci/travis-ci#1066](https://github.com/travis-ci/travis-ci/issues/1066).
|
|
71
|
+
|
|
72
|
+
**Advanced configuration**: Running the tests in the `script` step of the `release` stage is not necessary as the previous stage(s) already ran them. To increase speed, the `script` step of the `release` stage can be overwritten to skip the tests. Note that other commands such as build or compilation might still be required.
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
language: go
|
|
76
|
+
|
|
77
|
+
go:
|
|
78
|
+
- 1.6
|
|
79
|
+
- 1.7
|
|
80
|
+
|
|
81
|
+
jobs:
|
|
82
|
+
include:
|
|
83
|
+
# Define the release stage that runs semantic-release
|
|
84
|
+
- stage: release
|
|
85
|
+
# Advanced: optionally overwrite your default `script` step to skip the tests
|
|
86
|
+
# script:
|
|
87
|
+
# - make
|
|
88
|
+
deploy:
|
|
89
|
+
provider: script
|
|
90
|
+
skip_cleanup: true
|
|
91
|
+
script:
|
|
92
|
+
# Use nvm to install and use the Node LTS version (nvm is installed on all Travis images)
|
|
93
|
+
- nvm install lts/*
|
|
94
|
+
- npx semantic-release
|
|
95
|
+
```
|
package/docs/recipes/travis.md
CHANGED
|
@@ -10,7 +10,7 @@ Alternatively, the default `NPM_TOKEN` and `GH_TOKEN` can be easily [setup with
|
|
|
10
10
|
|
|
11
11
|
For projects that require to be tested only with a single [Node version](https://docs.travis-ci.com/user/getting-started/#Selecting-a-different-programming-language) on [one Operating System](https://docs.travis-ci.com/user/getting-started/#Selecting-infrastructure-(optional)).
|
|
12
12
|
|
|
13
|
-
**Note**: [Node 8 is the minimal version required](../support/FAQ.md#why-does-semantic-release-require-node-version--
|
|
13
|
+
**Note**: [Node 8 is the minimal version required](../support/FAQ.md#why-does-semantic-release-require-node-version--83).
|
|
14
14
|
|
|
15
15
|
### `.travis.yml` configuration for single Node job
|
|
16
16
|
|
|
@@ -25,10 +25,6 @@ language: node_js
|
|
|
25
25
|
|
|
26
26
|
node_js: 8
|
|
27
27
|
|
|
28
|
-
script:
|
|
29
|
-
# Run tests
|
|
30
|
-
- npm run test
|
|
31
|
-
|
|
32
28
|
deploy:
|
|
33
29
|
provider: script
|
|
34
30
|
skip_cleanup: true
|
|
@@ -56,9 +52,9 @@ For projects that require to be tested with multiple [Node versions](https://doc
|
|
|
56
52
|
|
|
57
53
|
### `.travis.yml` configuration for multiple Node jobs
|
|
58
54
|
|
|
59
|
-
This example is a minimal configuration for **semantic-release** with a build running Node
|
|
55
|
+
This example is a minimal configuration for **semantic-release** with a build running Node 6 and 8. See [Travis - Customizing the Build](https://docs.travis-ci.com/user/customizing-the-build) for additional configuration options.
|
|
60
56
|
|
|
61
|
-
This example uses [`travis-deploy-once`](https://github.com/semantic-release/travis-deploy-once) in order to
|
|
57
|
+
This example uses [`travis-deploy-once`](https://github.com/semantic-release/travis-deploy-once) in order to [Run `semantic-release` only after all tests succeeded](../usage/ci-configuration.md#run-semantic-release-only-after-all-tests-succeeded). Alternatively you can use [Travis CI Build Stages recipe](travis-build-stages.md).
|
|
62
58
|
|
|
63
59
|
It's recommended to run the `semantic-release` command in the [Travis `deploy` step](https://docs.travis-ci.com/user/customizing-the-build/#The-Build-Lifecycle) so if an error occurs the build will fail and Travis will send a notification.
|
|
64
60
|
|
|
@@ -70,15 +66,6 @@ language: node_js
|
|
|
70
66
|
node_js:
|
|
71
67
|
- 8
|
|
72
68
|
- 6
|
|
73
|
-
- 4
|
|
74
|
-
|
|
75
|
-
os:
|
|
76
|
-
- linux
|
|
77
|
-
- osx
|
|
78
|
-
|
|
79
|
-
script:
|
|
80
|
-
# Run tests
|
|
81
|
-
- npm run test
|
|
82
69
|
|
|
83
70
|
deploy:
|
|
84
71
|
provider: script
|
|
@@ -110,7 +97,7 @@ This recipe cover the Travis specifics only. See [Non JavaScript projects recipe
|
|
|
110
97
|
|
|
111
98
|
### `.travis.yml` configuration for non-JavaScript projects
|
|
112
99
|
|
|
113
|
-
This example is a minimal configuration for semantic-release with a build running [Go 1.6 and 1.7](https://docs.travis-ci.com/user/languages/go) on Linux and OSX. See [Travis - Customizing the Build](https://docs.travis-ci.com/user/customizing-the-build) for additional configuration options.
|
|
100
|
+
This example is a minimal configuration for **semantic-release** with a build running [Go 1.6 and 1.7](https://docs.travis-ci.com/user/languages/go) on Linux and OSX. See [Travis - Customizing the Build](https://docs.travis-ci.com/user/customizing-the-build) for additional configuration options.
|
|
114
101
|
|
|
115
102
|
This example uses [`travis-deploy-once`](https://github.com/semantic-release/travis-deploy-once) in order to [run `semantic-release` only after all tests succeeded](../usage/ci-configuration.md#run-semantic-release-only-after-all-tests-succeeded). Alternatively you can use [Travis CI Build Stages recipe](travis-build-stages.md).
|
|
116
103
|
|
|
@@ -129,17 +116,13 @@ os:
|
|
|
129
116
|
- linux
|
|
130
117
|
- osx
|
|
131
118
|
|
|
132
|
-
script:
|
|
133
|
-
# Run tests
|
|
134
|
-
- go test -v ./...
|
|
135
|
-
|
|
136
119
|
deploy:
|
|
137
120
|
provider: script
|
|
138
121
|
skip_cleanup: true
|
|
139
122
|
script:
|
|
140
123
|
# Use nvm to install and use the Node LTS version (nvm is installed on all Travis images)
|
|
141
124
|
- nvm install lts/*
|
|
142
|
-
# Run semantic-release only on job, after all other are successful
|
|
125
|
+
# Run semantic-release only on one job, after all other are successful
|
|
143
126
|
- npx travis-deploy-once "npx semantic-release"
|
|
144
127
|
```
|
|
145
128
|
|
package/docs/support/FAQ.md
CHANGED
|
@@ -131,7 +131,7 @@ See [Artifactory - npm Registry](https://www.jfrog.com/confluence/display/RTF/Np
|
|
|
131
131
|
|
|
132
132
|
You can trigger a release by pushing to your Git repository. You deliberately cannot trigger a *specific* version release, because this is the whole point of semantic-release.
|
|
133
133
|
|
|
134
|
-
|
|
134
|
+
## Can I exclude commits from the analysis?
|
|
135
135
|
|
|
136
136
|
Yes, every commits that contains `[skip release]` or `[release skip]` in their message will be excluded from the commit analysis and won't participate in the release type determination.
|
|
137
137
|
|
|
@@ -59,7 +59,7 @@ Default: `repository` property in `package.json` or [git origin url](https://git
|
|
|
59
59
|
|
|
60
60
|
CLI arguments: `-r`, `--repository-url`
|
|
61
61
|
|
|
62
|
-
The git repository URL
|
|
62
|
+
The git repository URL.
|
|
63
63
|
|
|
64
64
|
Any valid git url format is supported (See [Git protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols)).
|
|
65
65
|
|
|
@@ -75,7 +75,7 @@ CLI arguments: `-t`, `--tag-format`
|
|
|
75
75
|
|
|
76
76
|
The [Git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) format used by **semantic-release** to identify releases. The tag name is generated with [Lodash template](https://lodash.com/docs#template) and will be compiled with the `version` variable.
|
|
77
77
|
|
|
78
|
-
**Note**: The `tagFormat` must contain the `version` variable and compile to a [valid Git reference](https://git-scm.com/docs/git-check-ref-format#_description).
|
|
78
|
+
**Note**: The `tagFormat` must contain the `version` variable exactly once and compile to a [valid Git reference](https://git-scm.com/docs/git-check-ref-format#_description).
|
|
79
79
|
|
|
80
80
|
### dryRun
|
|
81
81
|
|
|
@@ -166,3 +166,27 @@ CLI argument: `--publish`
|
|
|
166
166
|
Define the list of [publish plugins](plugins.md#publish-plugin). Plugins will run in series, in the order defined in the `Array`.
|
|
167
167
|
|
|
168
168
|
See [Plugins configuration](plugins.md#configuration) for more details.
|
|
169
|
+
|
|
170
|
+
### success
|
|
171
|
+
|
|
172
|
+
Type: `Array`, `String`, `Object`
|
|
173
|
+
|
|
174
|
+
Default: `[]`
|
|
175
|
+
|
|
176
|
+
CLI argument: `--success`
|
|
177
|
+
|
|
178
|
+
Define the list of [success plugins](plugins.md#success-plugin). Plugins will run in series, in the order defined in the `Array`.
|
|
179
|
+
|
|
180
|
+
See [Plugins configuration](plugins.md#configuration) for more details.
|
|
181
|
+
|
|
182
|
+
### fail
|
|
183
|
+
|
|
184
|
+
Type: `Array`, `String`, `Object`
|
|
185
|
+
|
|
186
|
+
Default: `[]`
|
|
187
|
+
|
|
188
|
+
CLI argument: `--fail`
|
|
189
|
+
|
|
190
|
+
Define the list of [fail plugins](plugins.md#fail-plugin). Plugins will run in series, in the order defined in the `Array`.
|
|
191
|
+
|
|
192
|
+
See [Plugins configuration](plugins.md#configuration) for more details.
|
package/docs/usage/plugins.md
CHANGED
|
@@ -34,6 +34,18 @@ Plugin responsible for publishing the release.
|
|
|
34
34
|
|
|
35
35
|
Default implementation: [npm](https://github.com/semantic-release/npm#publish) and [github](https://github.com/semantic-release/github#publish).
|
|
36
36
|
|
|
37
|
+
### success plugin
|
|
38
|
+
|
|
39
|
+
Plugin responsible for notifying of a new release.
|
|
40
|
+
|
|
41
|
+
Default implementation: [github](https://github.com/semantic-release/github#success).
|
|
42
|
+
|
|
43
|
+
### fail plugin
|
|
44
|
+
|
|
45
|
+
Plugin responsible for notifying of a failed release.
|
|
46
|
+
|
|
47
|
+
Default implementation: [github](https://github.com/semantic-release/github#fail).
|
|
48
|
+
|
|
37
49
|
## Configuration
|
|
38
50
|
|
|
39
51
|
Plugin can be configured by specifying the plugin's module name or file path directly as a `String` or within the `path` key of an `Object`.
|
package/index.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
const {template} = require('lodash');
|
|
1
|
+
const {template, isPlainObject, castArray} = require('lodash');
|
|
2
2
|
const marked = require('marked');
|
|
3
3
|
const TerminalRenderer = require('marked-terminal');
|
|
4
4
|
const envCi = require('env-ci');
|
|
5
5
|
const hookStd = require('hook-std');
|
|
6
|
+
const pkg = require('./package.json');
|
|
6
7
|
const hideSensitive = require('./lib/hide-sensitive');
|
|
7
8
|
const getConfig = require('./lib/get-config');
|
|
8
9
|
const verify = require('./lib/verify');
|
|
9
10
|
const getNextVersion = require('./lib/get-next-version');
|
|
10
11
|
const getCommits = require('./lib/get-commits');
|
|
11
12
|
const getLastRelease = require('./lib/get-last-release');
|
|
13
|
+
const {extractErrors} = require('./lib/utils');
|
|
12
14
|
const logger = require('./lib/logger');
|
|
13
15
|
const {unshallow, gitHead: getGitHead, tag, push, deleteTag} = require('./lib/git');
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
marked.setOptions({renderer: new TerminalRenderer()});
|
|
18
|
+
|
|
19
|
+
async function run(options, plugins) {
|
|
16
20
|
const {isCi, branch, isPr} = envCi();
|
|
17
|
-
const config = await getConfig(opts, logger);
|
|
18
|
-
const {plugins, options} = config;
|
|
19
21
|
|
|
20
22
|
if (!isCi && !options.dryRun && !options.noCi) {
|
|
21
23
|
logger.log('This run was not triggered in a known CI environment, running in dry-run mode.');
|
|
@@ -34,7 +36,7 @@ async function run(opts) {
|
|
|
34
36
|
logger.log('Run automated release from branch %s', options.branch);
|
|
35
37
|
|
|
36
38
|
logger.log('Call plugin %s', 'verify-conditions');
|
|
37
|
-
await plugins.verifyConditions({options, logger}, true);
|
|
39
|
+
await plugins.verifyConditions({options, logger}, {settleAll: true});
|
|
38
40
|
|
|
39
41
|
// Unshallow the repo in order to get all the tags
|
|
40
42
|
await unshallow();
|
|
@@ -57,14 +59,13 @@ async function run(opts) {
|
|
|
57
59
|
const nextRelease = {type, version, gitHead: await getGitHead(), gitTag: template(options.tagFormat)({version})};
|
|
58
60
|
|
|
59
61
|
logger.log('Call plugin %s', 'verify-release');
|
|
60
|
-
await plugins.verifyRelease({options, logger, lastRelease, commits, nextRelease}, true);
|
|
62
|
+
await plugins.verifyRelease({options, logger, lastRelease, commits, nextRelease}, {settleAll: true});
|
|
61
63
|
|
|
62
64
|
const generateNotesParam = {options, logger, lastRelease, commits, nextRelease};
|
|
63
65
|
|
|
64
66
|
if (options.dryRun) {
|
|
65
67
|
logger.log('Call plugin %s', 'generate-notes');
|
|
66
68
|
const notes = await plugins.generateNotes(generateNotesParam);
|
|
67
|
-
marked.setOptions({renderer: new TerminalRenderer()});
|
|
68
69
|
logger.log('Release note for version %s:\n', nextRelease.version);
|
|
69
70
|
process.stdout.write(`${marked(notes)}\n`);
|
|
70
71
|
} else {
|
|
@@ -77,45 +78,86 @@ async function run(opts) {
|
|
|
77
78
|
await push(options.repositoryUrl, branch);
|
|
78
79
|
|
|
79
80
|
logger.log('Call plugin %s', 'publish');
|
|
80
|
-
await plugins.publish(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
81
|
+
const releases = await plugins.publish(
|
|
82
|
+
{options, logger, lastRelease, commits, nextRelease},
|
|
83
|
+
{
|
|
84
|
+
getNextInput: async lastResult => {
|
|
85
|
+
const newGitHead = await getGitHead();
|
|
86
|
+
// If previous publish plugin has created a commit (gitHead changed)
|
|
87
|
+
if (lastResult.nextRelease.gitHead !== newGitHead) {
|
|
88
|
+
// Delete the previously created tag
|
|
89
|
+
await deleteTag(options.repositoryUrl, nextRelease.gitTag);
|
|
90
|
+
// Recreate the tag, referencing the new gitHead
|
|
91
|
+
logger.log('Create tag %s', nextRelease.gitTag);
|
|
92
|
+
await tag(nextRelease.gitTag);
|
|
93
|
+
await push(options.repositoryUrl, branch);
|
|
94
|
+
|
|
95
|
+
nextRelease.gitHead = newGitHead;
|
|
96
|
+
// Regenerate the release notes
|
|
97
|
+
logger.log('Call plugin %s', 'generateNotes');
|
|
98
|
+
nextRelease.notes = await plugins.generateNotes(generateNotesParam);
|
|
99
|
+
}
|
|
100
|
+
// Call the next publish plugin with the updated `nextRelease`
|
|
101
|
+
return {options, logger, lastRelease, commits, nextRelease};
|
|
102
|
+
},
|
|
103
|
+
// Add nextRelease and plugin properties to published release
|
|
104
|
+
transform: (release, step) => ({...(isPlainObject(release) ? release : {}), ...nextRelease, ...step}),
|
|
95
105
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
await plugins.success(
|
|
109
|
+
{options, logger, lastRelease, commits, nextRelease, releases: castArray(releases)},
|
|
110
|
+
{settleAll: true}
|
|
111
|
+
);
|
|
112
|
+
|
|
99
113
|
logger.log('Published release: %s', nextRelease.version);
|
|
100
114
|
}
|
|
101
115
|
return true;
|
|
102
116
|
}
|
|
103
117
|
|
|
118
|
+
function logErrors(err) {
|
|
119
|
+
const errors = extractErrors(err).sort(error => (error.semanticRelease ? -1 : 0));
|
|
120
|
+
for (const error of errors) {
|
|
121
|
+
if (error.semanticRelease) {
|
|
122
|
+
logger.log(`%s ${error.message}`, error.code);
|
|
123
|
+
if (error.details) {
|
|
124
|
+
process.stdout.write(`${marked(error.details)}\n`);
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
logger.error('An error occurred while running semantic-release: %O', error);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function callFail(plugins, options, error) {
|
|
133
|
+
const errors = extractErrors(error).filter(error => error.semanticRelease);
|
|
134
|
+
if (errors.length > 0) {
|
|
135
|
+
try {
|
|
136
|
+
await plugins.fail({options, logger, errors}, {settleAll: true});
|
|
137
|
+
} catch (err) {
|
|
138
|
+
logErrors(err);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
104
143
|
module.exports = async opts => {
|
|
144
|
+
logger.log(`Running %s version %s`, pkg.name, pkg.version);
|
|
105
145
|
const unhook = hookStd({silent: false}, hideSensitive);
|
|
106
146
|
try {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
logger.error('An error occurred while running semantic-release: %O', error);
|
|
147
|
+
const config = await getConfig(opts, logger);
|
|
148
|
+
const {plugins, options} = config;
|
|
149
|
+
try {
|
|
150
|
+
const result = await run(options, plugins);
|
|
151
|
+
unhook();
|
|
152
|
+
return result;
|
|
153
|
+
} catch (err) {
|
|
154
|
+
if (!options.dryRun) {
|
|
155
|
+
await callFail(plugins, options, err);
|
|
117
156
|
}
|
|
157
|
+
throw err;
|
|
118
158
|
}
|
|
159
|
+
} catch (err) {
|
|
160
|
+
logErrors(err);
|
|
119
161
|
unhook();
|
|
120
162
|
throw err;
|
|
121
163
|
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const url = require('url');
|
|
2
|
+
const {inspect} = require('util');
|
|
3
|
+
const {toLower, isString} = require('lodash');
|
|
4
|
+
const pkg = require('../../package.json');
|
|
5
|
+
const RELEASE_TYPE = require('./release-types');
|
|
6
|
+
|
|
7
|
+
const homepage = url.format({...url.parse(pkg.homepage), ...{hash: null}});
|
|
8
|
+
const stringify = obj => (isString(obj) ? obj : inspect(obj, {breakLength: Infinity, depth: 2, maxArrayLength: 5}));
|
|
9
|
+
const linkify = file => `${homepage}/blob/caribou/${file}`;
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
ENOGITREPO: () => ({
|
|
13
|
+
message: 'Not running from a git repository.',
|
|
14
|
+
details: `The \`semantic-release\` command must be executed from a Git repository.
|
|
15
|
+
|
|
16
|
+
The current working directory is \`${process.cwd()}\`.
|
|
17
|
+
|
|
18
|
+
Please verify your CI configuration to make sure the \`semantic-release\` command is executed from the root of the cloned repository.`,
|
|
19
|
+
}),
|
|
20
|
+
ENOREPOURL: () => ({
|
|
21
|
+
message: 'The `repositoryUrl` option is required.',
|
|
22
|
+
details: `The [repositoryUrl option](${linkify(
|
|
23
|
+
'docs/usage/configuration.md#repositoryurl'
|
|
24
|
+
)}) cannot be determined from the semantic-release configuration, the \`package.json\` nor the [git origin url](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes).
|
|
25
|
+
|
|
26
|
+
Please make sure to add the \`repositoryUrl\` to the [semantic-release configuration] (${linkify(
|
|
27
|
+
'docs/usage/configuration.md'
|
|
28
|
+
)}).`,
|
|
29
|
+
}),
|
|
30
|
+
EGITNOPERMISSION: ({options}) => ({
|
|
31
|
+
message: 'The push permission to the Git repository is required.',
|
|
32
|
+
details: `**semantic-release** cannot push the version tag to the branch \`${
|
|
33
|
+
options.branch
|
|
34
|
+
}\` on remote Git repository.
|
|
35
|
+
|
|
36
|
+
Please refer to the [authentication configuration documentation](${linkify(
|
|
37
|
+
'docs/usage/ci-configuration.md#authentication'
|
|
38
|
+
)}) to configure the Git credentials on your CI environment.`,
|
|
39
|
+
}),
|
|
40
|
+
EINVALIDTAGFORMAT: ({tagFormat}) => ({
|
|
41
|
+
message: 'Invalid `tagFormat` option.',
|
|
42
|
+
details: `The [tagFormat](${linkify(
|
|
43
|
+
'docs/usage/configuration.md#tagformat'
|
|
44
|
+
)}) must compile to a [valid Git reference](https://git-scm.com/docs/git-check-ref-format#_description).
|
|
45
|
+
|
|
46
|
+
Your configuration for the \`tagFormat\` option is \`${stringify(tagFormat)}\`.`,
|
|
47
|
+
}),
|
|
48
|
+
ETAGNOVERSION: ({tagFormat}) => ({
|
|
49
|
+
message: 'Invalid `tagFormat` option.',
|
|
50
|
+
details: `The [tagFormat](${linkify(
|
|
51
|
+
'docs/usage/configuration.md#tagformat'
|
|
52
|
+
)}) option must contain the variable \`version\` exactly once.
|
|
53
|
+
|
|
54
|
+
Your configuration for the \`tagFormat\` option is \`${stringify(tagFormat)}\`.`,
|
|
55
|
+
}),
|
|
56
|
+
EPLUGINCONF: ({pluginType, pluginConf}) => ({
|
|
57
|
+
message: `The \`${pluginType}\` plugin configuration is invalid.`,
|
|
58
|
+
details: `The [${pluginType} plugin configuration](${linkify(
|
|
59
|
+
`docs/usage/plugins.md#${toLower(pluginType)}-plugin`
|
|
60
|
+
)}) if defined, must be a single or an array of plugins definition. A plugin definition is either a string or an object with a \`path\` property.
|
|
61
|
+
|
|
62
|
+
Your configuration for the \`${pluginType}\` plugin is \`${stringify(pluginConf)}\`.`,
|
|
63
|
+
}),
|
|
64
|
+
EPLUGIN: ({pluginName, pluginType}) => ({
|
|
65
|
+
message: `A plugin configured in the step ${pluginType} is not a valid semantic-release plugin.`,
|
|
66
|
+
details: `A valid \`${pluginType}\` **semantic-release** plugin must be a function or an object with a function in the property \`${pluginType}\`.
|
|
67
|
+
|
|
68
|
+
The plugin \`${pluginName}\` doesn't have the property \`${pluginType}\` and cannot be used for the \`${pluginType}\` step.
|
|
69
|
+
|
|
70
|
+
Please refer to the \`${pluginName}\` and [semantic-release plugins configuration](${linkify(
|
|
71
|
+
'docs/usage/plugins.md'
|
|
72
|
+
)}) documentation for more details.`,
|
|
73
|
+
}),
|
|
74
|
+
EANALYZEOUTPUT: ({result, pluginName}) => ({
|
|
75
|
+
message: 'The `analyzeCommits` plugin returned an invalid value. It must return a valid semver release type.',
|
|
76
|
+
details: `The \`analyzeCommits\` plugin must return a valid [semver](https://semver.org) release type. The valid values are: ${RELEASE_TYPE.map(
|
|
77
|
+
type => `\`${type}\``
|
|
78
|
+
).join(', ')}.
|
|
79
|
+
|
|
80
|
+
The \`analyzeCommits\` function of the \`${pluginName}\` returned \`${stringify(result)}\` instead.
|
|
81
|
+
|
|
82
|
+
We recommend to report the issue to the \`${pluginName}\` authors, providing the following informations:
|
|
83
|
+
- The **semantic-release** version: \`${pkg.version}\`
|
|
84
|
+
- The **semantic-release** logs from your CI job
|
|
85
|
+
- The value returned by the plugin: \`${stringify(result)}\`
|
|
86
|
+
- A link to the **semantic-release** plugin developer guide: [${linkify('docs/developer-guide/plugin.md')}](${linkify(
|
|
87
|
+
'docs/developer-guide/plugin.md'
|
|
88
|
+
)})`,
|
|
89
|
+
}),
|
|
90
|
+
ERELEASENOTESOUTPUT: ({result, pluginName}) => ({
|
|
91
|
+
message: 'The `generateNotes` plugin returned an invalid value. It must return a `String`.',
|
|
92
|
+
details: `The \`generateNotes\` plugin must return a \`String\`.
|
|
93
|
+
|
|
94
|
+
The \`generateNotes\` function of the \`${pluginName}\` returned \`${stringify(result)}\` instead.
|
|
95
|
+
|
|
96
|
+
We recommend to report the issue to the \`${pluginName}\` authors, providing the following informations:
|
|
97
|
+
- The **semantic-release** version: \`${pkg.version}\`
|
|
98
|
+
- The **semantic-release** logs from your CI job
|
|
99
|
+
- The value returned by the plugin: \`${stringify(result)}\`
|
|
100
|
+
- A link to the **semantic-release** plugin developer guide: [${linkify('docs/developer-guide/plugin.md')}](${linkify(
|
|
101
|
+
'docs/developer-guide/plugin.md'
|
|
102
|
+
)})`,
|
|
103
|
+
}),
|
|
104
|
+
EPUBLISHOUTPUT: ({result, pluginName}) => ({
|
|
105
|
+
message: 'A `publish` plugin returned an invalid value. It must return an `Object`.',
|
|
106
|
+
details: `The \`publish\` plugins must return an \`Object\`.
|
|
107
|
+
|
|
108
|
+
The \`publish\` function of the \`${pluginName}\` returned \`${stringify(result)}\` instead.
|
|
109
|
+
|
|
110
|
+
We recommend to report the issue to the \`${pluginName}\` authors, providing the following informations:
|
|
111
|
+
- The **semantic-release** version: \`${pkg.version}\`
|
|
112
|
+
- The **semantic-release** logs from your CI job
|
|
113
|
+
- The value returned by the plugin: \`${stringify(result)}\`
|
|
114
|
+
- A link to the **semantic-release** plugin developer guide: [${linkify('docs/developer-guide/plugin.md')}](${linkify(
|
|
115
|
+
'docs/developer-guide/plugin.md'
|
|
116
|
+
)})`,
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const {isString, isFunction, isArray, isPlainObject} = require('lodash');
|
|
2
|
+
const RELEASE_TYPE = require('./release-types');
|
|
3
|
+
|
|
4
|
+
const validatePluginConfig = conf => isString(conf) || isString(conf.path) || isFunction(conf);
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
verifyConditions: {
|
|
8
|
+
default: ['@semantic-release/npm', '@semantic-release/github'],
|
|
9
|
+
config: {
|
|
10
|
+
validator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
analyzeCommits: {
|
|
14
|
+
default: '@semantic-release/commit-analyzer',
|
|
15
|
+
config: {
|
|
16
|
+
validator: conf => Boolean(conf) && validatePluginConfig(conf),
|
|
17
|
+
},
|
|
18
|
+
output: {
|
|
19
|
+
validator: output => !output || RELEASE_TYPE.includes(output),
|
|
20
|
+
error: 'EANALYZEOUTPUT',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
verifyRelease: {
|
|
24
|
+
default: false,
|
|
25
|
+
config: {
|
|
26
|
+
validator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
generateNotes: {
|
|
30
|
+
default: '@semantic-release/release-notes-generator',
|
|
31
|
+
config: {
|
|
32
|
+
validator: conf => !conf || validatePluginConfig(conf),
|
|
33
|
+
},
|
|
34
|
+
output: {
|
|
35
|
+
validator: output => !output || isString(output),
|
|
36
|
+
error: 'ERELEASENOTESOUTPUT',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
publish: {
|
|
40
|
+
default: ['@semantic-release/npm', '@semantic-release/github'],
|
|
41
|
+
config: {
|
|
42
|
+
validator: conf => Boolean(conf) && (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
|
43
|
+
},
|
|
44
|
+
output: {
|
|
45
|
+
validator: output => !output || isPlainObject(output),
|
|
46
|
+
error: 'EPUBLISHOUTPUT',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
success: {
|
|
50
|
+
default: false,
|
|
51
|
+
config: {
|
|
52
|
+
validator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
fail: {
|
|
56
|
+
default: false,
|
|
57
|
+
config: {
|
|
58
|
+
validator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'];
|
package/lib/get-config.js
CHANGED
|
@@ -4,7 +4,7 @@ const cosmiconfig = require('cosmiconfig');
|
|
|
4
4
|
const resolveFrom = require('resolve-from');
|
|
5
5
|
const debug = require('debug')('semantic-release:config');
|
|
6
6
|
const {repoUrl} = require('./git');
|
|
7
|
-
const
|
|
7
|
+
const PLUGINS_DEFINITIONS = require('./definitions/plugins');
|
|
8
8
|
const plugins = require('./plugins');
|
|
9
9
|
const getGitAuthUrl = require('./get-git-auth-url');
|
|
10
10
|
|
|
@@ -25,7 +25,7 @@ module.exports = async (opts, logger) => {
|
|
|
25
25
|
// For each plugin defined in a shareable config, save in `pluginsPath` the extendable config path,
|
|
26
26
|
// so those plugin will be loaded relatively to the config file
|
|
27
27
|
Object.keys(extendsOpts).reduce((pluginsPath, option) => {
|
|
28
|
-
if (
|
|
28
|
+
if (PLUGINS_DEFINITIONS[option]) {
|
|
29
29
|
castArray(extendsOpts[option])
|
|
30
30
|
.filter(plugin => isString(plugin) || (isPlainObject(plugin) && isString(plugin.path)))
|
|
31
31
|
.map(plugin => (isString(plugin) ? plugin : plugin.path))
|
|
@@ -42,17 +42,17 @@ module.exports = async (opts, logger) => {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
const repositoryUrl = (await pkgRepoUrl()) || (await repoUrl());
|
|
46
|
-
|
|
47
45
|
// Set default options values if not defined yet
|
|
48
46
|
options = {
|
|
49
47
|
branch: 'master',
|
|
50
|
-
repositoryUrl:
|
|
48
|
+
repositoryUrl: (await pkgRepoUrl()) || (await repoUrl()),
|
|
51
49
|
tagFormat: `v\${version}`,
|
|
52
50
|
// Remove `null` and `undefined` options so they can be replaced with default ones
|
|
53
51
|
...pickBy(options, option => !isUndefined(option) && !isNull(option)),
|
|
54
52
|
};
|
|
55
53
|
|
|
54
|
+
options.repositoryUrl = options.repositoryUrl ? getGitAuthUrl(options.repositoryUrl) : options.repositoryUrl;
|
|
55
|
+
|
|
56
56
|
debug('options values: %O', options);
|
|
57
57
|
|
|
58
58
|
return {options, plugins: await plugins(options, pluginsPath, logger)};
|
package/lib/get-error.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const SemanticReleaseError = require('@semantic-release/error');
|
|
2
|
+
const ERROR_DEFINITIONS = require('./definitions/errors');
|
|
3
|
+
|
|
4
|
+
module.exports = (code, ctx = {}) => {
|
|
5
|
+
const {message, details} = ERROR_DEFINITIONS[code](ctx);
|
|
6
|
+
return new SemanticReleaseError(message, code, details);
|
|
7
|
+
};
|
package/lib/git.js
CHANGED
|
@@ -120,7 +120,6 @@ async function push(origin, branch) {
|
|
|
120
120
|
*
|
|
121
121
|
* @param {String} origin The remote repository URL.
|
|
122
122
|
* @param {String} tagName The tag name to delete.
|
|
123
|
-
* @throws {SemanticReleaseError} if the remote tag exists and references a commit that is not the local head commit.
|
|
124
123
|
*/
|
|
125
124
|
async function deleteTag(origin, tagName) {
|
|
126
125
|
// Delete the local tag
|
package/lib/plugins/index.js
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
|
-
const {isArray, isObject, omit} = require('lodash');
|
|
1
|
+
const {isArray, isObject, omit, castArray, isUndefined} = require('lodash');
|
|
2
2
|
const AggregateError = require('aggregate-error');
|
|
3
|
-
const
|
|
4
|
-
const
|
|
3
|
+
const getError = require('../get-error');
|
|
4
|
+
const PLUGINS_DEFINITIONS = require('../definitions/plugins');
|
|
5
5
|
const pipeline = require('./pipeline');
|
|
6
6
|
const normalize = require('./normalize');
|
|
7
7
|
|
|
8
8
|
module.exports = (options, pluginsPath, logger) => {
|
|
9
9
|
const errors = [];
|
|
10
|
-
const plugins = Object.keys(
|
|
11
|
-
const {config,
|
|
10
|
+
const plugins = Object.keys(PLUGINS_DEFINITIONS).reduce((plugins, pluginType) => {
|
|
11
|
+
const {config, default: def} = PLUGINS_DEFINITIONS[pluginType];
|
|
12
12
|
let pluginConfs;
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
if (isUndefined(options[pluginType])) {
|
|
15
|
+
pluginConfs = def;
|
|
16
|
+
} else {
|
|
14
17
|
// If an object is passed and the path is missing, set the default one for single plugins
|
|
15
18
|
if (isObject(options[pluginType]) && !options[pluginType].path && !isArray(def)) {
|
|
16
19
|
options[pluginType].path = def;
|
|
17
20
|
}
|
|
18
21
|
if (config && !config.validator(options[pluginType])) {
|
|
19
|
-
errors.push(
|
|
22
|
+
errors.push(getError('EPLUGINCONF', {pluginType, pluginConf: options[pluginType]}));
|
|
20
23
|
return plugins;
|
|
21
24
|
}
|
|
22
25
|
pluginConfs = options[pluginType];
|
|
23
|
-
} else {
|
|
24
|
-
pluginConfs = def;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
const globalOpts = omit(options, Object.keys(
|
|
28
|
+
const globalOpts = omit(options, Object.keys(PLUGINS_DEFINITIONS));
|
|
28
29
|
|
|
29
|
-
plugins[pluginType] =
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
plugins[pluginType] = pipeline(
|
|
31
|
+
castArray(pluginConfs).map(conf => normalize(pluginType, pluginsPath, globalOpts, conf, logger))
|
|
32
|
+
);
|
|
32
33
|
|
|
33
34
|
return plugins;
|
|
34
35
|
}, {});
|
package/lib/plugins/normalize.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
const {dirname} = require('path');
|
|
2
|
-
const {
|
|
3
|
-
const SemanticReleaseError = require('@semantic-release/error');
|
|
4
|
-
const {isString, isObject, isFunction, noop, cloneDeep} = require('lodash');
|
|
2
|
+
const {isString, isPlainObject, isFunction, noop, cloneDeep} = require('lodash');
|
|
5
3
|
const resolveFrom = require('resolve-from');
|
|
4
|
+
const getError = require('../get-error');
|
|
5
|
+
const {extractErrors} = require('../utils');
|
|
6
|
+
const PLUGINS_DEFINITIONS = require('../definitions/plugins');
|
|
6
7
|
|
|
7
|
-
module.exports = (pluginType, pluginsPath, globalOpts, pluginOpts, logger
|
|
8
|
+
module.exports = (pluginType, pluginsPath, globalOpts, pluginOpts, logger) => {
|
|
8
9
|
if (!pluginOpts) {
|
|
9
10
|
return noop;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
const {path, ...config} = isString(pluginOpts) || isFunction(pluginOpts) ? {path: pluginOpts} : pluginOpts;
|
|
14
|
+
const pluginName = isFunction(path) ? `[Function: ${path.name}]` : path;
|
|
15
|
+
|
|
13
16
|
if (!isFunction(pluginOpts)) {
|
|
14
17
|
if (pluginsPath[path]) {
|
|
15
18
|
logger.log('Load plugin %s from %s in shareable config %s', pluginType, path, pluginsPath[path]);
|
|
@@ -28,21 +31,27 @@ module.exports = (pluginType, pluginsPath, globalOpts, pluginOpts, logger, valid
|
|
|
28
31
|
let func;
|
|
29
32
|
if (isFunction(plugin)) {
|
|
30
33
|
func = plugin.bind(null, cloneDeep({...globalOpts, ...config}));
|
|
31
|
-
} else if (
|
|
34
|
+
} else if (isPlainObject(plugin) && plugin[pluginType] && isFunction(plugin[pluginType])) {
|
|
32
35
|
func = plugin[pluginType].bind(null, cloneDeep({...globalOpts, ...config}));
|
|
33
36
|
} else {
|
|
34
|
-
throw
|
|
35
|
-
`The ${pluginType} plugin must be a function, or an object with a function in the property ${pluginType}.`,
|
|
36
|
-
'EPLUGINCONF'
|
|
37
|
-
);
|
|
37
|
+
throw getError('EPLUGIN', {pluginType, pluginName});
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
return
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
return Object.defineProperty(
|
|
41
|
+
async input => {
|
|
42
|
+
const definition = PLUGINS_DEFINITIONS[pluginType];
|
|
43
|
+
try {
|
|
44
|
+
const result = await func(cloneDeep(input));
|
|
45
|
+
if (definition && definition.output && !definition.output.validator(result)) {
|
|
46
|
+
throw getError(PLUGINS_DEFINITIONS[pluginType].output.error, {result, pluginName});
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
} catch (err) {
|
|
50
|
+
extractErrors(err).forEach(err => Object.assign(err, {pluginName}));
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
'pluginName',
|
|
55
|
+
{value: pluginName, writable: false, enumerable: true}
|
|
56
|
+
);
|
|
48
57
|
};
|
package/lib/plugins/pipeline.js
CHANGED
|
@@ -1,33 +1,55 @@
|
|
|
1
1
|
const {identity} = require('lodash');
|
|
2
|
-
const pReflect = require('p-reflect');
|
|
3
2
|
const pReduce = require('p-reduce');
|
|
4
3
|
const AggregateError = require('aggregate-error');
|
|
4
|
+
const {extractErrors} = require('../utils');
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* A Function that execute a list of function sequencially. If at least one Function ins the pipeline throw an Error or rejects, the pipeline function rejects as well.
|
|
8
|
+
*
|
|
9
|
+
* @typedef {Function} Pipeline
|
|
10
|
+
* @param {Any} input Argument to pass to the first step in the pipeline.
|
|
11
|
+
* @param {Object} options Pipeline options.
|
|
12
|
+
* @param {Boolean} [options.settleAll=false] If `true` all the steps in the pipeline are executed, even if one rejects, if `false` the execution stops after a steps rejects.
|
|
13
|
+
* @param {Function} [options.getNextInput=identity] Function called after each step is executed, with the last and current step results; the returned value will be used as the argument of the next step.
|
|
14
|
+
* @param {Function} [options.transform=identity] Function called after each step is executed, with the current step result and the step function; the returned value will be saved in the pipeline results.
|
|
15
|
+
*
|
|
16
|
+
* @return {Array<*>|*} An Array with the result of each step in the pipeline; if there is only 1 step in the pipeline, the result of this step is returned directly.
|
|
17
|
+
*
|
|
18
|
+
* @throws {AggregateError|Error} An AggregateError with the errors of each step in the pipeline that rejected; if there is only 1 step in the pipeline, the error of this step is thrown directly.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create a Pipeline with a list of Functions.
|
|
23
|
+
*
|
|
24
|
+
* @param {Array<Function>} steps The list of Function to execute.
|
|
25
|
+
* @return {Pipeline} A Function that execute the `steps` sequencially
|
|
26
|
+
*/
|
|
27
|
+
module.exports = steps => async (input, {settleAll = false, getNextInput = identity, transform = identity} = {}) => {
|
|
7
28
|
const results = [];
|
|
8
29
|
const errors = [];
|
|
9
30
|
await pReduce(
|
|
10
31
|
steps,
|
|
11
|
-
async (
|
|
32
|
+
async (lastResult, step) => {
|
|
12
33
|
let result;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const {isFulfilled, value, reason} = await pReflect(nextStep(prevResult));
|
|
17
|
-
result = isFulfilled ? value : reason;
|
|
18
|
-
(isFulfilled ? results : errors).push(result);
|
|
19
|
-
} else {
|
|
20
|
-
result = await nextStep(prevResult);
|
|
34
|
+
try {
|
|
35
|
+
// Call the step with the input computed at the end of the previous iteration and save intermediary result
|
|
36
|
+
result = await transform(await step(lastResult), step);
|
|
21
37
|
results.push(result);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
if (settleAll) {
|
|
40
|
+
errors.push(...extractErrors(err));
|
|
41
|
+
result = err;
|
|
42
|
+
} else {
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
22
45
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return getNextInput(prevResult, result);
|
|
46
|
+
// Prepare input for the next step, passing the result of the last iteration (or initial parameter for the first iteration) and the current one
|
|
47
|
+
return getNextInput(lastResult, result);
|
|
26
48
|
},
|
|
27
49
|
input
|
|
28
50
|
);
|
|
29
51
|
if (errors.length > 0) {
|
|
30
|
-
throw new AggregateError(errors);
|
|
52
|
+
throw errors.length === 1 ? errors[0] : new AggregateError(errors);
|
|
31
53
|
}
|
|
32
|
-
return results;
|
|
54
|
+
return results.length <= 1 ? results[0] : results;
|
|
33
55
|
};
|
package/lib/utils.js
ADDED
package/lib/verify.js
CHANGED
|
@@ -1,44 +1,29 @@
|
|
|
1
1
|
const {template} = require('lodash');
|
|
2
|
-
const SemanticReleaseError = require('@semantic-release/error');
|
|
3
2
|
const AggregateError = require('aggregate-error');
|
|
4
3
|
const {isGitRepo, verifyAuth, verifyTagName} = require('./git');
|
|
4
|
+
const getError = require('./get-error');
|
|
5
5
|
|
|
6
6
|
module.exports = async (options, branch, logger) => {
|
|
7
7
|
const errors = [];
|
|
8
8
|
|
|
9
9
|
if (!await isGitRepo()) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (!options.repositoryUrl) {
|
|
15
|
-
errors.push(new SemanticReleaseError('The repositoryUrl option is required', 'ENOREPOURL'));
|
|
10
|
+
errors.push(getError('ENOGITREPO'));
|
|
11
|
+
} else if (!options.repositoryUrl) {
|
|
12
|
+
errors.push(getError('ENOREPOURL'));
|
|
16
13
|
} else if (!await verifyAuth(options.repositoryUrl, options.branch)) {
|
|
17
|
-
errors.push(
|
|
18
|
-
new SemanticReleaseError(
|
|
19
|
-
`The git credentials doesn't allow to push on the branch ${options.branch}.`,
|
|
20
|
-
'EGITNOPERMISSION'
|
|
21
|
-
)
|
|
22
|
-
);
|
|
14
|
+
errors.push(getError('EGITNOPERMISSION', {options}));
|
|
23
15
|
}
|
|
24
16
|
|
|
25
17
|
// Verify that compiling the `tagFormat` produce a valid Git tag
|
|
26
18
|
if (!await verifyTagName(template(options.tagFormat)({version: '0.0.0'}))) {
|
|
27
|
-
errors.push(
|
|
28
|
-
new SemanticReleaseError('The tagFormat template must compile to a valid Git tag format', 'EINVALIDTAGFORMAT')
|
|
29
|
-
);
|
|
19
|
+
errors.push(getError('EINVALIDTAGFORMAT', {tagFormat: options.tagFormat}));
|
|
30
20
|
}
|
|
31
21
|
|
|
32
22
|
// Verify the `tagFormat` contains the variable `version` by compiling the `tagFormat` template
|
|
33
23
|
// with a space as the `version` value and verify the result contains the space.
|
|
34
24
|
// The space is used as it's an invalid tag character, so it's guaranteed to no be present in the `tagFormat`.
|
|
35
25
|
if ((template(options.tagFormat)({version: ' '}).match(/ /g) || []).length !== 1) {
|
|
36
|
-
errors.push(
|
|
37
|
-
new SemanticReleaseError(
|
|
38
|
-
`The tagFormat template must contain the variable "\${version}" exactly once`,
|
|
39
|
-
'ETAGNOVERSION'
|
|
40
|
-
)
|
|
41
|
-
);
|
|
26
|
+
errors.push(getError('ETAGNOVERSION', {tagFormat: options.tagFormat}));
|
|
42
27
|
}
|
|
43
28
|
|
|
44
29
|
if (errors.length > 0) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "semantic-release",
|
|
3
3
|
"description": "Automated semver compliant package publishing",
|
|
4
|
-
"version": "13.
|
|
4
|
+
"version": "13.4.1",
|
|
5
5
|
"author": "Stephan Bönnemann <stephan@boennemann.me> (http://boennemann.me)",
|
|
6
6
|
"bin": {
|
|
7
7
|
"semantic-release": "bin/semantic-release.js"
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@semantic-release/commit-analyzer": "^5.0.0",
|
|
23
|
-
"@semantic-release/error": "^2.
|
|
24
|
-
"@semantic-release/github": "^4.0
|
|
25
|
-
"@semantic-release/npm": "^3.
|
|
23
|
+
"@semantic-release/error": "^2.2.0",
|
|
24
|
+
"@semantic-release/github": "^4.1.0",
|
|
25
|
+
"@semantic-release/npm": "^3.1.0",
|
|
26
26
|
"@semantic-release/release-notes-generator": "^6.0.0",
|
|
27
27
|
"aggregate-error": "^1.0.0",
|
|
28
28
|
"chalk": "^2.3.0",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"marked-terminal": "^2.0.0",
|
|
41
41
|
"p-locate": "^2.0.0",
|
|
42
42
|
"p-reduce": "^1.0.0",
|
|
43
|
-
"p-reflect": "^1.0.0",
|
|
44
43
|
"read-pkg-up": "^3.0.0",
|
|
45
44
|
"resolve-from": "^4.0.0",
|
|
46
|
-
"semver": "^5.4.1"
|
|
45
|
+
"semver": "^5.4.1",
|
|
46
|
+
"yargs": "^11.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"ava": "^0.25.0",
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
const {isString, isFunction, isArray} = require('lodash');
|
|
2
|
-
|
|
3
|
-
const RELEASE_TYPE = ['major', 'premajor', 'minor', 'preminor', 'patch', 'prepatch', 'prerelease'];
|
|
4
|
-
const validatePluginConfig = conf => isString(conf) || isString(conf.path) || isFunction(conf);
|
|
5
|
-
|
|
6
|
-
module.exports = {
|
|
7
|
-
verifyConditions: {
|
|
8
|
-
default: ['@semantic-release/npm', '@semantic-release/github'],
|
|
9
|
-
config: {
|
|
10
|
-
validator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
|
11
|
-
message:
|
|
12
|
-
'The "verifyConditions" plugin, if defined, must be a single or an array of plugins definition. A plugin definition is either a string or an object with a path property.',
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
analyzeCommits: {
|
|
16
|
-
default: '@semantic-release/commit-analyzer',
|
|
17
|
-
config: {
|
|
18
|
-
validator: conf => Boolean(conf) && validatePluginConfig(conf),
|
|
19
|
-
message:
|
|
20
|
-
'The "analyzeCommits" plugin is mandatory, and must be a single plugin definition. A plugin definition is either a string or an object with a path property.',
|
|
21
|
-
},
|
|
22
|
-
output: {
|
|
23
|
-
validator: output => !output || RELEASE_TYPE.includes(output),
|
|
24
|
-
message: 'The "analyzeCommits" plugin output, if defined, must be a valid semver release type.',
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
verifyRelease: {
|
|
28
|
-
default: false,
|
|
29
|
-
config: {
|
|
30
|
-
validator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
|
31
|
-
message:
|
|
32
|
-
'The "verifyRelease" plugin, if defined, must be a single or an array of plugins definition. A plugin definition is either a string or an object with a path property.',
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
generateNotes: {
|
|
36
|
-
default: '@semantic-release/release-notes-generator',
|
|
37
|
-
config: {
|
|
38
|
-
validator: conf => !conf || validatePluginConfig(conf),
|
|
39
|
-
message:
|
|
40
|
-
'The "generateNotes" plugin, if defined, must be a single plugin definition. A plugin definition is either a string or an object with a path property.',
|
|
41
|
-
},
|
|
42
|
-
output: {
|
|
43
|
-
validator: output => !output || isString(output),
|
|
44
|
-
message: 'The "generateNotes" plugin output, if defined, must be a string.',
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
publish: {
|
|
48
|
-
default: ['@semantic-release/npm', '@semantic-release/github'],
|
|
49
|
-
config: {
|
|
50
|
-
validator: conf => Boolean(conf) && (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
|
|
51
|
-
message:
|
|
52
|
-
'The "publish" plugin is mandatory, and must be a single or an array of plugins definition. A plugin definition is either a string or an object with a path property.',
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
};
|