Compare commits

...
6 Commits
Author SHA1 Message Date
Pierre VanduynslagerandGregor Martynus 1966f0e3e2 fix: verify branch first 2018-02-15 18:35:37 +00:00
Pierre Vanduynslager 305f4ee8eb fix: do not transform repositoryUrl if it allow to push
Even the user set Git credentials via environment variable, use the configured URL (with authentication) if it works.
This allow users to push tags and commits via ssh while still using the GitHub/GitLab API.
2018-02-14 10:45:44 -05:00
Pierre Vanduynslager 9788fcad4e feat: use @semantic-release/github as default for success and fail hooks
BREAKING CHANGE: `success` and `fail` hooks are now enabled by default

In order to disable the `@semantic-release/github` plugin for the `success` and `fail` hook, the corresponding options have to be set to `false` in the **semantic-release** configuration:

```json
{
  "release": {
    "success": false,
    "fail": false
  }
}
```

Users who do not use the `@semantic-release/github` plugin, should disable it in the `success` and `fail` by setting the corresponding options to `false` or to alternative plugin providing `success` and `fail` hooks.
2018-02-13 16:33:37 -05:00
Pierre Vanduynslager 04f3061bed fix: remove the github plugin from default success and fail hooks 2018-02-13 16:06:30 -05:00
Pierre Vanduynslager 1b3c51d624 docs: add missing success and fail options 2018-02-13 16:06:30 -05:00
Pierre Vanduynslager 8a2ef48308 test: revert to mockserver:latest docker container 2018-02-12 21:40:47 -05:00
9 changed files with 71 additions and 49 deletions
+24
View File
@@ -166,3 +166,27 @@ CLI argument: `--publish`
Define the list of [publish plugins](plugins.md#publish-plugin). Plugins will run in series, in the order defined in the `Array`.
See [Plugins configuration](plugins.md#configuration) for more details.
### success
Type: `Array`, `String`, `Object`
Default: `['@semantic-release/github']`
CLI argument: `--success`
Define the list of [success plugins](plugins.md#success-plugin). Plugins will run in series, in the order defined in the `Array`.
See [Plugins configuration](plugins.md#configuration) for more details.
### fail
Type: `Array`, `String`, `Object`
Default: `['@semantic-release/github']`
CLI argument: `--fail`
Define the list of [fail plugins](plugins.md#fail-plugin). Plugins will run in series, in the order defined in the `Array`.
See [Plugins configuration](plugins.md#configuration) for more details.
+9 -2
View File
@@ -29,10 +29,17 @@ async function run(options, plugins) {
return;
}
if (!await verify(options, branch, logger)) {
return;
if (branch !== options.branch) {
logger.log(
`This test run was triggered on the branch ${branch}, while semantic-release is configured to only publish from ${
options.branch
}, therefore a new version wont be published.`
);
return false;
}
await verify(options);
logger.log('Run automated release from branch %s', options.branch);
logger.log('Call plugin %s', 'verify-conditions');
+4 -2
View File
@@ -3,7 +3,7 @@ const readPkgUp = require('read-pkg-up');
const cosmiconfig = require('cosmiconfig');
const resolveFrom = require('resolve-from');
const debug = require('debug')('semantic-release:config');
const {repoUrl} = require('./git');
const {repoUrl, verifyAuth} = require('./git');
const PLUGINS_DEFINITIONS = require('./definitions/plugins');
const plugins = require('./plugins');
const getGitAuthUrl = require('./get-git-auth-url');
@@ -51,7 +51,9 @@ module.exports = async (opts, logger) => {
...pickBy(options, option => !isUndefined(option) && !isNull(option)),
};
options.repositoryUrl = options.repositoryUrl ? getGitAuthUrl(options.repositoryUrl) : options.repositoryUrl;
if (!await verifyAuth(options.repositoryUrl, options.branch)) {
options.repositoryUrl = options.repositoryUrl ? getGitAuthUrl(options.repositoryUrl) : options.repositoryUrl;
}
debug('options values: %O', options);
+1 -12
View File
@@ -3,7 +3,7 @@ const AggregateError = require('aggregate-error');
const {isGitRepo, verifyAuth, verifyTagName} = require('./git');
const getError = require('./get-error');
module.exports = async (options, branch, logger) => {
module.exports = async options => {
const errors = [];
if (!await isGitRepo()) {
@@ -29,15 +29,4 @@ module.exports = async (options, branch, logger) => {
if (errors.length > 0) {
throw new AggregateError(errors);
}
if (branch !== options.branch) {
logger.log(
`This test run was triggered on the branch ${branch}, while semantic-release is configured to only publish from ${
options.branch
}, therefore a new version wont be published.`
);
return false;
}
return true;
};
+13
View File
@@ -80,6 +80,19 @@ test.serial('Default values, reading repositoryUrl (http url) from package.json
t.is(options.tagFormat, `v\${version}`);
});
test.serial('Do not add git credential to repositoryUrl if push is allowed', async t => {
process.env.GIT_CREDENTIALS = 'user:pass';
// Create a git repository, set the current working directory at the root of the repo
const repositoryUrl = await gitRepo(true);
const pkg = {repository: repositoryUrl};
// Create package.json in repository root
await outputJson('./package.json', pkg);
const {options} = await t.context.getConfig();
t.is(options.repositoryUrl, repositoryUrl);
});
test.serial('Read options from package.json', async t => {
const release = {
analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'},
+1 -2
View File
@@ -4,8 +4,7 @@ import got from 'got';
import pRetry from 'p-retry';
import {mockServerClient} from 'mockserver-client';
// TODO temporarly use `mockserver-5.3.0` due to https://github.com/jamesdbloom/mockserver/issues/435
const IMAGE = 'jamesdbloom/mockserver:mockserver-5.3.0';
const IMAGE = 'jamesdbloom/mockserver:latest';
const MOCK_SERVER_PORT = 1080;
const MOCK_SERVER_HOST = 'localhost';
const docker = new Docker();
+10 -10
View File
@@ -302,9 +302,9 @@ test.serial('Log all "verifyConditions" errors', async t => {
'./lib/logger': t.context.logger,
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const errors = await t.throws(semanticRelease(options));
const errors = [...(await t.throws(semanticRelease(options)))];
t.deepEqual(Array.from(errors), [error1, error2, error3]);
t.deepEqual(errors, [error1, error2, error3]);
t.deepEqual(t.context.log.args[t.context.log.args.length - 2], ['%s error 2', 'ERR2']);
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ['%s error 3', 'ERR3']);
t.deepEqual(t.context.error.args[t.context.error.args.length - 1], [
@@ -345,9 +345,9 @@ test.serial('Log all "verifyRelease" errors', async t => {
'./lib/logger': t.context.logger,
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const errors = await t.throws(semanticRelease(options));
const errors = [...(await t.throws(semanticRelease(options)))];
t.deepEqual(Array.from(errors), [error1, error2]);
t.deepEqual(errors, [error1, error2]);
t.deepEqual(t.context.log.args[t.context.log.args.length - 2], ['%s error 1', 'ERR1']);
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ['%s error 2', 'ERR2']);
t.is(fail.callCount, 1);
@@ -428,9 +428,9 @@ test.serial('Dry-run skips fail', async t => {
'./lib/logger': t.context.logger,
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const errors = await t.throws(semanticRelease(options));
const errors = [...(await t.throws(semanticRelease(options)))];
t.deepEqual(Array.from(errors), [error1, error2]);
t.deepEqual(errors, [error1, error2]);
t.deepEqual(t.context.log.args[t.context.log.args.length - 2], ['%s error 1', 'ERR1']);
t.deepEqual(t.context.log.args[t.context.log.args.length - 1], ['%s error 2', 'ERR2']);
t.is(fail.callCount, 0);
@@ -596,7 +596,7 @@ test.serial('Returns falsy value if triggered by a PR', async t => {
t.falsy(await semanticRelease({repositoryUrl}));
t.is(
t.context.log.args[9][0],
t.context.log.args[t.context.log.args.length - 1][0],
"This run was triggered by a pull request and therefore a new version won't be published."
);
});
@@ -723,8 +723,8 @@ test.serial('Hide sensitive environment variable values from the logs', async t
await t.throws(semanticRelease(options));
t.regex(t.context.stdout.args[9][0], /Console: The token \[secure\] is invalid/);
t.regex(t.context.stdout.args[10][0], /Log: The token \[secure\] is invalid/);
t.regex(t.context.stdout.args[t.context.stdout.args.length - 2][0], /Console: The token \[secure\] is invalid/);
t.regex(t.context.stdout.args[t.context.stdout.args.length - 1][0], /Log: The token \[secure\] is invalid/);
t.regex(t.context.stderr.args[0][0], /Error: The token \[secure\] is invalid/);
t.regex(t.context.stderr.args[1][0], /Invalid token \[secure\]/);
});
@@ -785,7 +785,7 @@ test.serial('Throw SemanticReleaseError if repositoryUrl is not set and cannot b
'./lib/logger': t.context.logger,
'env-ci': () => ({isCi: true, branch: 'master', isPr: false}),
});
const errors = Array.from(await t.throws(semanticRelease()));
const errors = [...(await t.throws(semanticRelease()))];
// Verify error code and type
t.is(errors[0].code, 'ENOREPOURL');
+2 -2
View File
@@ -603,11 +603,11 @@ test.serial('Exit with 1 if missing permission to push to the remote repository'
// Create a git repository, set the current working directory at the root of the repo
t.log('Create git repository');
const {repositoryUrl} = await gitbox.createRepo(packageName);
await gitbox.createRepo(packageName);
await writeJson('./package.json', {
name: packageName,
version: '0.0.0-dev',
repository: {url: repositoryUrl},
repository: {url: 'http://user:wrong_pass@localhost:2080/git/unauthorized.git'},
});
/* Initial release */
+7 -19
View File
@@ -1,5 +1,4 @@
import test from 'ava';
import {stub} from 'sinon';
import tempy from 'tempy';
import verify from '../lib/verify';
import {gitRepo} from './helpers/git-utils';
@@ -9,17 +8,13 @@ const envBackup = Object.assign({}, process.env);
// Save the current working diretory
const cwd = process.cwd();
test.beforeEach(t => {
test.beforeEach(() => {
// Delete environment variables that could have been set on the machine running the tests
delete process.env.GIT_CREDENTIALS;
delete process.env.GH_TOKEN;
delete process.env.GITHUB_TOKEN;
delete process.env.GL_TOKEN;
delete process.env.GITLAB_TOKEN;
// Stub the logger functions
t.context.log = stub();
t.context.error = stub();
t.context.logger = {log: t.context.log, error: t.context.error};
});
test.afterEach.always(() => {
@@ -32,7 +27,7 @@ test.afterEach.always(() => {
test.serial('Throw a AggregateError', async t => {
await gitRepo();
const errors = Array.from(await t.throws(verify({}, 'master', t.context.logger)));
const errors = [...(await t.throws(verify({})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'ENOREPOURL');
@@ -46,7 +41,7 @@ test.serial('Throw a SemanticReleaseError if does not run on a git repository',
const dir = tempy.directory();
process.chdir(dir);
const errors = Array.from(await t.throws(verify({}, 'master', t.context.logger)));
const errors = [...(await t.throws(verify({})))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'ENOGITREPO');
@@ -56,7 +51,7 @@ test.serial('Throw a SemanticReleaseError if the "tagFormat" is not valid', asyn
const repositoryUrl = await gitRepo(true);
const options = {repositoryUrl, tagFormat: `?\${version}`};
const errors = Array.from(await t.throws(verify(options, 'master', t.context.logger)));
const errors = [...(await t.throws(verify(options, 'master', t.context.logger)))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'EINVALIDTAGFORMAT');
@@ -66,7 +61,7 @@ test.serial('Throw a SemanticReleaseError if the "tagFormat" does not contains t
const repositoryUrl = await gitRepo(true);
const options = {repositoryUrl, tagFormat: 'test'};
const errors = Array.from(await t.throws(verify(options, 'master', t.context.logger)));
const errors = [...(await t.throws(verify(options, 'master', t.context.logger)))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'ETAGNOVERSION');
@@ -76,22 +71,15 @@ test.serial('Throw a SemanticReleaseError if the "tagFormat" contains multiple "
const repositoryUrl = await gitRepo(true);
const options = {repositoryUrl, tagFormat: `\${version}v\${version}`};
const errors = Array.from(await t.throws(verify(options, 'master', t.context.logger)));
const errors = [...(await t.throws(verify(options)))];
t.is(errors[0].name, 'SemanticReleaseError');
t.is(errors[0].code, 'ETAGNOVERSION');
});
test.serial('Return "false" if the current branch is not the once configured', async t => {
const repositoryUrl = await gitRepo(true);
const options = {repositoryUrl, tagFormat: `v\${version}`, branch: 'master'};
t.false(await verify(options, 'other', t.context.logger));
});
test.serial('Return "true" if all verification pass', async t => {
const repositoryUrl = await gitRepo(true);
const options = {repositoryUrl, tagFormat: `v\${version}`, branch: 'master'};
t.true(await verify(options, 'master', t.context.logger));
await t.notThrows(verify(options));
});