diff --git a/package.json b/package.json index a1d5b619..7f8247a5 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "dependencies": { "@semantic-release/commit-analyzer": "^3.0.1", "@semantic-release/condition-travis": "^6.0.0", - "@semantic-release/error": "^2.0.0", + "@semantic-release/error": "^2.1.0", "@semantic-release/last-release-npm": "^2.0.0", "@semantic-release/release-notes-generator": "^5.0.0", "chalk": "^2.3.0", diff --git a/src/cli.js b/src/cli.js index 7e68486f..e21c8785 100755 --- a/src/cli.js +++ b/src/cli.js @@ -1,5 +1,4 @@ const program = require('commander'); -const SemanticReleaseError = require('@semantic-release/error'); const logger = require('./lib/logger'); function list(values) { @@ -49,7 +48,7 @@ module.exports = async () => { } catch (err) { // If error is a SemanticReleaseError then it's an expected exception case (no release to be done, running on a PR etc..) and the cli will return with 0 // Otherwise it's an unexpected error (configuration issue, code issue, plugin issue etc...) and the cli will return 1 - if (err instanceof SemanticReleaseError) { + if (err.semanticRelease) { logger.log(`%s ${err.message}`, err.code); } else { process.exitCode = 1; diff --git a/test/fixtures/plugin-error-inherited.js b/test/fixtures/plugin-error-inherited.js new file mode 100644 index 00000000..12aad0f1 --- /dev/null +++ b/test/fixtures/plugin-error-inherited.js @@ -0,0 +1,14 @@ +const SemanticReleaseError = require('@semantic-release/error'); + +class InheritedError extends SemanticReleaseError { + constructor(message, code, newProperty) { + super(message); + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.code = code; + } +} + +module.exports = function(config, options, cb) { + cb(new InheritedError('Inherited error', 'EINHERITED')); +}; diff --git a/test/integration.test.js b/test/integration.test.js index a6496f28..241fc7cc 100644 --- a/test/integration.test.js +++ b/test/integration.test.js @@ -17,6 +17,7 @@ const env = { const cli = require.resolve('../bin/semantic-release'); const noop = require.resolve('../src/lib/plugin-noop'); const pluginError = require.resolve('./fixtures/plugin-error-a'); +const pluginInheritedError = require.resolve('./fixtures/plugin-error-inherited'); test.before(async t => { await mockServer.start(); @@ -574,7 +575,7 @@ test.serial('Run via JS API', async t => { await semanticRelease({githubToken, verifyConditions: [noop, noop], debug: true}); t.true(t.context.log.calledWithMatch(/Published Github release: /, new RegExp(`release-url/${version}`))); - t.true(t.context.log.calledWithMatch(/Publishing version %s to npm registry %s/, version, registry.uri)); + t.true(t.context.log.calledWithMatch(/Publishing version .* to npm registry/, version, registry.uri)); // Verify package.json and has been updated t.is((await readJson('./package.json')).version, version); @@ -615,7 +616,7 @@ test.serial('Returns and error code if NPM token is invalid', async t => { t.is(code, 1); }); -test.serial('Log unexpected errors from plugins', async t => { +test.serial('Log unexpected errors from plugins and exit with 1', async t => { const packageName = 'test-module-9'; const repo = 'test-repo'; // Create a git repository, set the current working directory at the root of the repo @@ -639,6 +640,30 @@ test.serial('Log unexpected errors from plugins', async t => { t.is(code, 1); }); +test.serial('Log errors inheriting SemanticReleaseError and exit with 0', async t => { + const packageName = 'test-module-10'; + const repo = 'test-repo'; + // Create a git repository, set the current working directory at the root of the repo + t.log('Create git repository and package.json'); + await gitRepo(); + // Create package.json in repository root + await writeJson('./package.json', { + name: packageName, + version: '0.0.0-dev', + repository: {url: `git+https://github.com/${repo}/${packageName}`}, + release: {githubUrl: mockServer.url, verifyConditions: pluginInheritedError}, + }); + + /** Initial release **/ + t.log('Commit a feature'); + await gitCommits(['feat: Initial commit']); + t.log('$ semantic-release'); + let {stdout, code} = await execa(cli, [], {env, reject: false}); + // Verify the type and message are logged + t.regex(stdout, /EINHERITED Inherited error/); + t.is(code, 0); +}); + test.serial('CLI returns error code and prints help if called with a command', async t => { t.log('$ semantic-release pre'); let {stdout, code} = await execa(cli, ['pre'], {env, reject: false});