Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d28b7e3e07 | ||
|
|
e00dd160c7 | ||
|
|
3316f1a79e | ||
|
|
8942093c18 | ||
|
|
1b8aa95a6e | ||
|
|
624ee88abd | ||
|
|
4053d8f7fb | ||
|
|
88f33ec482 | ||
|
|
0761ef378a | ||
|
|
f30fb6c8af | ||
|
|
0113db2e06 |
@@ -287,6 +287,8 @@ Being able to write code for just the most recent node versions greatly simplifi
|
||||
|
||||
For a special purpose tool like `semantic-release`, that's only meant to be used in controlled CI environments, we think it's okay to have such a high version requirement. As `semantic-release` handles package publishing we expect almost every project to have at least one build job running node 8 already – and that's all it takes. Even if that's not that case `semantic-release` can still be executed with the help of [npx](https://www.npmjs.com/package/npx) (`npx -p node@8 npm run semantic-release`).
|
||||
|
||||
Please see our [Node Support Policy](#node-support-policy) for our long-term promise for supporting Node.
|
||||
|
||||
## Badge
|
||||
|
||||
Use this in one of your projects? Include one of these badges in your README.md to let people know that your package is published using `semantic-release`.
|
||||
@@ -309,6 +311,20 @@ Use this in one of your projects? Include one of these badges in your README.md
|
||||
[](https://github.com/semantic-release/semantic-release)
|
||||
```
|
||||
|
||||
## Node Support Policy
|
||||
|
||||
We only support [Long-Term Support](https://github.com/nodejs/Release) versions of Node starting with [Node 8.9.0 (LTS)](https://nodejs.org/en/blog/release/v8.9.0/).
|
||||
|
||||
We specifically limit our support to LTS versions of Node, not because this package won't work on other versions, but because we have a limited amount of time, and supporting LTS offers the greatest return on that investment.
|
||||
|
||||
It's possible this package will work correctly on newer versions of Node. It may even be possible to use this package on older versions of Node, though that's more unlikely as we'll make every effort to take advantage of features available in the oldest LTS version we support.
|
||||
|
||||
As each Node LTS version reaches its end-of-life we will remove that version from the node engines property of our package's package.json file. Removing a Node version is considered a breaking change and will entail the publishing of a new major version of this package. We will not accept any requests to support an end-of-life version of Node. Any merge requests or issues supporting an end-of-life version of Node will be closed.
|
||||
|
||||
We will accept code that allows this package to run on newer, non-LTS, versions of Node. Furthermore, we will attempt to ensure our own changes work on the latest version of Node. To help in that commitment, our continuous integration setup runs against all LTS versions of Node in addition the most recent Node release; called current.
|
||||
|
||||
JavaScript package managers should allow you to install this package with any version of Node, with, at most, a warning if your version of Node does not fall within the range specified by our node engines property. If you encounter issues installing this package, please report the issue to your package manager.
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
+3
-9
@@ -84,24 +84,18 @@ function noGitHeadMessage(branch, version) {
|
||||
This means semantic-release can not extract the commits between now and then.
|
||||
This is usually caused by releasing from outside the repository directory or with innaccessible git metadata.
|
||||
|
||||
You can recover from this error by creating a tag for the version "${
|
||||
version
|
||||
}" on the commit corresponding to this release:
|
||||
You can recover from this error by creating a tag for the version "${version}" on the commit corresponding to this release:
|
||||
$ git tag -f v${version} <commit sha1 corresponding to last release>
|
||||
$ git push -f --tags origin ${branch}
|
||||
`;
|
||||
}
|
||||
|
||||
function notInHistoryMessage(gitHead, branch, version) {
|
||||
return `The commit the last release of this package was derived from is not in the direct history of the "${
|
||||
branch
|
||||
}" branch.
|
||||
return `The commit the last release of this package was derived from is not in the direct history of the "${branch}" branch.
|
||||
This means semantic-release can not extract the commits between now and then.
|
||||
This is usually caused by force pushing, releasing from an unrelated branch, or using an already existing package name.
|
||||
|
||||
You can recover from this error by restoring the commit "${gitHead}" or by creating a tag for the version "${
|
||||
version
|
||||
}" on the commit corresponding to this release:
|
||||
You can recover from this error by restoring the commit "${gitHead}" or by creating a tag for the version "${version}" on the commit corresponding to this release:
|
||||
$ git tag -f v${version || '<version>'} <commit sha1 corresponding to last release>
|
||||
$ git push -f --tags origin ${branch}
|
||||
`;
|
||||
|
||||
@@ -8,7 +8,7 @@ module.exports = (pluginType, pluginConfig, logger, validator) => {
|
||||
}
|
||||
const {path, ...config} = isString(pluginConfig) || isFunction(pluginConfig) ? {path: pluginConfig} : pluginConfig;
|
||||
if (!isFunction(pluginConfig)) {
|
||||
logger.log('Load plugin %s', path);
|
||||
logger.log('Load plugin %s from %s', pluginType, path);
|
||||
}
|
||||
const plugin = isFunction(path) ? path : importFrom.silent(__dirname, path) || importFrom(process.cwd(), path);
|
||||
|
||||
|
||||
+5
-4
@@ -18,7 +18,7 @@
|
||||
"@semantic-release/commit-analyzer": "^5.0.0",
|
||||
"@semantic-release/condition-travis": "^7.0.0",
|
||||
"@semantic-release/error": "^2.1.0",
|
||||
"@semantic-release/github": "^2.0.0",
|
||||
"@semantic-release/github": "^3.0.0",
|
||||
"@semantic-release/npm": "^2.0.0",
|
||||
"@semantic-release/release-notes-generator": "^6.0.0",
|
||||
"chalk": "^2.3.0",
|
||||
@@ -41,18 +41,19 @@
|
||||
"codecov": "^3.0.0",
|
||||
"commitizen": "^2.9.6",
|
||||
"cz-conventional-changelog": "^2.0.0",
|
||||
"delay": "^2.0.0",
|
||||
"dockerode": "^2.5.2",
|
||||
"eslint-config-prettier": "^2.5.0",
|
||||
"eslint-plugin-prettier": "^2.3.0",
|
||||
"file-url": "^2.0.2",
|
||||
"fs-extra": "^4.0.2",
|
||||
"fs-extra": "^5.0.0",
|
||||
"got": "^8.0.0",
|
||||
"js-yaml": "^3.10.0",
|
||||
"mockserver-client": "^2.0.0",
|
||||
"mockserver-client": "^5.1.1",
|
||||
"nock": "^9.0.2",
|
||||
"nyc": "^11.2.1",
|
||||
"p-retry": "^1.0.0",
|
||||
"prettier": "~1.8.0",
|
||||
"prettier": "~1.9.2",
|
||||
"proxyquire": "^1.8.0",
|
||||
"sinon": "^4.0.0",
|
||||
"tempy": "^0.2.1",
|
||||
|
||||
+14
-13
@@ -12,18 +12,19 @@ import {
|
||||
gitDetachedHead,
|
||||
} from './helpers/git-utils';
|
||||
|
||||
// Save the current working diretory
|
||||
const cwd = process.cwd();
|
||||
|
||||
test.beforeEach(t => {
|
||||
// Save the current working diretory
|
||||
t.context.cwd = process.cwd();
|
||||
// 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(t => {
|
||||
test.afterEach.always(() => {
|
||||
// Restore the current working directory
|
||||
process.chdir(t.context.cwd);
|
||||
process.chdir(cwd);
|
||||
});
|
||||
|
||||
test.serial('Get all commits when there is no last release', async t => {
|
||||
@@ -411,7 +412,7 @@ test.serial('Throws ENOGITHEAD error if the gitHead of the last release cannot b
|
||||
t.is(error.name, 'SemanticReleaseError');
|
||||
// Verify the log function has been called with a message explaining the error
|
||||
t.regex(
|
||||
t.context.error.firstCall.args[0],
|
||||
t.context.error.args[0][0],
|
||||
/The commit the last release of this package was derived from cannot be determined from the release metadata nor from the repository tags/
|
||||
);
|
||||
});
|
||||
@@ -429,9 +430,9 @@ test.serial('Throws ENOTINHISTORY error if gitHead is not in history', async t =
|
||||
t.is(error.code, 'ENOTINHISTORY');
|
||||
t.is(error.name, 'SemanticReleaseError');
|
||||
// Verify the log function has been called with a message mentionning the branch
|
||||
t.regex(t.context.error.firstCall.args[0], /history of the "master" branch/);
|
||||
t.regex(t.context.error.args[0][0], /history of the "master" branch/);
|
||||
// Verify the log function has been called with a message mentionning the missing gitHead
|
||||
t.regex(t.context.error.firstCall.args[0], /restoring the commit "notinhistory"/);
|
||||
t.regex(t.context.error.args[0][0], /restoring the commit "notinhistory"/);
|
||||
});
|
||||
|
||||
test.serial('Throws ENOTINHISTORY error if gitHead is not in branch history but present in others', async t => {
|
||||
@@ -454,9 +455,9 @@ test.serial('Throws ENOTINHISTORY error if gitHead is not in branch history but
|
||||
t.is(error.code, 'ENOTINHISTORY');
|
||||
t.is(error.name, 'SemanticReleaseError');
|
||||
// Verify the log function has been called with a message mentionning the branch
|
||||
t.regex(t.context.error.firstCall.args[0], /history of the "master" branch/);
|
||||
t.regex(t.context.error.args[0][0], /history of the "master" branch/);
|
||||
// Verify the log function has been called with a message mentionning the missing gitHead
|
||||
t.regex(t.context.error.firstCall.args[0], new RegExp(`restoring the commit "${commitsBranch[0].hash}"`));
|
||||
t.regex(t.context.error.args[0][0], new RegExp(`restoring the commit "${commitsBranch[0].hash}"`));
|
||||
});
|
||||
|
||||
test.serial('Throws ENOTINHISTORY error if gitHead is not in detached head but present in other branch', async t => {
|
||||
@@ -483,9 +484,9 @@ test.serial('Throws ENOTINHISTORY error if gitHead is not in detached head but p
|
||||
t.is(error.code, 'ENOTINHISTORY');
|
||||
t.is(error.name, 'SemanticReleaseError');
|
||||
// Verify the log function has been called with a message mentionning the branch
|
||||
t.regex(t.context.error.firstCall.args[0], /history of the "master" branch/);
|
||||
t.regex(t.context.error.args[0][0], /history of the "master" branch/);
|
||||
// Verify the log function has been called with a message mentionning the missing gitHead
|
||||
t.regex(t.context.error.firstCall.args[0], new RegExp(`restoring the commit "${commitsBranch[0].hash}"`));
|
||||
t.regex(t.context.error.args[0][0], new RegExp(`restoring the commit "${commitsBranch[0].hash}"`));
|
||||
});
|
||||
|
||||
test.serial('Throws ENOTINHISTORY error when a tag is not in branch history but present in others', async t => {
|
||||
@@ -509,7 +510,7 @@ test.serial('Throws ENOTINHISTORY error when a tag is not in branch history but
|
||||
t.is(error.code, 'ENOTINHISTORY');
|
||||
t.is(error.name, 'SemanticReleaseError');
|
||||
// Verify the log function has been called with a message mentionning the branch
|
||||
t.regex(t.context.error.firstCall.args[0], /history of the "master" branch/);
|
||||
t.regex(t.context.error.args[0][0], /history of the "master" branch/);
|
||||
// Verify the log function has been called with a message mentionning the missing gitHead
|
||||
t.regex(t.context.error.firstCall.args[0], new RegExp(`restoring the commit "${shaTag}"`));
|
||||
t.regex(t.context.error.args[0][0], new RegExp(`restoring the commit "${shaTag}"`));
|
||||
});
|
||||
|
||||
+15
-14
@@ -5,20 +5,21 @@ import {stub} from 'sinon';
|
||||
import yaml from 'js-yaml';
|
||||
import {gitRepo, gitCommits, gitShallowClone, gitAddConfig} from './helpers/git-utils';
|
||||
|
||||
// Save the current process.env
|
||||
const envBackup = Object.assign({}, process.env);
|
||||
// Save the current working diretory
|
||||
const cwd = process.cwd();
|
||||
|
||||
test.beforeEach(t => {
|
||||
// Save the current process.env
|
||||
t.context.env = Object.assign({}, process.env);
|
||||
// Save the current working diretory
|
||||
t.context.cwd = process.cwd();
|
||||
t.context.plugins = stub().returns({});
|
||||
t.context.getConfig = proxyquire('../lib/get-config', {'./plugins': t.context.plugins});
|
||||
});
|
||||
|
||||
test.afterEach.always(t => {
|
||||
// Restore the current working directory
|
||||
process.chdir(t.context.cwd);
|
||||
test.afterEach.always(() => {
|
||||
// Restore process.env
|
||||
process.env = Object.assign({}, t.context.env);
|
||||
process.env = envBackup;
|
||||
// Restore the current working directory
|
||||
process.chdir(cwd);
|
||||
});
|
||||
|
||||
test.serial('Default values, reading repositoryUrl from package.json', async t => {
|
||||
@@ -84,7 +85,7 @@ test.serial('Read options from package.json', async t => {
|
||||
// Verify the options contains the plugin config from package.json
|
||||
t.deepEqual(options, release);
|
||||
// Verify the plugins module is called with the plugin options from package.json
|
||||
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||
t.deepEqual(t.context.plugins.args[0][0], release);
|
||||
});
|
||||
|
||||
test.serial('Read options from .releaserc.yml', async t => {
|
||||
@@ -104,7 +105,7 @@ test.serial('Read options from .releaserc.yml', async t => {
|
||||
// Verify the options contains the plugin config from package.json
|
||||
t.deepEqual(options, release);
|
||||
// Verify the plugins module is called with the plugin options from package.json
|
||||
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||
t.deepEqual(t.context.plugins.args[0][0], release);
|
||||
});
|
||||
|
||||
test.serial('Read options from .releaserc.json', async t => {
|
||||
@@ -124,7 +125,7 @@ test.serial('Read options from .releaserc.json', async t => {
|
||||
// Verify the options contains the plugin config from package.json
|
||||
t.deepEqual(options, release);
|
||||
// Verify the plugins module is called with the plugin options from package.json
|
||||
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||
t.deepEqual(t.context.plugins.args[0][0], release);
|
||||
});
|
||||
|
||||
test.serial('Read options from .releaserc.js', async t => {
|
||||
@@ -144,7 +145,7 @@ test.serial('Read options from .releaserc.js', async t => {
|
||||
// Verify the options contains the plugin config from package.json
|
||||
t.deepEqual(options, release);
|
||||
// Verify the plugins module is called with the plugin options from package.json
|
||||
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||
t.deepEqual(t.context.plugins.args[0][0], release);
|
||||
});
|
||||
|
||||
test.serial('Read options from release.config.js', async t => {
|
||||
@@ -164,7 +165,7 @@ test.serial('Read options from release.config.js', async t => {
|
||||
// Verify the options contains the plugin config from package.json
|
||||
t.deepEqual(options, release);
|
||||
// Verify the plugins module is called with the plugin options from package.json
|
||||
t.deepEqual(t.context.plugins.firstCall.args[0], release);
|
||||
t.deepEqual(t.context.plugins.args[0][0], release);
|
||||
});
|
||||
|
||||
test.serial('Prioritise cli parameters over file configuration and git repo', async t => {
|
||||
@@ -191,5 +192,5 @@ test.serial('Prioritise cli parameters over file configuration and git repo', as
|
||||
// Verify the options contains the plugin config from cli
|
||||
t.deepEqual(result.options, options);
|
||||
// Verify the plugins module is called with the plugin options from cli
|
||||
t.deepEqual(t.context.plugins.firstCall.args[0], options);
|
||||
t.deepEqual(t.context.plugins.args[0][0], options);
|
||||
});
|
||||
|
||||
+4
-6
@@ -11,14 +11,12 @@ import {
|
||||
gitAddConfig,
|
||||
} from './helpers/git-utils';
|
||||
|
||||
test.beforeEach(t => {
|
||||
// Save the current working diretory
|
||||
t.context.cwd = process.cwd();
|
||||
});
|
||||
// Save the current working diretory
|
||||
const cwd = process.cwd();
|
||||
|
||||
test.afterEach.always(t => {
|
||||
test.afterEach.always(() => {
|
||||
// Restore the current working directory
|
||||
process.chdir(t.context.cwd);
|
||||
process.chdir(cwd);
|
||||
});
|
||||
|
||||
test.serial('Get the last commit sha', async t => {
|
||||
|
||||
@@ -7,8 +7,10 @@ import nock from 'nock';
|
||||
* @param {String} [githubUrl='https://api.github.com'] The url on which to intercept http requests.
|
||||
* @return {Object} A `nock` object ready to respond to a github authentication request.
|
||||
*/
|
||||
export default function authenticate(
|
||||
{githubToken = 'GH_TOKEN', githubUrl = 'https://api.github.com', githubApiPathPrefix = ''} = {}
|
||||
) {
|
||||
export default function authenticate({
|
||||
githubToken = 'GH_TOKEN',
|
||||
githubUrl = 'https://api.github.com',
|
||||
githubApiPathPrefix = '',
|
||||
} = {}) {
|
||||
return nock(`${githubUrl}/${githubApiPathPrefix}`, {reqheaders: {Authorization: `token ${githubToken}`}});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Docker from 'dockerode';
|
||||
import getStream from 'get-stream';
|
||||
import got from 'got';
|
||||
import delay from 'delay';
|
||||
import pRetry from 'p-retry';
|
||||
|
||||
const IMAGE = 'npmjs/npm-docker-couchdb:1.6.1';
|
||||
@@ -28,6 +29,7 @@ async function start() {
|
||||
});
|
||||
|
||||
await container.start();
|
||||
await delay(3000);
|
||||
|
||||
try {
|
||||
// Wait for the registry to be ready
|
||||
|
||||
+66
-68
@@ -6,29 +6,27 @@ import DEFINITIONS from '../lib/plugins/definitions';
|
||||
import {gitHead as getGitHead} from '../lib/git';
|
||||
import {gitRepo, gitCommits, gitTagVersion} from './helpers/git-utils';
|
||||
|
||||
// Save the current process.env
|
||||
const envBackup = Object.assign({}, process.env);
|
||||
// Save the current working diretory
|
||||
const cwd = process.cwd();
|
||||
|
||||
stub(process.stdout, 'write');
|
||||
stub(process.stderr, 'write');
|
||||
|
||||
test.beforeEach(t => {
|
||||
// Save the current process.env
|
||||
t.context.env = Object.assign({}, process.env);
|
||||
// Save the current working diretory
|
||||
t.context.cwd = process.cwd();
|
||||
// Stub the logger functions
|
||||
t.context.log = stub();
|
||||
t.context.error = stub();
|
||||
t.context.logger = {log: t.context.log, error: t.context.error};
|
||||
t.context.semanticRelease = proxyquire('../index', {'./lib/logger': t.context.logger});
|
||||
|
||||
t.context.stdout = stub(process.stdout, 'write');
|
||||
t.context.stderr = stub(process.stderr, 'write');
|
||||
});
|
||||
|
||||
test.afterEach.always(t => {
|
||||
test.afterEach.always(() => {
|
||||
// Restore process.env
|
||||
process.env = Object.assign({}, t.context.env);
|
||||
process.env = envBackup;
|
||||
// Restore the current working directory
|
||||
process.chdir(t.context.cwd);
|
||||
|
||||
t.context.stdout.restore();
|
||||
t.context.stderr.restore();
|
||||
process.chdir(cwd);
|
||||
});
|
||||
|
||||
test.serial('Plugins are called with expected values', async t => {
|
||||
@@ -65,44 +63,44 @@ test.serial('Plugins are called with expected values', async t => {
|
||||
|
||||
await t.context.semanticRelease(options);
|
||||
|
||||
t.true(verifyConditions1.calledOnce);
|
||||
t.deepEqual(verifyConditions1.firstCall.args[1], {options, logger: t.context.logger});
|
||||
t.true(verifyConditions2.calledOnce);
|
||||
t.deepEqual(verifyConditions2.firstCall.args[1], {options, logger: t.context.logger});
|
||||
t.is(verifyConditions1.callCount, 1);
|
||||
t.deepEqual(verifyConditions1.args[0][1], {options, logger: t.context.logger});
|
||||
t.is(verifyConditions2.callCount, 1);
|
||||
t.deepEqual(verifyConditions2.args[0][1], {options, logger: t.context.logger});
|
||||
|
||||
t.true(getLastRelease.calledOnce);
|
||||
t.deepEqual(getLastRelease.firstCall.args[1], {options, logger: t.context.logger});
|
||||
t.is(getLastRelease.callCount, 1);
|
||||
t.deepEqual(getLastRelease.args[0][1], {options, logger: t.context.logger});
|
||||
|
||||
t.true(analyzeCommits.calledOnce);
|
||||
t.deepEqual(analyzeCommits.firstCall.args[1].options, options);
|
||||
t.deepEqual(analyzeCommits.firstCall.args[1].logger, t.context.logger);
|
||||
t.deepEqual(analyzeCommits.firstCall.args[1].lastRelease, lastRelease);
|
||||
t.deepEqual(analyzeCommits.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.deepEqual(analyzeCommits.firstCall.args[1].commits[0].message, commits[0].message);
|
||||
t.is(analyzeCommits.callCount, 1);
|
||||
t.deepEqual(analyzeCommits.args[0][1].options, options);
|
||||
t.deepEqual(analyzeCommits.args[0][1].logger, t.context.logger);
|
||||
t.deepEqual(analyzeCommits.args[0][1].lastRelease, lastRelease);
|
||||
t.deepEqual(analyzeCommits.args[0][1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.deepEqual(analyzeCommits.args[0][1].commits[0].message, commits[0].message);
|
||||
|
||||
t.true(verifyRelease.calledOnce);
|
||||
t.deepEqual(verifyRelease.firstCall.args[1].options, options);
|
||||
t.deepEqual(verifyRelease.firstCall.args[1].logger, t.context.logger);
|
||||
t.deepEqual(verifyRelease.firstCall.args[1].lastRelease, lastRelease);
|
||||
t.deepEqual(verifyRelease.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.deepEqual(verifyRelease.firstCall.args[1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(verifyRelease.firstCall.args[1].nextRelease, nextRelease);
|
||||
t.is(verifyRelease.callCount, 1);
|
||||
t.deepEqual(verifyRelease.args[0][1].options, options);
|
||||
t.deepEqual(verifyRelease.args[0][1].logger, t.context.logger);
|
||||
t.deepEqual(verifyRelease.args[0][1].lastRelease, lastRelease);
|
||||
t.deepEqual(verifyRelease.args[0][1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.deepEqual(verifyRelease.args[0][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(verifyRelease.args[0][1].nextRelease, nextRelease);
|
||||
|
||||
t.true(generateNotes.calledOnce);
|
||||
t.deepEqual(generateNotes.firstCall.args[1].options, options);
|
||||
t.deepEqual(generateNotes.firstCall.args[1].logger, t.context.logger);
|
||||
t.deepEqual(generateNotes.firstCall.args[1].lastRelease, lastRelease);
|
||||
t.deepEqual(generateNotes.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.deepEqual(generateNotes.firstCall.args[1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(generateNotes.firstCall.args[1].nextRelease, nextRelease);
|
||||
t.is(generateNotes.callCount, 1);
|
||||
t.deepEqual(generateNotes.args[0][1].options, options);
|
||||
t.deepEqual(generateNotes.args[0][1].logger, t.context.logger);
|
||||
t.deepEqual(generateNotes.args[0][1].lastRelease, lastRelease);
|
||||
t.deepEqual(generateNotes.args[0][1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.deepEqual(generateNotes.args[0][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease);
|
||||
|
||||
t.true(publish.calledOnce);
|
||||
t.deepEqual(publish.firstCall.args[1].options, options);
|
||||
t.deepEqual(publish.firstCall.args[1].logger, t.context.logger);
|
||||
t.deepEqual(publish.firstCall.args[1].lastRelease, lastRelease);
|
||||
t.deepEqual(publish.firstCall.args[1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.deepEqual(publish.firstCall.args[1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(publish.firstCall.args[1].nextRelease, Object.assign({}, nextRelease, {notes}));
|
||||
t.is(publish.callCount, 1);
|
||||
t.deepEqual(publish.args[0][1].options, options);
|
||||
t.deepEqual(publish.args[0][1].logger, t.context.logger);
|
||||
t.deepEqual(publish.args[0][1].lastRelease, lastRelease);
|
||||
t.deepEqual(publish.args[0][1].commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.deepEqual(publish.args[0][1].commits[0].message, commits[0].message);
|
||||
t.deepEqual(publish.args[0][1].nextRelease, Object.assign({}, nextRelease, {notes}));
|
||||
});
|
||||
|
||||
test.serial('Use new gitHead, and recreate release notes if a publish plugin create a commit', async t => {
|
||||
@@ -138,16 +136,16 @@ test.serial('Use new gitHead, and recreate release notes if a publish plugin cre
|
||||
|
||||
await t.context.semanticRelease(options);
|
||||
|
||||
t.true(generateNotes.calledTwice);
|
||||
t.deepEqual(generateNotes.firstCall.args[1].nextRelease, nextRelease);
|
||||
t.true(publish1.calledOnce);
|
||||
t.deepEqual(publish1.firstCall.args[1].nextRelease, Object.assign({}, nextRelease, {notes}));
|
||||
t.is(generateNotes.callCount, 2);
|
||||
t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease);
|
||||
t.is(publish1.callCount, 1);
|
||||
t.deepEqual(publish1.args[0][1].nextRelease, Object.assign({}, nextRelease, {notes}));
|
||||
|
||||
nextRelease.gitHead = await getGitHead();
|
||||
|
||||
t.deepEqual(generateNotes.secondCall.args[1].nextRelease, Object.assign({}, nextRelease, {notes}));
|
||||
t.true(publish2.calledOnce);
|
||||
t.deepEqual(publish2.firstCall.args[1].nextRelease, Object.assign({}, nextRelease, {notes}));
|
||||
t.is(publish2.callCount, 1);
|
||||
t.deepEqual(publish2.args[0][1].nextRelease, Object.assign({}, nextRelease, {notes}));
|
||||
});
|
||||
|
||||
test.serial('Dry-run skips verifyConditions and publish', async t => {
|
||||
@@ -185,12 +183,12 @@ test.serial('Dry-run skips verifyConditions and publish', async t => {
|
||||
|
||||
await t.context.semanticRelease(options);
|
||||
|
||||
t.true(verifyConditions.notCalled);
|
||||
t.true(getLastRelease.calledOnce);
|
||||
t.true(analyzeCommits.calledOnce);
|
||||
t.true(verifyRelease.calledOnce);
|
||||
t.true(generateNotes.calledOnce);
|
||||
t.true(publish.notCalled);
|
||||
t.is(verifyConditions.callCount, 0);
|
||||
t.is(getLastRelease.callCount, 1);
|
||||
t.is(analyzeCommits.callCount, 1);
|
||||
t.is(verifyRelease.callCount, 1);
|
||||
t.is(generateNotes.callCount, 1);
|
||||
t.is(publish.callCount, 0);
|
||||
});
|
||||
|
||||
test.serial('Accept "undefined" values for the "getLastRelease" and "generateNotes" plugins', async t => {
|
||||
@@ -225,20 +223,20 @@ test.serial('Accept "undefined" values for the "getLastRelease" and "generateNot
|
||||
|
||||
await t.context.semanticRelease(options);
|
||||
|
||||
t.true(getLastRelease.calledOnce);
|
||||
t.is(getLastRelease.callCount, 1);
|
||||
|
||||
t.true(analyzeCommits.calledOnce);
|
||||
t.deepEqual(analyzeCommits.firstCall.args[1].lastRelease, lastRelease);
|
||||
t.is(analyzeCommits.callCount, 1);
|
||||
t.deepEqual(analyzeCommits.args[0][1].lastRelease, lastRelease);
|
||||
|
||||
t.true(verifyRelease.calledOnce);
|
||||
t.deepEqual(verifyRelease.firstCall.args[1].lastRelease, lastRelease);
|
||||
t.is(verifyRelease.callCount, 1);
|
||||
t.deepEqual(verifyRelease.args[0][1].lastRelease, lastRelease);
|
||||
|
||||
t.true(generateNotes.calledOnce);
|
||||
t.deepEqual(generateNotes.firstCall.args[1].lastRelease, lastRelease);
|
||||
t.is(generateNotes.callCount, 1);
|
||||
t.deepEqual(generateNotes.args[0][1].lastRelease, lastRelease);
|
||||
|
||||
t.true(publish.calledOnce);
|
||||
t.deepEqual(publish.firstCall.args[1].lastRelease, lastRelease);
|
||||
t.falsy(publish.firstCall.args[1].nextRelease.notes);
|
||||
t.is(publish.callCount, 1);
|
||||
t.deepEqual(publish.args[0][1].lastRelease, lastRelease);
|
||||
t.falsy(publish.args[0][1].nextRelease.notes);
|
||||
});
|
||||
|
||||
test.serial('Throw SemanticReleaseError if not running from a git repository', async t => {
|
||||
|
||||
+20
-30
@@ -23,9 +23,16 @@ const testEnv = Object.assign({}, process.env, {
|
||||
NPM_EMAIL: 'integration@test.com',
|
||||
LEGACY_TOKEN: Buffer.from(`${process.env.NPM_USERNAME}:${process.env.NPM_PASSWORD}`, 'utf8').toString('base64'),
|
||||
});
|
||||
// Save the current process.env
|
||||
const envBackup = Object.assign({}, process.env);
|
||||
const cli = require.resolve('../bin/semantic-release');
|
||||
const pluginError = require.resolve('./fixtures/plugin-error');
|
||||
const pluginInheritedError = require.resolve('./fixtures/plugin-error-inherited');
|
||||
// Save the current working diretory
|
||||
const cwd = process.cwd();
|
||||
// Disable logs during tests
|
||||
stub(process.stdout, 'write');
|
||||
stub(process.stderr, 'write');
|
||||
|
||||
test.before(async () => {
|
||||
// Start the local NPM registry
|
||||
@@ -34,11 +41,7 @@ test.before(async () => {
|
||||
await mockServer.start();
|
||||
});
|
||||
|
||||
test.beforeEach(t => {
|
||||
// Save the current process.env
|
||||
t.context.env = Object.assign({}, process.env);
|
||||
// Save the current working diretory
|
||||
t.context.cwd = process.cwd();
|
||||
test.beforeEach(() => {
|
||||
// Delete env paramaters that could have been set on the machine running the tests
|
||||
delete process.env.NPM_TOKEN;
|
||||
delete process.env.NPM_USERNAME;
|
||||
@@ -56,23 +59,13 @@ test.beforeEach(t => {
|
||||
delete process.env[keys[i]];
|
||||
}
|
||||
}
|
||||
// Disable logs during tests
|
||||
t.context.log = stub(console, 'log');
|
||||
t.context.error = stub(console, 'error');
|
||||
t.context.stdout = stub(process.stdout, 'write');
|
||||
t.context.stderr = stub(process.stderr, 'write');
|
||||
});
|
||||
|
||||
test.afterEach.always(t => {
|
||||
test.afterEach.always(() => {
|
||||
// Restore process.env
|
||||
process.env = Object.assign({}, t.context.env);
|
||||
process.env = envBackup;
|
||||
// Restore the current working directory
|
||||
process.chdir(t.context.cwd);
|
||||
// Restore the logs
|
||||
t.context.log.restore();
|
||||
t.context.error.restore();
|
||||
t.context.stdout.restore();
|
||||
t.context.stderr.restore();
|
||||
process.chdir(cwd);
|
||||
});
|
||||
|
||||
test.after.always(async () => {
|
||||
@@ -492,9 +485,7 @@ test.serial('Create a tag as a recovery solution for "ENOTINHISTORY" error', asy
|
||||
t.regex(
|
||||
stderr,
|
||||
new RegExp(
|
||||
`You can recover from this error by restoring the commit "${head}" or by creating a tag for the version "${
|
||||
version
|
||||
}" on the commit corresponding to this release`
|
||||
`You can recover from this error by restoring the commit "${head}" or by creating a tag for the version "${version}" on the commit corresponding to this release`
|
||||
)
|
||||
);
|
||||
|
||||
@@ -611,7 +602,6 @@ test.serial('Pass options via CLI arguments', async t => {
|
||||
test.serial('Run via JS API', async t => {
|
||||
const packageName = 'test-js-api';
|
||||
const owner = 'test-repo';
|
||||
const githubToken = 'OTHER_TOKEN';
|
||||
// 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();
|
||||
@@ -627,19 +617,22 @@ test.serial('Run via JS API', async t => {
|
||||
const version = '1.0.0';
|
||||
const verifyMock = await mockServer.mock(
|
||||
`/repos/${owner}/${packageName}`,
|
||||
{headers: [{name: 'Authorization', values: [`token ${githubToken}`]}]},
|
||||
{headers: [{name: 'Authorization', values: [`token ${env.GH_TOKEN}`]}]},
|
||||
{body: {permissions: {push: true}}, method: 'GET'}
|
||||
);
|
||||
const createRefMock = await mockServer.mock(
|
||||
`/repos/${owner}/${packageName}/git/refs`,
|
||||
{body: {ref: `refs/tags/v${version}`}, headers: [{name: 'Authorization', values: [`token ${githubToken}`]}]},
|
||||
{
|
||||
body: {ref: `refs/tags/v${version}`},
|
||||
headers: [{name: 'Authorization', values: [`token ${env.GH_TOKEN}`]}],
|
||||
},
|
||||
{body: {ref: `refs/tags/${version}`}}
|
||||
);
|
||||
const createReleaseMock = await mockServer.mock(
|
||||
`/repos/${owner}/${packageName}/releases`,
|
||||
{
|
||||
body: {tag_name: `v${version}`, target_commitish: 'master', name: `v${version}`},
|
||||
headers: [{name: 'Authorization', values: [`token ${githubToken}`]}],
|
||||
headers: [{name: 'Authorization', values: [`token ${env.GH_TOKEN}`]}],
|
||||
},
|
||||
{body: {html_url: `release-url/${version}`}}
|
||||
);
|
||||
@@ -650,14 +643,11 @@ test.serial('Run via JS API', async t => {
|
||||
await gitCommits(['feat: Initial commit']);
|
||||
t.log('$ Call semantic-release via API');
|
||||
await semanticRelease({
|
||||
verifyConditions: [{path: '@semantic-release/github', githubToken}, '@semantic-release/npm'],
|
||||
publish: [{path: '@semantic-release/github', githubToken}, '@semantic-release/npm'],
|
||||
verifyConditions: [{path: '@semantic-release/github'}, '@semantic-release/npm'],
|
||||
publish: [{path: '@semantic-release/github'}, '@semantic-release/npm'],
|
||||
debug: true,
|
||||
});
|
||||
|
||||
t.true(t.context.log.calledWithMatch(/Published Github release: /, new RegExp(`release-url/${version}`)));
|
||||
t.true(t.context.log.calledWithMatch(/Publishing version .* to npm registry/, version));
|
||||
|
||||
// Verify package.json and has been updated
|
||||
t.is((await readJson('./package.json')).version, version);
|
||||
|
||||
|
||||
+12
-9
@@ -1,5 +1,5 @@
|
||||
import test from 'ava';
|
||||
import {stub, match} from 'sinon';
|
||||
import {stub} from 'sinon';
|
||||
import logger from '../lib/logger';
|
||||
|
||||
test.beforeEach(t => {
|
||||
@@ -16,8 +16,8 @@ test.serial('Basic log', t => {
|
||||
logger.log('test log');
|
||||
logger.error('test error');
|
||||
|
||||
t.true(t.context.log.calledWithMatch(/.*test log/));
|
||||
t.true(t.context.error.calledWithMatch(/.*test error/));
|
||||
t.regex(t.context.log.args[0][0], /.*test log/);
|
||||
t.regex(t.context.error.args[0][0], /.*test error/);
|
||||
});
|
||||
|
||||
test.serial('Log object', t => {
|
||||
@@ -25,16 +25,18 @@ test.serial('Log object', t => {
|
||||
logger.log(obj);
|
||||
logger.error(obj);
|
||||
|
||||
t.true(t.context.log.calledWithMatch(match.string, obj));
|
||||
t.true(t.context.error.calledWithMatch(match.string, obj));
|
||||
t.is(t.context.log.args[0][1], obj);
|
||||
t.is(t.context.error.args[0][1], obj);
|
||||
});
|
||||
|
||||
test.serial('Log with string formatting', t => {
|
||||
logger.log('test log %s', 'log value');
|
||||
logger.error('test error %s', 'error value');
|
||||
|
||||
t.true(t.context.log.calledWithMatch(/.*test log/, 'log value'));
|
||||
t.true(t.context.error.calledWithMatch(/.*test error/, 'error value'));
|
||||
t.regex(t.context.log.args[0][0], /.*test log/);
|
||||
t.regex(t.context.error.args[0][0], /.*test error/);
|
||||
t.is(t.context.log.args[0][1], 'log value');
|
||||
t.is(t.context.error.args[0][1], 'error value');
|
||||
});
|
||||
|
||||
test.serial('Log with error stacktrace and properties', t => {
|
||||
@@ -43,6 +45,7 @@ test.serial('Log with error stacktrace and properties', t => {
|
||||
const otherError = new Error('other error message');
|
||||
logger.error('test error %O', otherError);
|
||||
|
||||
t.true(t.context.error.calledWithMatch(match.string, error));
|
||||
t.true(t.context.error.calledWithMatch(/.*test error/, otherError));
|
||||
t.is(t.context.error.args[0][1], error);
|
||||
t.regex(t.context.error.args[1][0], /.*test error/);
|
||||
t.is(t.context.error.args[1][1], otherError);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import test from 'ava';
|
||||
import {noop} from 'lodash';
|
||||
import {stub, match} from 'sinon';
|
||||
import {stub} from 'sinon';
|
||||
import normalize from '../../lib/plugins/normalize';
|
||||
|
||||
test.beforeEach(t => {
|
||||
@@ -10,17 +10,17 @@ test.beforeEach(t => {
|
||||
});
|
||||
|
||||
test('Normalize and load plugin from string', t => {
|
||||
const plugin = normalize('', './test/fixtures/plugin-noop', t.context.logger);
|
||||
const plugin = normalize('verifyConditions', './test/fixtures/plugin-noop', t.context.logger);
|
||||
|
||||
t.is(typeof plugin, 'function');
|
||||
t.true(t.context.log.calledWith(match.string, './test/fixtures/plugin-noop'));
|
||||
t.deepEqual(t.context.log.args[0], ['Load plugin %s from %s', 'verifyConditions', './test/fixtures/plugin-noop']);
|
||||
});
|
||||
|
||||
test('Normalize and load plugin from object', t => {
|
||||
const plugin = normalize('', {path: './test/fixtures/plugin-noop'}, t.context.logger);
|
||||
const plugin = normalize('publish', {path: './test/fixtures/plugin-noop'}, t.context.logger);
|
||||
|
||||
t.is(typeof plugin, 'function');
|
||||
t.true(t.context.log.calledWith(match.string, './test/fixtures/plugin-noop'));
|
||||
t.deepEqual(t.context.log.args[0], ['Load plugin %s from %s', 'publish', './test/fixtures/plugin-noop']);
|
||||
});
|
||||
|
||||
test('Normalize and load plugin from function', t => {
|
||||
@@ -33,7 +33,7 @@ test('Normalize and load plugin that retuns multiple functions', t => {
|
||||
const plugin = normalize('verifyConditions', './test/fixtures/multi-plugin', t.context.logger);
|
||||
|
||||
t.is(typeof plugin, 'function');
|
||||
t.true(t.context.log.calledWith(match.string, './test/fixtures/multi-plugin'));
|
||||
t.deepEqual(t.context.log.args[0], ['Load plugin %s from %s', 'verifyConditions', './test/fixtures/multi-plugin']);
|
||||
});
|
||||
|
||||
test('Wrap plugin in a function that validate the output of the plugin', async t => {
|
||||
|
||||
Reference in New Issue
Block a user