Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4951b7c30 | ||
|
|
17a600672f | ||
|
|
470697c01d | ||
|
|
94b00e21c7 | ||
|
|
d0180c4348 | ||
|
|
186950acc0 | ||
|
|
c90765e10d | ||
|
|
ad2e1d76b7 | ||
|
|
65d344bae8 | ||
|
|
8a1dd7b324 |
@@ -0,0 +1 @@
|
||||
base: app0ZOxG0FnHmOiuU
|
||||
@@ -87,8 +87,8 @@ When pushing new commits with `git push` a CI build is triggered. After running
|
||||
|
||||
| Step | Description |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------- |
|
||||
| Verify Conditions` | Run the [verifyConditions](#verifyConditions) plugin) |
|
||||
| Get last release` | Obtain last release with the [getLastRelease](#getLastRelease) plugin |
|
||||
| Verify Conditions | Run the [verifyConditions](#verifyConditions) plugin) |
|
||||
| Get last release | Obtain last release with the [getLastRelease](#getLastRelease) plugin |
|
||||
| Analyze commits | Determine the type of release to do with the [analyzeCommits](#analyzeCommits) plugin |
|
||||
| Verify release | Call the [verifyRelease](#verifyRelease) plugin |
|
||||
| npm publish | Update the version in `package.json` and call `npm publish` |
|
||||
|
||||
+6
-5
@@ -15,17 +15,19 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@semantic-release/commit-analyzer": "^3.0.1",
|
||||
"@semantic-release/commit-analyzer": "^4.0.0",
|
||||
"@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": "^4.0.0",
|
||||
"@semantic-release/release-notes-generator": "^5.0.0",
|
||||
"chalk": "^2.3.0",
|
||||
"commander": "^2.11.0",
|
||||
"debug": "^3.1.0",
|
||||
"execa": "^0.8.0",
|
||||
"fs-extra": "^4.0.2",
|
||||
"get-stream": "^3.0.0",
|
||||
"git-head": "^1.2.1",
|
||||
"git-log-parser": "^1.2.0",
|
||||
"github": "^12.0.0",
|
||||
"lodash": "^4.0.0",
|
||||
"marked": "^0.3.6",
|
||||
@@ -52,13 +54,12 @@
|
||||
"eslint-plugin-prettier": "^2.3.0",
|
||||
"eslint-plugin-promise": "^3.5.0",
|
||||
"eslint-plugin-standard": "^3.0.1",
|
||||
"get-stream": "^3.0.0",
|
||||
"mockserver-client": "^1.0.16",
|
||||
"nock": "^9.0.2",
|
||||
"npm-registry-couchapp": "^2.6.12",
|
||||
"nyc": "^11.2.1",
|
||||
"p-map-series": "^1.0.0",
|
||||
"prettier": "^1.7.0",
|
||||
"prettier": "~1.8.0",
|
||||
"proxyquire": "^1.8.0",
|
||||
"rimraf": "^2.5.0",
|
||||
"sinon": "^4.0.0",
|
||||
|
||||
+2
-3
@@ -1,5 +1,4 @@
|
||||
const program = require('commander');
|
||||
const SemanticReleaseError = require('@semantic-release/error');
|
||||
const logger = require('./lib/logger');
|
||||
|
||||
function list(values) {
|
||||
@@ -49,11 +48,11 @@ 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;
|
||||
logger.error(err);
|
||||
logger.error('An error occurred while running semantic-release: %O', err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
+28
-31
@@ -1,4 +1,6 @@
|
||||
const execa = require('execa');
|
||||
const gitLogParser = require('git-log-parser');
|
||||
const getStream = require('get-stream');
|
||||
const debug = require('debug')('semantic-release:get-commits');
|
||||
const getVersionHead = require('./get-version-head');
|
||||
const {debugShell} = require('./debug');
|
||||
@@ -6,7 +8,7 @@ const logger = require('./logger');
|
||||
|
||||
/**
|
||||
* Commit message.
|
||||
*
|
||||
*
|
||||
* @typedef {Object} Commit
|
||||
* @property {string} hash The commit hash.
|
||||
* @property {string} message The commit message.
|
||||
@@ -14,7 +16,7 @@ const logger = require('./logger');
|
||||
|
||||
/**
|
||||
* Last release.
|
||||
*
|
||||
*
|
||||
* @typedef {Object} LastRelease
|
||||
* @property {string} version The version number of the last release.
|
||||
* @property {string} [gitHead] The commit sha used to make the last release.
|
||||
@@ -22,7 +24,7 @@ const logger = require('./logger');
|
||||
|
||||
/**
|
||||
* Result object.
|
||||
*
|
||||
*
|
||||
* @typedef {Object} Result
|
||||
* @property {Array<Commit>} commits The list of commits since the last release.
|
||||
* @property {LastRelease} lastRelease The updated lastRelease.
|
||||
@@ -30,7 +32,7 @@ const logger = require('./logger');
|
||||
|
||||
/**
|
||||
* Retrieve the list of commits on the current branch since the last released version, or all the commits of the current branch if there is no last released version.
|
||||
*
|
||||
*
|
||||
* The commit correspoding to the last released version is determined as follow:
|
||||
* - Use `lastRelease.gitHead` if defined and present in `branch` history.
|
||||
* - If `lastRelease.gitHead` is not in the `branch` history, unshallow the repository and try again.
|
||||
@@ -39,9 +41,9 @@ const logger = require('./logger');
|
||||
* @param {LastRelease} lastRelease The lastRelease object obtained from the getLastRelease plugin.
|
||||
* @param {string} branch The branch to release from.
|
||||
* @param {Object} logger Global logger.
|
||||
*
|
||||
*
|
||||
* @return {Promise<Result>} The list of commits on the branch `branch` since the last release and the updated lastRelease with the gitHead used to retrieve the commits.
|
||||
*
|
||||
*
|
||||
* @throws {SemanticReleaseError} with code `ENOTINHISTORY` if `lastRelease.gitHead` or the commit sha derived from `config.lastRelease.version` is not in the direct history of `branch`.
|
||||
* @throws {SemanticReleaseError} with code `ENOGITHEAD` if `lastRelease.gitHead` is undefined and no commit sha can be found for the `config.lastRelease.version`.
|
||||
*/
|
||||
@@ -65,28 +67,17 @@ module.exports = async ({version, gitHead}, branch) => {
|
||||
debugShell('Unshallow repo', shell, debug);
|
||||
}
|
||||
|
||||
try {
|
||||
const shell = await execa('git', [
|
||||
'log',
|
||||
'--format=format:%H==SPLIT==%B==END==',
|
||||
`${gitHead ? gitHead + '..' : ''}HEAD`,
|
||||
]);
|
||||
debugShell('Get commits', shell, debug);
|
||||
const commits = shell.stdout
|
||||
.split('==END==')
|
||||
.filter(raw => !!raw.trim())
|
||||
.map(raw => {
|
||||
const [hash, message] = raw.trim().split('==SPLIT==');
|
||||
return {hash, message};
|
||||
});
|
||||
logger.log('Found %s commits since last release', commits.length);
|
||||
debug('Parsed commits: %o', commits);
|
||||
return {commits, lastRelease: {version, gitHead}};
|
||||
} catch (err) {
|
||||
debug(err);
|
||||
logger.log('Found no commit since last release');
|
||||
return {commits: [], lastRelease: {version, gitHead}};
|
||||
}
|
||||
Object.assign(gitLogParser.fields, {hash: 'H', message: 'B', gitTags: 'd', committerDate: {key: 'ci', type: Date}});
|
||||
const commits = (await getStream.array(gitLogParser.parse({_: `${gitHead ? gitHead + '..' : ''}HEAD`}))).map(
|
||||
commit => {
|
||||
commit.message = commit.message.trim();
|
||||
commit.gitTags = commit.gitTags.trim();
|
||||
return commit;
|
||||
}
|
||||
);
|
||||
logger.log('Found %s commits since last release', commits.length);
|
||||
debug('Parsed commits: %o', commits);
|
||||
return {commits, lastRelease: {version, gitHead}};
|
||||
};
|
||||
|
||||
function noGitHeadMessage(branch, version) {
|
||||
@@ -94,18 +85,24 @@ 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}
|
||||
`;
|
||||
|
||||
@@ -7,7 +7,7 @@ const {debugShell} = require('./debug');
|
||||
* Get the commit sha for a given tag.
|
||||
*
|
||||
* @param {string} tagName Tag name for which to retrieve the commit sha.
|
||||
*
|
||||
*
|
||||
* @return {string} The commit sha of the tag in parameter or `null`.
|
||||
*/
|
||||
async function gitTagHead(tagName) {
|
||||
@@ -23,9 +23,9 @@ async function gitTagHead(tagName) {
|
||||
|
||||
/**
|
||||
* Verify if the commist `sha` is in the direct history of the current branch.
|
||||
*
|
||||
*
|
||||
* @param {string} sha The sha of the commit to look for.
|
||||
*
|
||||
*
|
||||
* @return {boolean} `true` if the commit `sha` is in the history of the current branch, `false` otherwise.
|
||||
*/
|
||||
async function isCommitInHistory(sha) {
|
||||
@@ -39,9 +39,9 @@ async function isCommitInHistory(sha) {
|
||||
*
|
||||
* @param {string} gitHead The commit sha to look for.
|
||||
* @param {string} version The version corresponding to the commit sha to look for. Used to search in git tags.
|
||||
*
|
||||
*
|
||||
* @return {Promise<string>} A Promise that resolves to the commit sha of the version, either `gitHead` of the commit associated with the `version` tag.
|
||||
*
|
||||
*
|
||||
* @throws {SemanticReleaseError} with code `ENOTINHISTORY` if `gitHead` or the commit sha dereived from `version` is not in the direct history of `branch`.
|
||||
* @throws {SemanticReleaseError} with code `ENOGITHEAD` if `gitHead` is undefined and no commit sha can be found for the `version`.
|
||||
*/
|
||||
|
||||
+8
-3
@@ -6,13 +6,18 @@ const chalk = require('chalk');
|
||||
module.exports = {
|
||||
log(...args) {
|
||||
const [format, ...rest] = args;
|
||||
console.log(`${chalk.grey('[Semantic release]:')} ${format}`, ...rest.map(arg => chalk.magenta(arg)));
|
||||
console.log(
|
||||
`${chalk.grey('[Semantic release]:')}${
|
||||
typeof format === 'string' ? ` ${format.replace(/%[^%]/g, seq => chalk.magenta(seq))}` : ''
|
||||
}`,
|
||||
...(typeof format === 'string' ? [] : [format]).concat(rest)
|
||||
);
|
||||
},
|
||||
error(...args) {
|
||||
const [format, ...rest] = args;
|
||||
console.error(
|
||||
`${chalk.grey('[Semantic release]:')} ${chalk.red(format instanceof Error ? format.stack : format)}`,
|
||||
...rest.map(arg => chalk.red(arg instanceof Error ? arg.stack : arg))
|
||||
`${chalk.grey('[Semantic release]:')}${typeof format === 'string' ? ` ${chalk.red(format)}` : ''}`,
|
||||
...(typeof format === 'string' ? [] : [format]).concat(rest)
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
Vendored
+3
-1
@@ -1,3 +1,5 @@
|
||||
module.exports = function(config, options, cb) {
|
||||
cb(new Error('a'));
|
||||
const error = new Error('a');
|
||||
error.errorProperty = 'errorProperty';
|
||||
cb(error);
|
||||
};
|
||||
|
||||
+14
@@ -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'));
|
||||
};
|
||||
@@ -42,14 +42,48 @@ test.serial('Get all commits when there is no last release', async t => {
|
||||
t.is(result.commits.length, 2);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.is(result.commits[0].message, commits[0].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
t.is(result.commits[1].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[1].message, commits[1].message);
|
||||
t.truthy(result.commits[1].committerDate);
|
||||
t.truthy(result.commits[1].author.name);
|
||||
t.truthy(result.commits[1].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.falsy(result.lastRelease.gitHead);
|
||||
t.falsy(result.lastRelease.version);
|
||||
});
|
||||
|
||||
test.serial('Get all commits with gitTags', async t => {
|
||||
// Create a git repository, set the current working directory at the root of the repo
|
||||
await gitRepo();
|
||||
// Add commits to the master branch
|
||||
let commits = await gitCommits(['First']);
|
||||
// Create the tag corresponding to version 1.0.0
|
||||
await gitTagVersion('v1.0.0');
|
||||
// Add new commits to the master branch
|
||||
commits = (await gitCommits(['Second'])).concat(commits);
|
||||
|
||||
// Retrieve the commits with the commits module
|
||||
const result = await t.context.getCommits({}, 'master');
|
||||
// Verify the commits created and retrieved by the module are identical
|
||||
t.is(result.commits.length, 2);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.is(result.commits[0].message, commits[0].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
t.is(result.commits[0].gitTags, '(HEAD -> master)');
|
||||
t.is(result.commits[1].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[1].message, commits[1].message);
|
||||
t.truthy(result.commits[1].committerDate);
|
||||
t.truthy(result.commits[1].author.name);
|
||||
t.truthy(result.commits[1].committer.name);
|
||||
t.is(result.commits[1].gitTags, '(tag: v1.0.0)');
|
||||
});
|
||||
|
||||
test.serial('Get all commits when there is no last release, including the ones not in the shallow clone', async t => {
|
||||
// Create a git repository, set the current working directory at the root of the repo
|
||||
const repo = await gitRepo();
|
||||
@@ -68,8 +102,14 @@ test.serial('Get all commits when there is no last release, including the ones n
|
||||
t.is(result.commits.length, 2);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.is(result.commits[0].message, commits[0].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
t.is(result.commits[1].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[1].message, commits[1].message);
|
||||
t.truthy(result.commits[1].committerDate);
|
||||
t.truthy(result.commits[1].author.name);
|
||||
t.truthy(result.commits[1].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.falsy(result.lastRelease.gitHead);
|
||||
@@ -89,8 +129,14 @@ test.serial('Get all commits since gitHead (from lastRelease)', async t => {
|
||||
t.is(result.commits.length, 2);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.is(result.commits[0].message, commits[0].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
t.is(result.commits[1].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[1].message, commits[1].message);
|
||||
t.truthy(result.commits[1].committerDate);
|
||||
t.truthy(result.commits[1].author.name);
|
||||
t.truthy(result.commits[1].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.is(result.lastRelease.gitHead, commits[commits.length - 1].hash);
|
||||
@@ -112,6 +158,9 @@ test.serial('Get all commits since gitHead (from lastRelease) on a detached head
|
||||
t.is(result.commits.length, 1);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[0].message, commits[1].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.is(result.lastRelease.gitHead, commits[commits.length - 1].hash);
|
||||
@@ -135,8 +184,14 @@ test.serial('Get all commits since gitHead (from tag) ', async t => {
|
||||
t.is(result.commits.length, 2);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.is(result.commits[0].message, commits[0].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
t.is(result.commits[1].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[1].message, commits[1].message);
|
||||
t.truthy(result.commits[1].committerDate);
|
||||
t.truthy(result.commits[1].author.name);
|
||||
t.truthy(result.commits[1].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.is(result.lastRelease.gitHead.substring(0, 7), commits[commits.length - 1].hash);
|
||||
@@ -162,6 +217,9 @@ test.serial('Get all commits since gitHead (from tag) on a detached head repo',
|
||||
t.is(result.commits.length, 1);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[0].message, commits[1].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.is(result.lastRelease.gitHead.substring(0, 7), commits[commits.length - 1].hash);
|
||||
@@ -185,8 +243,14 @@ test.serial('Get all commits since gitHead (from tag formatted like v<version>)
|
||||
t.is(result.commits.length, 2);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.is(result.commits[0].message, commits[0].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
t.is(result.commits[1].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[1].message, commits[1].message);
|
||||
t.truthy(result.commits[1].committerDate);
|
||||
t.truthy(result.commits[1].author.name);
|
||||
t.truthy(result.commits[1].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.is(result.lastRelease.gitHead.substring(0, 7), commits[commits.length - 1].hash);
|
||||
@@ -210,8 +274,14 @@ test.serial('Get commits when last release gitHead is missing but a tag match th
|
||||
t.is(result.commits.length, 2);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.is(result.commits[0].message, commits[0].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
t.is(result.commits[1].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[1].message, commits[1].message);
|
||||
t.truthy(result.commits[1].committerDate);
|
||||
t.truthy(result.commits[1].author.name);
|
||||
t.truthy(result.commits[1].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.is(result.lastRelease.gitHead.substring(0, 7), commits[commits.length - 1].hash);
|
||||
@@ -233,8 +303,14 @@ test.serial('Get all commits since gitHead, when gitHead are mising from the sha
|
||||
t.is(result.commits.length, 2);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.is(result.commits[0].message, commits[0].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
t.is(result.commits[1].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[1].message, commits[1].message);
|
||||
t.truthy(result.commits[1].committerDate);
|
||||
t.truthy(result.commits[1].author.name);
|
||||
t.truthy(result.commits[1].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.is(result.lastRelease.gitHead.substring(0, 7), commits[commits.length - 1].hash);
|
||||
@@ -263,8 +339,14 @@ test.serial('Get all commits since gitHead from tag, when tags are mising from t
|
||||
t.is(result.commits.length, 2);
|
||||
t.is(result.commits[0].hash.substring(0, 7), commits[0].hash);
|
||||
t.is(result.commits[0].message, commits[0].message);
|
||||
t.truthy(result.commits[0].committerDate);
|
||||
t.truthy(result.commits[0].author.name);
|
||||
t.truthy(result.commits[0].committer.name);
|
||||
t.is(result.commits[1].hash.substring(0, 7), commits[1].hash);
|
||||
t.is(result.commits[1].message, commits[1].message);
|
||||
t.truthy(result.commits[1].committerDate);
|
||||
t.truthy(result.commits[1].author.name);
|
||||
t.truthy(result.commits[1].committer.name);
|
||||
// Verify the last release is returned and updated
|
||||
t.truthy(result.lastRelease);
|
||||
t.is(result.lastRelease.gitHead.substring(0, 7), commits[commits.length - 1].hash);
|
||||
|
||||
+12
-12
@@ -5,7 +5,7 @@ import pMapSeries from 'p-map-series';
|
||||
|
||||
/**
|
||||
* Commit message informations.
|
||||
*
|
||||
*
|
||||
* @typedef {Object} Commit
|
||||
* @property {string} branch The commit branch.
|
||||
* @property {string} hash The commit hash.
|
||||
@@ -13,13 +13,13 @@ import pMapSeries from 'p-map-series';
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a temporary git repository and change the current working directory to the repository root.
|
||||
*
|
||||
* @method gitCommits
|
||||
* @param {Array<Commit>} commits the created commits.
|
||||
*
|
||||
* @return {string} The path of the repository.
|
||||
*/
|
||||
* Create a temporary git repository and change the current working directory to the repository root.
|
||||
*
|
||||
* @method gitCommits
|
||||
* @param {Array<Commit>} commits the created commits.
|
||||
*
|
||||
* @return {string} The path of the repository.
|
||||
*/
|
||||
export async function gitRepo() {
|
||||
const dir = tempy.directory();
|
||||
|
||||
@@ -34,7 +34,7 @@ export async function gitRepo() {
|
||||
* Create commits on the current git repository.
|
||||
*
|
||||
* @param {Array<string>} messages commit messages.
|
||||
*
|
||||
*
|
||||
* @returns {Array<Commit>} The created commits, in reverse order (to match `git log` order).
|
||||
*/
|
||||
export async function gitCommits(messages) {
|
||||
@@ -49,7 +49,7 @@ export async function gitCommits(messages) {
|
||||
* Amend a commit (rewriting the sha) on the current git repository.
|
||||
*
|
||||
* @param {string} messages commit message.
|
||||
*
|
||||
*
|
||||
* @returns {Array<Commit>} the created commits.
|
||||
*/
|
||||
export async function gitAmmendCommit(msg) {
|
||||
@@ -105,7 +105,7 @@ export async function gitLog() {
|
||||
/**
|
||||
* Create a shallow clone of a git repository and change the current working directory to the cloned repository root.
|
||||
* The shallow will contain a limited number of commit and no tags.
|
||||
*
|
||||
*
|
||||
* @param {string} origin The path of the repository to clone.
|
||||
* @param {number} [depth=1] The number of commit to clone.
|
||||
* @return {string} The path of the cloned repository.
|
||||
@@ -120,7 +120,7 @@ export async function gitShallowClone(origin, branch = 'master', depth = 1) {
|
||||
|
||||
/**
|
||||
* Create a git repo with a detached head from another git repository and change the current working directory to the new repository root.
|
||||
*
|
||||
*
|
||||
* @param {string} origin The path of the repository to clone.
|
||||
* @param {number} head A commit sha of the origin repo that will become the detached head of the new one.
|
||||
* @return {string} The path of the new repository.
|
||||
|
||||
@@ -2,7 +2,7 @@ import nock from 'nock';
|
||||
|
||||
/**
|
||||
* Retun a `nock` object setup to respond to a github authentication request. Other expectation and responses can be chained.
|
||||
*
|
||||
*
|
||||
* @param {String} [githubToken='GH_TOKEN'] The github token to return in the authentication response.
|
||||
* @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.
|
||||
|
||||
@@ -47,7 +47,7 @@ const url = `http://${MOCK_SERVER_HOST}:${MOCK_SERVER_PORT}`;
|
||||
* @param {Object} request Request expectation. The http request made on `path` has to match those criteria in order to be valid.
|
||||
* @param {Object} request.body The JSON body the expected request must match.
|
||||
* @param {Object} request.headers The headers the expected request must match.
|
||||
* @param {Object} response The http response to return when receiving a request on `path`.
|
||||
* @param {Object} response The http response to return when receiving a request on `path`.
|
||||
* @param {String} [response.method='POST'] The http method for which to respond.
|
||||
* @param {number} [response.statusCode=200] The status code to respond.
|
||||
* @param {Object} response.body The JSON object to respond in the response body.
|
||||
|
||||
@@ -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();
|
||||
@@ -35,7 +36,6 @@ test.beforeEach(async t => {
|
||||
});
|
||||
|
||||
test.afterEach.always(async t => {
|
||||
console.log();
|
||||
// Restore process.env
|
||||
process.env = Object.assign({}, t.context.env);
|
||||
// Restore the current working directory
|
||||
@@ -408,7 +408,9 @@ 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`
|
||||
)
|
||||
);
|
||||
|
||||
@@ -574,7 +576,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 +617,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
|
||||
@@ -634,11 +636,39 @@ test.serial('Log unexpected errors from plugins', async t => {
|
||||
await gitCommits(['feat: Initial commit']);
|
||||
t.log('$ semantic-release');
|
||||
let {stderr, code} = await execa(cli, [], {env, reject: false});
|
||||
// Verify the type and message are logged
|
||||
t.regex(stderr, /Error: a/);
|
||||
// Verify the the stacktrace is logged
|
||||
t.regex(stderr, new RegExp(pluginError));
|
||||
// Verify the Error properties are logged
|
||||
t.regex(stderr, /errorProperty: 'errorProperty'/);
|
||||
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});
|
||||
|
||||
+19
-8
@@ -1,5 +1,5 @@
|
||||
import test from 'ava';
|
||||
import {stub} from 'sinon';
|
||||
import {stub, match} from 'sinon';
|
||||
import logger from '../src/lib/logger';
|
||||
|
||||
test.beforeEach(t => {
|
||||
@@ -20,18 +20,29 @@ test.serial('Basic log', t => {
|
||||
t.true(t.context.error.calledWithMatch(/.*test error/));
|
||||
});
|
||||
|
||||
test.serial('Log object', t => {
|
||||
const obj = {a: 1, b: '2'};
|
||||
logger.log(obj);
|
||||
logger.error(obj);
|
||||
|
||||
t.true(t.context.log.calledWithMatch(match.string, obj));
|
||||
t.true(t.context.error.calledWithMatch(match.string, 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 %s/, 'log value'));
|
||||
t.true(t.context.error.calledWithMatch(/.*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'));
|
||||
});
|
||||
|
||||
test.serial('Log with error stacktrace', t => {
|
||||
logger.error(new Error('error message'));
|
||||
logger.error('test error %s', new Error('other error message'));
|
||||
test.serial('Log with error stacktrace and properties', t => {
|
||||
const error = new Error('error message');
|
||||
logger.error(error);
|
||||
const otherError = new Error('other error message');
|
||||
logger.error('test error %O', otherError);
|
||||
|
||||
t.true(t.context.error.calledWithMatch(/.*test error %s/, /Error: other error message(\s|.)*?logger\.test\.js/));
|
||||
t.true(t.context.error.calledWithMatch(/Error: error message(\s|.)*?logger\.test\.js/));
|
||||
t.true(t.context.error.calledWithMatch(match.string, error));
|
||||
t.true(t.context.error.calledWithMatch(/.*test error/, otherError));
|
||||
});
|
||||
|
||||
@@ -2,12 +2,12 @@ import test from 'ava';
|
||||
import SemanticReleaseError from '@semantic-release/error';
|
||||
import verify from '../src/lib/verify-pkg';
|
||||
|
||||
test.only('Verify name and repository', t => {
|
||||
test('Verify name and repository', t => {
|
||||
// Call the verify module with package
|
||||
t.notThrows(() => verify({name: 'package', repository: {url: 'http://github.com/whats/up.git'}}));
|
||||
});
|
||||
|
||||
test.only('Return error for missing package name', t => {
|
||||
test('Return error for missing package name', t => {
|
||||
// Call the verify module with package
|
||||
const error = t.throws(() => verify({repository: {url: 'http://github.com/whats/up.git'}}));
|
||||
// Verify error code and type
|
||||
@@ -15,7 +15,7 @@ test.only('Return error for missing package name', t => {
|
||||
t.true(error instanceof SemanticReleaseError);
|
||||
});
|
||||
|
||||
test.only('Return error for missing repository', t => {
|
||||
test('Return error for missing repository', t => {
|
||||
// Call the verify module with package
|
||||
const error = t.throws(() => verify({name: 'package'}));
|
||||
// Verify error code and type
|
||||
@@ -23,7 +23,7 @@ test.only('Return error for missing repository', t => {
|
||||
t.true(error instanceof SemanticReleaseError);
|
||||
});
|
||||
|
||||
test.only('Return error for missing repository url', t => {
|
||||
test('Return error for missing repository url', t => {
|
||||
// Call the verify module with package
|
||||
const error = t.throws(() => verify({name: 'package', repository: {}}));
|
||||
// Verify error code and type
|
||||
|
||||
Reference in New Issue
Block a user