diff --git a/README.md b/README.md index a3e16670..2834f9e0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # @semantic-release/exec -Set of [semantic-release](https://github.com/semantic-release/semantic-release) plugins to execute custom shell commands. +[**semantic-release**](https://github.com/semantic-release/semantic-release) plugin to execute custom shell commands. [![Travis](https://img.shields.io/travis/semantic-release/exec.svg)](https://travis-ci.org/semantic-release/exec) [![Codecov](https://img.shields.io/codecov/c/github/semantic-release/exec.svg)](https://codecov.io/gh/semantic-release/exec) @@ -9,7 +9,63 @@ Set of [semantic-release](https://github.com/semantic-release/semantic-release) [![npm latest version](https://img.shields.io/npm/v/@semantic-release/exec/latest.svg)](https://www.npmjs.com/package/@semantic-release/exec) [![npm next version](https://img.shields.io/npm/v/@semantic-release/exec/next.svg)](https://www.npmjs.com/package/@semantic-release/exec) -## verifyConditions +| Step | Description | +|--------------------|---------------------------------------------------------------------------------------------------------| +| `verifyConditions` | Execute a shell command to verify if the release should happen. | +| `analyzeCommits` | Execute a shell command to determine the type of release. | +| `verifyRelease` | Execute a shell command to verifying a release that was determined before and is about to be published. | +| `generateNotes` | Execute a shell command to generate the release note. | +| `prepare` | Execute a shell command to prepare the release. | +| `publish` | Execute a shell command to publish the release. | +| `success` | Execute a shell command to notify of a new release. | +| `fail` | Execute a shell command to notify of a failed release. | + +## Install + +```bash +$ npm install @semantic-release/exec -D +``` + +## Usage + +The plugin can be configured in the [**semantic-release** configuration file](https://github.com/semantic-release/semantic-release/blob/caribou/docs/usage/configuration.md#configuration): + +```json +{ + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + ["@semantic-release/exec", { + "verifyConditionsCmd": "./verify.sh", + "publishCmd": "./publish.sh ${nextRelease.version} ${options.branch} ${commits.length} ${Date.now()}" + }], + ] +} +``` + +With this example: +- the shell command `./verify.sh` will be executed on the [verify conditions step](https://github.com/semantic-release/semantic-release#release-steps) +- the shell command `./publish.sh 1.0.0 master 3 870668040000` (for the release of version `1.0.0` from branch `master` with `3` commits on `August 4th, 1997 at 2:14 AM`) will be executed on the [publish step](https://github.com/semantic-release/semantic-release#release-steps) + +## Configuration + +### Options + +| Options | Description | +|-----------------------|-----------------------------------------------------------------------------------------------------------------| +| `verifyConditionsCmd` | The shell command to execute during the verify condition step. See [verifyConditionsCmd](#verifyconditionscmd). | +| `analyzeCommitsCmd` | The shell command to execute during the analyze commits step. See [analyzeCommitsCmd](#analyzecommitscmd). | +| `verifyReleaseCmd` | The shell command to execute during the verify release step. See [verifyReleaseCmd](#verifyreleasecmd). | +| `generateNotesCmd` | The shell command to execute during the generate notes step. See [generateNotesCmd](#generatenotescmd). | +| `prepareCmd` | The shell command to execute during the prepare step. See [prepareCmd](#preparecmd). | +| `publishCmd` | The shell command to execute during the publish step. See [publishCmd](#publishcmd). | +| `successCmd` | The shell command to execute during the success step. See [successCmd](#successcmd). | +| `failCmd` | The shell command to execute during the fail step. See [failCmd](#failcmd). | +| `shell` | The shell to use to run the command. See [execa#shell](https://github.com/sindresorhus/execa#shell). | + +Each shell command is generated with [Lodash template](https://lodash.com/docs#template). All the objets passed to the [semantic-release plugins](https://github.com/semantic-release/semantic-release#plugins) are available as template options. + +## verifyConditionsCmd Execute a shell command to verify if the release should happen. @@ -19,9 +75,7 @@ Execute a shell command to verify if the release should happen. | `stdout` | Write only the reason for the verification to fail. | | `stderr` | Can be used for logging. | -## analyzeCommits - -Execute a shell command to determine the type release. +## analyzeCommitsCmd | Command property | Description | |------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -29,9 +83,7 @@ Execute a shell command to determine the type release. | `stdout` | Only the release type (`major`, `minor` or `patch` etc..) can be written to `stdout`. If no release has to be done the command must not write to `stdout`. | | `stderr` | Can be used for logging. | -## verifyRelease - -Execute a shell command to verifying a release that was determined before and is about to be published. +## verifyReleaseCmd | Command property | Description | |------------------|--------------------------------------------------------------------------| @@ -39,9 +91,7 @@ Execute a shell command to verifying a release that was determined before and is | `stdout` | Only the reason for the verification to fail can be written to `stdout`. | | `stderr` | Can be used for logging. | -## generateNotes - -Execute a shell command to generate the release note. +## generateNotesCmd | Command property | Description | |------------------|---------------------------------------------------------------------------------------------------------------------| @@ -49,9 +99,7 @@ Execute a shell command to generate the release note. | `stdout` | Only the release note must be written to `stdout`. | | `stderr` | Can be used for logging. | -## prepare - -Execute a shell command to prepare the release. +## prepareCmd | Command property | Description | |------------------|---------------------------------------------------------------------------------------------------------------------| @@ -59,9 +107,7 @@ Execute a shell command to prepare the release. | `stdout` | Can be used for logging. | | `stderr` | Can be used for logging. | -## publish - -Execute a shell command to publish the release. +## publishCmd | Command property | Description | |------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -69,9 +115,7 @@ Execute a shell command to publish the release. | `stdout` | The `release` information can be written to `stdout` as parseable JSON (for example `{"name": "Release name", "url": "http://url/release/1.0.0"}`). If the command write non parseable JSON to `stdout` no `release` information will be returned. | | `stderr` | Can be used for logging. | -## success - -Execute a shell command to notify of a successful release. +## successCmd | Command property | Description | |------------------|---------------------------------------------------------------------------------------------------------------------| @@ -79,70 +123,10 @@ Execute a shell command to notify of a successful release. | `stdout` | Can be used for logging. | | `stderr` | Can be used for logging. | -## fail - -Execute a shell command to notify of a failed release. +## failCmd | Command property | Description | |------------------|---------------------------------------------------------------------------------------------------------------------| | `exit code` | Any non `0` code is considered as an unexpected error and will stop the `semantic-release` execution with an error. | | `stdout` | Can be used for logging. | | `stderr` | Can be used for logging. | - -## Configuration - -### Options - -| Options | Description | -|---------|------------------------------------------------------------------------------------------------------| -| `cmd` | The shell command to execute. See [cmd](#cmd). | -| `shell` | The shell to use to run the command. See [execa#shell](https://github.com/sindresorhus/execa#shell). | - -#### `cmd` - -The shell command is generated with [Lodash template](https://lodash.com/docs#template). All the objets passed to the [semantic-release plugins](https://github.com/semantic-release/semantic-release#plugins) are available as template options. - -##### `cmd` examples - -```json -{ - "release": { - "publish": [ - { - "path": "@semantic-release/exec", - "cmd": "./publish.sh ${nextRelease.version} ${options.branch} ${commits.length} ${Date.now()}", - }, - "@semantic-release/npm", - "@semantic-release/github" - ] - } -} -``` - -This will execute the shell command `./publish.sh 1.0.0 master 3 870668040000` (for the release of version `1.0.0` from branch `master` with `3` commits on `August 4th, 1997 at 2:14 AM`). - -### Usage - -Options can be set within the plugin definition in the `semantic-release` configuration file: - -```json -{ - "release": { - "verifyConditions": [ - "@semantic-release/npm", - { - "path": "@semantic-release/exec", - "cmd": "./verify.sh", - } - ], - "publish": [ - "@semantic-release/npm", - { - "path": "@semantic-release/exec", - "cmd": "./publish.sh ${nextRelease.version}", - }, - "@semantic-release/github" - ] - } -} -``` diff --git a/index.js b/index.js index b4238819..8537b789 100644 --- a/index.js +++ b/index.js @@ -1,75 +1,93 @@ +const {isNil} = require('lodash'); const parseJson = require('parse-json'); const debug = require('debug')('semantic-release:exec'); const SemanticReleaseError = require('@semantic-release/error'); -const execScript = require('./lib/exec-script'); +const exec = require('./lib/exec'); const verifyConfig = require('./lib/verify-config'); async function verifyConditions(pluginConfig, context) { - verifyConfig(pluginConfig); - - try { - await execScript(pluginConfig, context); - } catch (error) { - throw new SemanticReleaseError(error.stdout, 'EVERIFYCONDITIONS'); + if (!isNil(pluginConfig.verifyConditionsCmd) || !isNil(pluginConfig.cmd)) { + verifyConfig('verifyConditionsCmd', pluginConfig); + + try { + await exec('verifyConditionsCmd', pluginConfig, context); + } catch (error) { + throw new SemanticReleaseError(error.stdout, 'EVERIFYCONDITIONS'); + } } } async function analyzeCommits(pluginConfig, context) { - verifyConfig(pluginConfig); + if (!isNil(pluginConfig.analyzeCommitsCmd) || !isNil(pluginConfig.cmd)) { + verifyConfig('analyzeCommitsCmd', pluginConfig); - const stdout = await execScript(pluginConfig, context); - return stdout || undefined; + const stdout = await exec('analyzeCommitsCmd', pluginConfig, context); + return stdout || undefined; + } } async function verifyRelease(pluginConfig, context) { - verifyConfig(pluginConfig); - - try { - await execScript(pluginConfig, context); - } catch (error) { - throw new SemanticReleaseError(error.stdout, 'EVERIFYRELEASE'); + if (!isNil(pluginConfig.verifyReleaseCmd) || !isNil(pluginConfig.cmd)) { + verifyConfig('verifyReleaseCmd', pluginConfig); + + try { + await exec('verifyReleaseCmd', pluginConfig, context); + } catch (error) { + throw new SemanticReleaseError(error.stdout, 'EVERIFYRELEASE'); + } } } async function generateNotes(pluginConfig, context) { - verifyConfig(pluginConfig); + if (!isNil(pluginConfig.generateNotesCmd) || !isNil(pluginConfig.cmd)) { + verifyConfig('generateNotesCmd', pluginConfig); - const stdout = await execScript(pluginConfig, context); - return stdout; + const stdout = await exec('generateNotesCmd', pluginConfig, context); + return stdout; + } } async function prepare(pluginConfig, context) { - verifyConfig(pluginConfig); + if (!isNil(pluginConfig.prepareCmd) || !isNil(pluginConfig.cmd)) { + verifyConfig('prepareCmd', pluginConfig); - await execScript(pluginConfig, context); + await exec('prepareCmd', pluginConfig, context); + } } async function publish(pluginConfig, context) { - verifyConfig(pluginConfig); - - const stdout = await execScript(pluginConfig, context); - - try { - return stdout ? parseJson(stdout) : undefined; - } catch (error) { - debug(stdout); - debug(error); - context.logger.log( - `The command ${pluginConfig.cmd} wrote invalid JSON to stdout. The stdout content will be ignored.` - ); + if (!isNil(pluginConfig.publishCmd) || !isNil(pluginConfig.cmd)) { + verifyConfig('publishCmd', pluginConfig); + + const stdout = await exec('publishCmd', pluginConfig, context); + + try { + return stdout ? parseJson(stdout) : undefined; + } catch (error) { + debug(stdout); + debug(error); + context.logger.log( + `The command ${pluginConfig.publishCmd || + pluginConfig.cmd} wrote invalid JSON to stdout. The stdout content will be ignored.` + ); + } } } async function success(pluginConfig, context) { - verifyConfig(pluginConfig); + if (!isNil(pluginConfig.successCmd) || !isNil(pluginConfig.cmd)) { + verifyConfig('successCmd', pluginConfig); - await execScript(pluginConfig, context); + await exec('successCmd', pluginConfig, context); + } } async function fail(pluginConfig, context) { - verifyConfig(pluginConfig); + if (!isNil(pluginConfig.failCmd) || !isNil(pluginConfig.cmd)) { + verifyConfig('failCmd', pluginConfig); - await execScript(pluginConfig, context); + await exec('failCmd', pluginConfig, context); + } } module.exports = {verifyConditions, analyzeCommits, verifyRelease, generateNotes, prepare, publish, success, fail}; diff --git a/lib/definitions/errors.js b/lib/definitions/errors.js new file mode 100644 index 00000000..48bee493 --- /dev/null +++ b/lib/definitions/errors.js @@ -0,0 +1,27 @@ +const url = require('url'); +const {inspect} = require('util'); +const {isString} = require('lodash'); +const pkg = require('../../package.json'); + +const homepage = url.format({...url.parse(pkg.homepage), ...{hash: null}}); +const stringify = obj => (isString(obj) ? obj : inspect(obj, {breakLength: Infinity, depth: 2, maxArrayLength: 5})); +const linkify = file => `${homepage}/blob/master/${file}`; + +module.exports = { + EINVALIDCMD: ({cmd, cmdProp}) => ({ + message: `Invalid \`${cmdProp}\` option.`, + details: `The [\`${cmdProp}\` option](${linkify( + `README.md#${cmdProp}` + )}) is required and must be a non empty \`String\`. + +Your configuration for the \`${cmdProp}\` option is \`${stringify(cmd)}\`.`, + }), + EINVALIDSHELL: ({shell}) => ({ + message: 'Invalid `shell` option.', + details: `The [\`shell\` option](${linkify( + 'README.md#options' + )}) if defined, must be a non empty \`String\` or the value \`true\`. + +Your configuration for the \`shell\` option is \`${stringify(shell)}\`.`, + }), +}; diff --git a/lib/exec-script.js b/lib/exec.js similarity index 60% rename from lib/exec-script.js rename to lib/exec.js index f6207ba9..da094b0a 100644 --- a/lib/exec-script.js +++ b/lib/exec.js @@ -1,8 +1,9 @@ const {template} = require('lodash'); const execa = require('execa'); -module.exports = async ({cmd, shell, ...config}, {cwd, env, stdout, stderr, logger, ...context}) => { - const script = template(cmd)({config, ...context}); +module.exports = async (cmdProp, {shell, ...config}, {cwd, env, stdout, stderr, logger, ...context}) => { + const cmd = config[cmdProp] ? cmdProp : 'cmd'; + const script = template(config[cmd])({config, ...context}); logger.log('Call script %s', script); diff --git a/lib/get-error.js b/lib/get-error.js new file mode 100644 index 00000000..c5b926e8 --- /dev/null +++ b/lib/get-error.js @@ -0,0 +1,7 @@ +const SemanticReleaseError = require('@semantic-release/error'); +const ERROR_DEFINITIONS = require('./definitions/errors'); + +module.exports = (code, ctx) => { + const {message, details} = ERROR_DEFINITIONS[code](ctx); + return new SemanticReleaseError(message, code, details); +}; diff --git a/lib/verify-config.js b/lib/verify-config.js index 72fb8693..5a0dd69d 100644 --- a/lib/verify-config.js +++ b/lib/verify-config.js @@ -1,18 +1,27 @@ -const {isUndefined, isString} = require('lodash'); -const SemanticReleaseError = require('@semantic-release/error'); +const {isNil, isString} = require('lodash'); +const AggregateError = require('aggregate-error'); +const getError = require('./get-error'); -module.exports = ({cmd, shell}) => { - if (!isString(cmd) || !cmd.trim()) { - throw new SemanticReleaseError( - 'The exec plugin must be configured with the shell command to execute in the a "cmd" option.', - 'EINVALIDCMD' - ); - } +const isNonEmptyString = value => isString(value) && value.trim(); +const isOptional = validator => value => isNil(value) || validator(value); + +const VALIDATORS = { + cmd: isNonEmptyString, + shell: isOptional(shell => shell === true || isNonEmptyString(shell)), +}; + +module.exports = (cmdProp, {shell, ...pluginConfig}) => { + const cmd = pluginConfig[cmdProp] ? cmdProp : pluginConfig.cmd ? 'cmd' : cmdProp; + + const errors = Object.entries({shell, cmd: pluginConfig[cmd]}).reduce( + (errors, [option, value]) => + VALIDATORS[option](value) + ? errors + : [...errors, getError(`EINVALID${option.toUpperCase()}`, {[option]: value, cmdProp})], + [] + ); - if (!isUndefined(shell) && (!isString(shell) || !shell.trim())) { - throw new SemanticReleaseError( - 'The "shell" option, if specified, must be a non empty String or the value "true".', - 'EINVALIDSHELL' - ); + if (errors.length > 0) { + throw new AggregateError(errors); } }; diff --git a/package.json b/package.json index 13491453..4ebbc32c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@semantic-release/exec", - "description": "Set of semantic-release plugins to run custom scripts", + "description": "semantic-release plugin to run custom shell commands", "version": "0.0.0-development", "author": "Pierre Vanduynslager (https://github.com/pvdlg)", "bugs": { @@ -17,6 +17,7 @@ ], "dependencies": { "@semantic-release/error": "^2.1.0", + "aggregate-error": "^1.0.0", "debug": "^4.0.0", "execa": "^1.0.0", "lodash": "^4.17.4", diff --git a/test/analyze-commits.test.js b/test/analyze-commits.test.js index 0fc81d18..25298864 100644 --- a/test/analyze-commits.test.js +++ b/test/analyze-commits.test.js @@ -13,9 +13,7 @@ test.beforeEach(t => { }); test('Return the value analyzeCommits script wrote to stdout', async t => { - const pluginConfig = { - cmd: './test/fixtures/echo-args.sh "minor "', - }; + const pluginConfig = {analyzeCommitsCmd: './test/fixtures/echo-args.sh "minor "'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; const result = await analyzeCommits(pluginConfig, context); @@ -23,48 +21,32 @@ test('Return the value analyzeCommits script wrote to stdout', async t => { }); test('Return "undefined" if the analyzeCommits script wrtite nothing to stdout', async t => { - const pluginConfig = { - cmd: './test/fixtures/echo-args.sh " "', - }; + const pluginConfig = {analyzeCommitsCmd: './test/fixtures/echo-args.sh " "'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; const result = await analyzeCommits(pluginConfig, context); t.is(result, undefined); }); -test('Throw "SemanticReleaseError" if "cmd" options is missing', async t => { - const pluginConfig = {}; +test('Throw Error if if the analyzeCommits script does not returns 0', async t => { + const pluginConfig = {analyzeCommitsCmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - const error = await t.throws(analyzeCommits(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); -}); - -test('Throw "SemanticReleaseError" if "cmd" options is empty', async t => { - const pluginConfig = {cmd: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(analyzeCommits(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); + await t.throws(analyzeCommits(pluginConfig, context), Error); }); -test('Throw "SemanticReleaseError" if "shell" options is invalid', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh', shell: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(analyzeCommits(pluginConfig, context)); +test('Use "cmd" if defined and "analyzeCommitsCmd" is not', async t => { + const pluginConfig = {cmd: './test/fixtures/echo-args.sh "minor "'}; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDSHELL'); + const result = await analyzeCommits(pluginConfig, context); + t.is(result, 'minor'); }); -test('Throw Error if if the analyzeCommits script does not returns 0', async t => { - const pluginConfig = {cmd: 'exit 1'}; +test('Use "analyzeCommitsCmd" even if "cmd" is defined', async t => { + const pluginConfig = {analyzeCommitsCmd: './test/fixtures/echo-args.sh "minor "', cmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - await t.throws(analyzeCommits(pluginConfig, context), Error); + const result = await analyzeCommits(pluginConfig, context); + t.is(result, 'minor'); }); diff --git a/test/exec-script.test.js b/test/exec.test.js similarity index 58% rename from test/exec-script.test.js rename to test/exec.test.js index 73d1d030..43bfbf9d 100644 --- a/test/exec-script.test.js +++ b/test/exec.test.js @@ -1,7 +1,7 @@ import test from 'ava'; import {stub} from 'sinon'; import {WritableStreamBuffer} from 'stream-buffers'; -import execScript from '../lib/exec-script'; +import exec from '../lib/exec'; test.beforeEach(t => { t.context.stdout = new WritableStreamBuffer(); @@ -13,10 +13,10 @@ test.beforeEach(t => { }); test('Pipe script output to stdout and stderr', async t => { - const pluginConfig = {cmd: '>&2 echo "write to stderr" && echo "write to stdout"'}; + const pluginConfig = {publishCmd: '>&2 echo "write to stderr" && echo "write to stdout"'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - const result = await execScript(pluginConfig, context); + const result = await exec('publishCmd', pluginConfig, context); t.is(result, 'write to stdout'); t.is(t.context.stdout.getContentsAsString('utf8').trim(), 'write to stdout'); @@ -24,7 +24,10 @@ test('Pipe script output to stdout and stderr', async t => { }); test('Generate command with template', async t => { - const pluginConfig = {cmd: `./test/fixtures/echo-args.sh \${config.conf} \${lastRelease.version}`, conf: 'confValue'}; + const pluginConfig = { + publishCmd: `./test/fixtures/echo-args.sh \${config.conf} \${lastRelease.version}`, + conf: 'confValue', + }; const context = { stdout: t.context.stdout, stderr: t.context.stderr, @@ -32,16 +35,23 @@ test('Generate command with template', async t => { logger: t.context.logger, }; - const result = await execScript(pluginConfig, context); + const result = await exec('publishCmd', pluginConfig, context); t.is(result, 'confValue 1.0.0'); }); test('Execute the script with the specified "shell"', async t => { const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - let result = await execScript({cmd: 'echo $0', shell: 'bash'}, context); + let result = await exec('publishCmd', {publishCmd: 'echo $0', shell: 'bash'}, context); t.is(result, 'bash'); - result = await execScript({cmd: 'echo $0', shell: 'sh'}, context); + result = await exec('publishCmd', {publishCmd: 'echo $0', shell: 'sh'}, context); t.is(result, 'sh'); }); + +test('Execute the script in "cmd" if no step specific command is passed', async t => { + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; + + const result = await exec('publishCmd', {cmd: 'echo run cmd'}, context); + t.is(result, 'run cmd'); +}); diff --git a/test/fail.test.js b/test/fail.test.js index b3a51c97..2627a957 100644 --- a/test/fail.test.js +++ b/test/fail.test.js @@ -13,45 +13,29 @@ test.beforeEach(t => { }); test('Execute script in fail step', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh'}; + const pluginConfig = {failCmd: './test/fixtures/echo-args.sh'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; await t.notThrows(fail(pluginConfig, context)); }); -test('Throw "SemanticReleaseError" if "cmd" options is missing', async t => { - const pluginConfig = {}; +test('Throw "Error" if the fail script does not returns 0', async t => { + const pluginConfig = {failCmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - const error = await t.throws(fail(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); -}); - -test('Throw "SemanticReleaseError" if "cmd" options is empty', async t => { - const pluginConfig = {cmd: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(fail(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); + await t.throws(fail(pluginConfig, context), Error); }); -test('Throw "SemanticReleaseError" if "shell" options is invalid', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh', shell: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(fail(pluginConfig, context)); +test('Use "cmd" if defined and "failCmd" is not', async t => { + const pluginConfig = {cmd: './test/fixtures/echo-args.sh'}; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDSHELL'); + await t.notThrows(fail(pluginConfig, context)); }); -test('Throw "Error" if the fail script does not returns 0', async t => { - const pluginConfig = {cmd: 'exit 1'}; +test('Use "failCmd" even if "cmd" is defined', async t => { + const pluginConfig = {failCmd: './test/fixtures/echo-args.sh', cmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - await t.throws(fail(pluginConfig, context), Error); + await t.notThrows(fail(pluginConfig, context)); }); diff --git a/test/generate-notes.test.js b/test/generate-notes.test.js index c77619fd..ac2357f7 100644 --- a/test/generate-notes.test.js +++ b/test/generate-notes.test.js @@ -13,48 +13,32 @@ test.beforeEach(t => { }); test('Return the value generateNotes script wrote to stdout', async t => { - const pluginConfig = { - cmd: './test/fixtures/echo-args.sh "\nRelease note \n\n"', - }; + const pluginConfig = {generateNotesCmd: './test/fixtures/echo-args.sh "\nRelease note \n\n"'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; const result = await generateNotes(pluginConfig, context); t.is(result, 'Release note'); }); -test('Throw "SemanticReleaseError" if "cmd" options is missing', async t => { - const pluginConfig = {}; +test('Throw "Error" if if the generateNotes script does not returns 0', async t => { + const pluginConfig = {generateNotesCmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - const error = await t.throws(generateNotes(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); -}); - -test('Throw "SemanticReleaseError" if "cmd" options is empty', async t => { - const pluginConfig = {cmd: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(generateNotes(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); + await t.throws(generateNotes(pluginConfig, context), Error); }); -test('Throw "SemanticReleaseError" if "shell" options is invalid', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh', shell: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(generateNotes(pluginConfig, context)); +test('Use "cmd" if defined and "generateNotesCmd" is not', async t => { + const pluginConfig = {cmd: './test/fixtures/echo-args.sh "\nRelease note \n\n"'}; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDSHELL'); + const result = await generateNotes(pluginConfig, context); + t.is(result, 'Release note'); }); -test('Throw "Error" if if the generateNotes script does not returns 0', async t => { - const pluginConfig = {cmd: 'exit 1'}; +test('Use "generateNotesCmd" even if "cmd" is defined', async t => { + const pluginConfig = {generateNotesCmd: './test/fixtures/echo-args.sh "\nRelease note \n\n"', cmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - await t.throws(generateNotes(pluginConfig, context), Error); + const result = await generateNotes(pluginConfig, context); + t.is(result, 'Release note'); }); diff --git a/test/integration.test.js b/test/integration.test.js new file mode 100644 index 00000000..4f3362e5 --- /dev/null +++ b/test/integration.test.js @@ -0,0 +1,13 @@ +import test from 'ava'; +import m from '..'; + +test('Skip step if neither "cmd" nor step cmd is defined', async t => { + await t.notThrows(m.verifyConditions({}, {})); + await t.notThrows(m.analyzeCommits({}, {})); + await t.notThrows(m.verifyRelease({}, {})); + await t.notThrows(m.generateNotes({}, {})); + await t.notThrows(m.prepare({}, {})); + await t.notThrows(m.publish({}, {})); + await t.notThrows(m.success({}, {})); + await t.notThrows(m.fail({}, {})); +}); diff --git a/test/prepare.test.js b/test/prepare.test.js index b3d55a55..02da8b9b 100644 --- a/test/prepare.test.js +++ b/test/prepare.test.js @@ -13,45 +13,29 @@ test.beforeEach(t => { }); test('Execute script in prepare step', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh'}; + const pluginConfig = {prepareCmd: './test/fixtures/echo-args.sh'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; await t.notThrows(prepare(pluginConfig, context)); }); -test('Throw "SemanticReleaseError" if "cmd" options is missing', async t => { - const pluginConfig = {}; +test('Throw "Error" if the prepare script does not returns 0', async t => { + const pluginConfig = {prepareCmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - const error = await t.throws(prepare(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); -}); - -test('Throw "SemanticReleaseError" if "cmd" options is empty', async t => { - const pluginConfig = {cmd: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(prepare(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); + await t.throws(prepare(pluginConfig, context), Error); }); -test('Throw "SemanticReleaseError" if "shell" options is invalid', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh', shell: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(prepare(pluginConfig, context)); +test('Use "cmd" if defined and "prepareCmd" is not', async t => { + const pluginConfig = {cmd: './test/fixtures/echo-args.sh'}; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDSHELL'); + await t.notThrows(prepare(pluginConfig, context)); }); -test('Throw "Error" if the prepare script does not returns 0', async t => { - const pluginConfig = {cmd: 'exit 1'}; +test('Use "prepareCmd" even if "cmd" is defined', async t => { + const pluginConfig = {prepareCmd: './test/fixtures/echo-args.sh', cmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - await t.throws(prepare(pluginConfig, context), Error); + await t.notThrows(prepare(pluginConfig, context)); }); diff --git a/test/publish.test.js b/test/publish.test.js index 8fd177fb..f1873efc 100644 --- a/test/publish.test.js +++ b/test/publish.test.js @@ -14,7 +14,7 @@ test.beforeEach(t => { test('Parse JSON returned by publish script', async t => { const pluginConfig = { - cmd: + publishCmd: './test/fixtures/echo-args.sh {\\"name\\": \\"Release name\\", \\"url\\": \\"https://host.com/release/1.0.0\\"}', }; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; @@ -23,59 +23,56 @@ test('Parse JSON returned by publish script', async t => { t.deepEqual(result, {name: 'Release name', url: 'https://host.com/release/1.0.0'}); }); -test('Return "undefined" if the publish script wrtite invalid JSON to stdout', async t => { - const pluginConfig = { - cmd: './test/fixtures/echo-args.sh invalid_json', - }; +test('Return "undefined" if the publish script wrtite invalid JSON to stdout (with "publishCmd")', async t => { + const pluginConfig = {publishCmd: './test/fixtures/echo-args.sh invalid_json'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; const result = await publish(pluginConfig, context); t.is(result, undefined); }); -test('Return "undefined" if the publish script wrtite nothing to stdout', async t => { - const pluginConfig = { - cmd: './test/fixtures/echo-args.sh', - }; +test('Return "undefined" if the publish script wrtite invalid JSON to stdout (with "cmd")', async t => { + const pluginConfig = {cmd: './test/fixtures/echo-args.sh invalid_json'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; const result = await publish(pluginConfig, context); t.is(result, undefined); }); -test('Throw "SemanticReleaseError" if "cmd" options is missing', async t => { - const pluginConfig = {}; +test('Return "undefined" if the publish script wrtite nothing to stdout', async t => { + const pluginConfig = {publishCmd: './test/fixtures/echo-args.sh'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - const error = await t.throws(publish(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); + const result = await publish(pluginConfig, context); + t.is(result, undefined); }); -test('Throw "SemanticReleaseError" if "cmd" options is empty', async t => { - const pluginConfig = {cmd: ' '}; +test('Throw "Error" if the publish script does not returns 0', async t => { + const pluginConfig = {publishCmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - const error = await t.throws(publish(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); + await t.throws(publish(pluginConfig, context), Error); }); -test('Throw "SemanticReleaseError" if "shell" options is invalid', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh', shell: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(publish(pluginConfig, context)); +test('Use "cmd" if defined and "publishCmd" is not', async t => { + const pluginConfig = { + cmd: + './test/fixtures/echo-args.sh {\\"name\\": \\"Release name\\", \\"url\\": \\"https://host.com/release/1.0.0\\"}', + }; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDSHELL'); + const result = await publish(pluginConfig, context); + t.deepEqual(result, {name: 'Release name', url: 'https://host.com/release/1.0.0'}); }); -test('Throw "Error" if the publish script does not returns 0', async t => { - const pluginConfig = {cmd: 'exit 1'}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; +test('Use "publishCmd" even if "cmd" is defined', async t => { + const pluginConfig = { + publishCmd: + './test/fixtures/echo-args.sh {\\"name\\": \\"Release name\\", \\"url\\": \\"https://host.com/release/1.0.0\\"}', + cmd: 'exit 1', + }; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - await t.throws(publish(pluginConfig, context), Error); + const result = await publish(pluginConfig, context); + t.deepEqual(result, {name: 'Release name', url: 'https://host.com/release/1.0.0'}); }); diff --git a/test/success.test.js b/test/success.test.js index 278c0032..77904a35 100644 --- a/test/success.test.js +++ b/test/success.test.js @@ -13,45 +13,29 @@ test.beforeEach(t => { }); test('Execute script in success step', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh'}; + const pluginConfig = {successCmd: './test/fixtures/echo-args.sh'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; await t.notThrows(success(pluginConfig, context)); }); -test('Throw "SemanticReleaseError" if "cmd" options is missing', async t => { - const pluginConfig = {}; +test('Throw "Error" if the success script does not returns 0', async t => { + const pluginConfig = {successCmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - const error = await t.throws(success(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); -}); - -test('Throw "SemanticReleaseError" if "cmd" options is empty', async t => { - const pluginConfig = {cmd: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(success(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); + await t.throws(success(pluginConfig, context), Error); }); -test('Throw "SemanticReleaseError" if "shell" options is invalid', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh', shell: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(success(pluginConfig, context)); +test('Use "cmd" if defined and "successCmd" is not', async t => { + const pluginConfig = {cmd: './test/fixtures/echo-args.sh'}; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDSHELL'); + await t.notThrows(success(pluginConfig, context)); }); -test('Throw "Error" if the success script does not returns 0', async t => { - const pluginConfig = {cmd: 'exit 1'}; +test('Use "successCmd" even if "cmd" is defined', async t => { + const pluginConfig = {successCmd: './test/fixtures/echo-args.sh', cmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - await t.throws(success(pluginConfig, context), Error); + await t.notThrows(success(pluginConfig, context)); }); diff --git a/test/verify-config.test.js b/test/verify-config.test.js new file mode 100644 index 00000000..85491459 --- /dev/null +++ b/test/verify-config.test.js @@ -0,0 +1,122 @@ +import test from 'ava'; +import verify from '../lib/verify-config'; + +test('Verify "cmd" and "shell" options', t => { + t.notThrows(() => verify('verifyConditionsCmd', {verifyConditionsCmd: 'shell cmd'})); + t.notThrows(() => verify('analyzeCommitsCmd', {analyzeCommitsCmd: 'shell cmd'})); + t.notThrows(() => verify('verifyReleaseCmd', {verifyReleaseCmd: 'shell cmd'})); + t.notThrows(() => verify('generateNotesCmd', {generateNotesCmd: 'shell cmd'})); + t.notThrows(() => verify('prepareCmd', {prepareCmd: 'shell cmd'})); + t.notThrows(() => verify('publishCmd', {publishCmd: 'shell cmd'})); + t.notThrows(() => verify('successCmd', {successCmd: 'shell cmd'})); + t.notThrows(() => verify('failCmd', {failCmd: 'shell cmd'})); + + t.notThrows(() => verify('verifyConditionsCmd', {cmd: 'shell cmd'})); + + t.notThrows(() => verify('verifyConditionsCmd', {cmd: 'shell cmd', shell: true})); + t.notThrows(() => verify('verifyConditionsCmd', {cmd: 'shell cmd', shell: 'bash'})); +}); + +test('Throw SemanticReleaseError if "cmd" option is missing', t => { + const [error] = t.throws(() => verify('verifyConditionsCmd', {})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); +}); + +test('Throw SemanticReleaseError if "cmd" option is not a String', t => { + let [error] = t.throws(() => verify('verifyConditionsCmd', {verifyConditionsCmd: 1})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('analyzeCommitsCmd', {analyzeCommitsCmd: 1})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('verifyReleaseCmd', {verifyReleaseCmd: 1})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('generateNotesCmd', {generateNotesCmd: 1})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('prepareCmd', {prepareCmd: 1})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('publishCmd', {publishCmd: 1})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('successCmd', {successCmd: 1})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('failCmd', {failCmd: 1})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('verifyConditionsCmd', {cmd: 1})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); +}); + +test('Throw SemanticReleaseError if "cmd" option is an empty String', t => { + let [error] = t.throws(() => verify('verifyConditionsCmd', {verifyConditionsCmd: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('analyzeCommitsCmd', {analyzeCommitsCmd: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('verifyReleaseCmd', {verifyReleaseCmd: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('generateNotesCmd', {generateNotesCmd: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('prepareCmd', {prepareCmd: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('publishCmd', {publishCmd: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('successCmd', {successCmd: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('failCmd', {failCmd: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); + + [error] = t.throws(() => verify('verifyConditionsCmd', {cmd: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDCMD'); +}); + +test('Throw SemanticReleaseError if "shell" option is not a String or "true"', t => { + const [error] = t.throws(() => verify('verifyConditionsCmd', {shell: false})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDSHELL'); +}); + +test('Throw SemanticReleaseError if "shell" option is an empty String', t => { + const [error] = t.throws(() => verify('verifyConditionsCmd', {shell: ' '})); + t.is(error.name, 'SemanticReleaseError'); + t.is(error.code, 'EINVALIDSHELL'); +}); + +test('Return SemanticReleaseError Array if multiple config are invalid', t => { + const [error1, error2] = t.throws(() => verify('verifyConditionsCmd', {verifyConditionsCmd: 1, shell: false})); + + t.is(error1.name, 'SemanticReleaseError'); + t.is(error1.code, 'EINVALIDSHELL'); + + t.is(error2.name, 'SemanticReleaseError'); + t.is(error2.code, 'EINVALIDCMD'); +}); diff --git a/test/verify-confitions.test.js b/test/verify-confitions.test.js index 6bce0ddb..ced89b21 100644 --- a/test/verify-confitions.test.js +++ b/test/verify-confitions.test.js @@ -12,56 +12,33 @@ test.beforeEach(t => { t.context.logger = {log: t.context.log, error: t.context.error}; }); -test('Verify plugin config is an Object with a "cmd" property', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh'}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - - await t.notThrows(verifyConditions(pluginConfig, context)); -}); - -test('Throw "SemanticReleaseError" if "cmd" options is missing', async t => { - const pluginConfig = {}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - - const error = await t.throws(verifyConditions(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); -}); - -test('Throw "SemanticReleaseError" if "cmd" options is empty', async t => { - const pluginConfig = {cmd: ' '}; +test('Return if the verifyConditions script returns 0', async t => { + const pluginConfig = {verifyConditionsCmd: 'exit 0'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - const error = await t.throws(verifyConditions(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); + await t.notThrows(verifyConditions(pluginConfig, context)); }); -test('Throw "SemanticReleaseError" if "shell" options is invalid', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh', shell: ' '}; +test('Throw "SemanticReleaseError" if the verifyConditions script does not returns 0', async t => { + const pluginConfig = {verifyConditionsCmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; const error = await t.throws(verifyConditions(pluginConfig, context)); t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDSHELL'); + t.is(error.code, 'EVERIFYCONDITIONS'); }); -test('Return if the verifyConditions script returns 0', async t => { - const pluginConfig = {cmd: 'exit 0'}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; +test('Use "cmd" if defined and "verifyConditionsCmd" is not', async t => { + const pluginConfig = {cmd: './test/fixtures/echo-args.sh'}; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; await t.notThrows(verifyConditions(pluginConfig, context)); }); -test('Throw "SemanticReleaseError" if the verifyConditions script does not returns 0', async t => { - const pluginConfig = {cmd: 'exit 1'}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(verifyConditions(pluginConfig, context)); +test('Use "verifyConditionsCmd" even if "cmd" is defined', async t => { + const pluginConfig = {verifyConditionsCmd: './test/fixtures/echo-args.sh', cmd: 'exit 1'}; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EVERIFYCONDITIONS'); + await t.notThrows(verifyConditions(pluginConfig, context)); }); diff --git a/test/verify-release.test.js b/test/verify-release.test.js index 1e29d9ce..c41b96fc 100644 --- a/test/verify-release.test.js +++ b/test/verify-release.test.js @@ -13,48 +13,32 @@ test.beforeEach(t => { }); test('Return if the verifyRelease script returns 0', async t => { - const pluginConfig = {cmd: 'exit 0'}; + const pluginConfig = {verifyReleaseCmd: 'exit 0'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; await t.notThrows(verifyRelease(pluginConfig, context)); }); -test('Throw "SemanticReleaseError" if "cmd" options is missing', async t => { - const pluginConfig = {}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - - const error = await t.throws(verifyRelease(pluginConfig, context)); - - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); -}); - -test('Throw "SemanticReleaseError" if "cmd" options is empty', async t => { - const pluginConfig = {cmd: ' '}; +test('Throw "SemanticReleaseError" if the verifyRelease script does not returns 0', async t => { + const pluginConfig = {verifyReleaseCmd: 'exit 1'}; const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; const error = await t.throws(verifyRelease(pluginConfig, context)); t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDCMD'); + t.is(error.code, 'EVERIFYRELEASE'); }); -test('Throw "SemanticReleaseError" if "shell" options is invalid', async t => { - const pluginConfig = {cmd: './test/fixtures/echo-args.sh', shell: ' '}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(verifyRelease(pluginConfig, context)); +test('Use "cmd" if defined and "verifyReleaseCmd" is not', async t => { + const pluginConfig = {cmd: './test/fixtures/echo-args.sh'}; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EINVALIDSHELL'); + await t.notThrows(verifyRelease(pluginConfig, context)); }); -test('Throw "SemanticReleaseError" if the verifyRelease script does not returns 0', async t => { - const pluginConfig = {cmd: 'exit 1'}; - const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger, options: {}}; - - const error = await t.throws(verifyRelease(pluginConfig, context)); +test('Use "verifyReleaseCmd" even if "cmd" is defined', async t => { + const pluginConfig = {verifyReleaseCmd: './test/fixtures/echo-args.sh', cmd: 'exit 1'}; + const context = {stdout: t.context.stdout, stderr: t.context.stderr, logger: t.context.logger}; - t.is(error.name, 'SemanticReleaseError'); - t.is(error.code, 'EVERIFYRELEASE'); + await t.notThrows(verifyRelease(pluginConfig, context)); });