feat: add the prepare plugin hook

BREAKING CHANGE: Committing or creating files in the `publish` plugin hook is not supported anymore and now must be done in the `prepare` hook

Plugins with a `publish` hook that makes a commit or create a file that can be committed must use the `prepare` hook.
This commit is contained in:
Pierre Vanduynslager 2018-02-12 17:14:24 -05:00
parent 20246c02b1
commit c2beb643fa
14 changed files with 104 additions and 61 deletions

View File

@ -86,6 +86,7 @@ After running the tests the command `semantic-release` will execute the followin
| Verify release | Verify the release conformity with the [verify release plugins](docs/usage/plugins.md#verifyrelease-plugin). | | Verify release | Verify the release conformity with the [verify release plugins](docs/usage/plugins.md#verifyrelease-plugin). |
| Generate notes | Generate release notes with the [generate notes plugin](docs/usage/plugins.md#generatenotes-plugin) for the commits added since the last release. | | Generate notes | Generate release notes with the [generate notes plugin](docs/usage/plugins.md#generatenotes-plugin) for the commits added since the last release. |
| Create Git tag | Create a Git tag corresponding the new release version | | Create Git tag | Create a Git tag corresponding the new release version |
| Prepare | Prepare the release with the [prepare plugins](docs/usage/plugins.md#prepare-plugin). |
| Publish | Publish the release with the [publish plugins](docs/usage/plugins.md#publish-plugin). | | Publish | Publish the release with the [publish plugins](docs/usage/plugins.md#publish-plugin). |
| Notify | Notify of new releases or errors with the [success](docs/usage/plugins.md#success-plugin) and [fail](docs/usage/plugins.md#fail-plugin) plugins. | | Notify | Notify of new releases or errors with the [success](docs/usage/plugins.md#success-plugin) and [fail](docs/usage/plugins.md#fail-plugin) plugins. |

1
cli.js
View File

@ -25,6 +25,7 @@ Usage:
.option('analyze-commits', {type: 'string', group: 'Plugins'}) .option('analyze-commits', {type: 'string', group: 'Plugins'})
.option('verify-release', {...stringList, group: 'Plugins'}) .option('verify-release', {...stringList, group: 'Plugins'})
.option('generate-notes', {type: 'string', group: 'Plugins'}) .option('generate-notes', {type: 'string', group: 'Plugins'})
.option('prepare', {...stringList, group: 'Plugins'})
.option('publish', {...stringList, group: 'Plugins'}) .option('publish', {...stringList, group: 'Plugins'})
.option('success', {...stringList, group: 'Plugins'}) .option('success', {...stringList, group: 'Plugins'})
.option('fail', {...stringList, group: 'Plugins'}) .option('fail', {...stringList, group: 'Plugins'})

View File

@ -9,6 +9,7 @@
- [fail](https://github.com/semantic-release/github#fail): Open a GitHub issue when a release fails - [fail](https://github.com/semantic-release/github#fail): Open a GitHub issue when a release fails
- [@semantic-release/npm](https://github.com/semantic-release/npm) - [@semantic-release/npm](https://github.com/semantic-release/npm)
- [verifyConditions](https://github.com/semantic-release/npm#verifyconditions): Verify the presence and the validity of the npm authentication and release configuration - [verifyConditions](https://github.com/semantic-release/npm#verifyconditions): Verify the presence and the validity of the npm authentication and release configuration
- [prepare](https://github.com/semantic-release/npm#prepare): Update the package.json version and create the npm package tarball
- [publish](https://github.com/semantic-release/npm#publish): Publish the package on the npm registry - [publish](https://github.com/semantic-release/npm#publish): Publish the package on the npm registry
## Official plugins ## Official plugins
@ -18,15 +19,16 @@
- [publish](https://github.com/semantic-release/gitlab#publish): Publish a [GitLab release](https://docs.gitlab.com/ce/workflow/releases.html) - [publish](https://github.com/semantic-release/gitlab#publish): Publish a [GitLab release](https://docs.gitlab.com/ce/workflow/releases.html)
- [@semantic-release/git](https://github.com/semantic-release/git) - [@semantic-release/git](https://github.com/semantic-release/git)
- [verifyConditions](https://github.com/semantic-release/git#verifyconditions): Verify the presence and the validity of the Git authentication and release configuration - [verifyConditions](https://github.com/semantic-release/git#verifyconditions): Verify the presence and the validity of the Git authentication and release configuration
- [publish](https://github.com/semantic-release/git#publish): Push a release commit and tag, including configurable files - [prepare](https://github.com/semantic-release/git#prepare): Push a release commit and tag, including configurable files
- [@semantic-release/changelog](https://github.com/semantic-release/changelog) - [@semantic-release/changelog](https://github.com/semantic-release/changelog)
- [verifyConditions](https://github.com/semantic-release/changelog#verifyconditions): Verify the presence and the validity of the configuration - [verifyConditions](https://github.com/semantic-release/changelog#verifyconditions): Verify the presence and the validity of the configuration
- [publish](https://github.com/semantic-release/changelog#publish): Create or update the changelog file in the local project repository - [prepare](https://github.com/semantic-release/changelog#prepare): Create or update the changelog file in the local project repository
- [@semantic-release/exec](https://github.com/semantic-release/exec) - [@semantic-release/exec](https://github.com/semantic-release/exec)
- [verifyConditions](https://github.com/semantic-release/exec#verifyconditions): Execute a shell command to verify if the release should happen - [verifyConditions](https://github.com/semantic-release/exec#verifyconditions): Execute a shell command to verify if the release should happen
- [analyzeCommits](https://github.com/semantic-release/exec#analyzecommits): Execute a shell command to determine the type of release - [analyzeCommits](https://github.com/semantic-release/exec#analyzecommits): Execute a shell command to determine the type of release
- [verifyRelease](https://github.com/semantic-release/exec#verifyrelease): Execute a shell command to verifying a release that was determined before and is about to be published. - [verifyRelease](https://github.com/semantic-release/exec#verifyrelease): Execute a shell command to verifying a release that was determined before and is about to be published.
- [generateNotes](https://github.com/semantic-release/exec#analyzecommits): Execute a shell command to generate the release note - [generateNotes](https://github.com/semantic-release/exec#analyzecommits): Execute a shell command to generate the release note
- [prepare](https://github.com/semantic-release/exec#prepare): Execute a shell command to prepare the release
- [publish](https://github.com/semantic-release/exec#publish): Execute a shell command to publish the release - [publish](https://github.com/semantic-release/exec#publish): Execute a shell command to publish the release
- [success](https://github.com/semantic-release/exec#success): Execute a shell command to notify of a new release - [success](https://github.com/semantic-release/exec#success): Execute a shell command to notify of a new release
- [fail](https://github.com/semantic-release/exec#fail): Execute a shell command to notify of a failed release - [fail](https://github.com/semantic-release/exec#fail): Execute a shell command to notify of a failed release

View File

@ -155,6 +155,18 @@ Define the [generate notes plugin](plugins.md#generatenotes-plugin).
See [Plugins configuration](plugins.md#configuration) for more details. See [Plugins configuration](plugins.md#configuration) for more details.
### prepare
Type: `Array`, `String`, `Object`
Default: `['@semantic-release/npm']`
CLI argument: `--prepare`
Define the list of [prepare plugins](plugins.md#prepare-plugin). Plugins will run in series, in the order defined in the `Array`.
See [Plugins configuration](plugins.md#configuration) for more details.
### publish ### publish
Type: `Array`, `String`, `Object` Type: `Array`, `String`, `Object`

View File

@ -28,6 +28,14 @@ Plugin responsible for generating release notes.
Default implementation: [@semantic-release/release-notes-generator](https://github.com/semantic-release/release-notes-generator). Default implementation: [@semantic-release/release-notes-generator](https://github.com/semantic-release/release-notes-generator).
### prepare plugin
Plugin responsible for preparing the release, including:
- Creating or updating files such as `package.json`, `CHANGELOG.md`, documentation or compiled assets.
- Create and push commits
Default implementation: [npm](https://github.com/semantic-release/npm#prepare).
### publish plugin ### publish plugin
Plugin responsible for publishing the release. Plugin responsible for publishing the release.

View File

@ -12,7 +12,7 @@ const getCommits = require('./lib/get-commits');
const getLastRelease = require('./lib/get-last-release'); const getLastRelease = require('./lib/get-last-release');
const {extractErrors} = require('./lib/utils'); const {extractErrors} = require('./lib/utils');
const logger = require('./lib/logger'); const logger = require('./lib/logger');
const {unshallow, gitHead: getGitHead, tag, push, deleteTag} = require('./lib/git'); const {unshallow, gitHead: getGitHead, tag, push} = require('./lib/git');
marked.setOptions({renderer: new TerminalRenderer()}); marked.setOptions({renderer: new TerminalRenderer()});
@ -41,7 +41,7 @@ async function run(options, plugins) {
await verify(options); await verify(options);
logger.log('Run automated release from branch %s', options.branch); logger.log('Run automated release from branch %s', options.branch);
console.log(options);
logger.log('Call plugin %s', 'verify-conditions'); logger.log('Call plugin %s', 'verify-conditions');
await plugins.verifyConditions({options, logger}, {settleAll: true}); await plugins.verifyConditions({options, logger}, {settleAll: true});
@ -79,26 +79,14 @@ async function run(options, plugins) {
logger.log('Call plugin %s', 'generateNotes'); logger.log('Call plugin %s', 'generateNotes');
nextRelease.notes = await plugins.generateNotes(generateNotesParam); nextRelease.notes = await plugins.generateNotes(generateNotesParam);
// Create the tag before calling the publish plugins as some require the tag to exists logger.log('Call plugin %s', 'prepare');
logger.log('Create tag %s', nextRelease.gitTag); await plugins.prepare(
await tag(nextRelease.gitTag);
await push(options.repositoryUrl, branch);
logger.log('Call plugin %s', 'publish');
const releases = await plugins.publish(
{options, logger, lastRelease, commits, nextRelease}, {options, logger, lastRelease, commits, nextRelease},
{ {
getNextInput: async lastResult => { getNextInput: async lastResult => {
const newGitHead = await getGitHead(); const newGitHead = await getGitHead();
// If previous publish plugin has created a commit (gitHead changed) // If previous prepare plugin has created a commit (gitHead changed)
if (lastResult.nextRelease.gitHead !== newGitHead) { if (lastResult.nextRelease.gitHead !== newGitHead) {
// Delete the previously created tag
await deleteTag(options.repositoryUrl, nextRelease.gitTag);
// Recreate the tag, referencing the new gitHead
logger.log('Create tag %s', nextRelease.gitTag);
await tag(nextRelease.gitTag);
await push(options.repositoryUrl, branch);
nextRelease.gitHead = newGitHead; nextRelease.gitHead = newGitHead;
// Regenerate the release notes // Regenerate the release notes
logger.log('Call plugin %s', 'generateNotes'); logger.log('Call plugin %s', 'generateNotes');
@ -107,11 +95,21 @@ async function run(options, plugins) {
// Call the next publish plugin with the updated `nextRelease` // Call the next publish plugin with the updated `nextRelease`
return {options, logger, lastRelease, commits, nextRelease}; return {options, logger, lastRelease, commits, nextRelease};
}, },
// Add nextRelease and plugin properties to published release
transform: (release, step) => ({...(isPlainObject(release) ? release : {}), ...nextRelease, ...step}),
} }
); );
// Create the tag before calling the publish plugins as some require the tag to exists
logger.log('Create tag %s', nextRelease.gitTag);
await tag(nextRelease.gitTag);
await push(options.repositoryUrl, branch);
logger.log('Call plugin %s', 'publish');
const releases = await plugins.publish(
{options, logger, lastRelease, commits, nextRelease},
// Add nextRelease and plugin properties to published release
{transform: (release, step) => ({...(isPlainObject(release) ? release : {}), ...nextRelease, ...step})}
);
await plugins.success( await plugins.success(
{options, logger, lastRelease, commits, nextRelease, releases: castArray(releases)}, {options, logger, lastRelease, commits, nextRelease, releases: castArray(releases)},
{settleAll: true} {settleAll: true}

View File

@ -36,6 +36,12 @@ module.exports = {
error: 'ERELEASENOTESOUTPUT', error: 'ERELEASENOTESOUTPUT',
}, },
}, },
prepare: {
default: ['@semantic-release/npm'],
config: {
validator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)),
},
},
publish: { publish: {
default: ['@semantic-release/npm', '@semantic-release/github'], default: ['@semantic-release/npm', '@semantic-release/github'],
config: { config: {

View File

@ -115,22 +115,6 @@ async function push(origin, branch) {
await execa('git', ['push', '--tags', origin, `HEAD:${branch}`]); await execa('git', ['push', '--tags', origin, `HEAD:${branch}`]);
} }
/**
* Delete a tag locally and remotely.
*
* @param {String} origin The remote repository URL.
* @param {String} tagName The tag name to delete.
*/
async function deleteTag(origin, tagName) {
// Delete the local tag
let shell = await execa('git', ['tag', '-d', tagName], {reject: false});
debug('delete local tag', shell);
// Delete the tag remotely
shell = await execa('git', ['push', '--delete', origin, tagName], {reject: false});
debug('delete remote tag', shell);
}
/** /**
* Verify a tag name is a valid Git reference. * Verify a tag name is a valid Git reference.
* *
@ -157,6 +141,5 @@ module.exports = {
verifyAuth, verifyAuth,
tag, tag,
push, push,
deleteTag,
verifyTagName, verifyTagName,
}; };

View File

@ -22,7 +22,7 @@
"@semantic-release/commit-analyzer": "^5.0.0", "@semantic-release/commit-analyzer": "^5.0.0",
"@semantic-release/error": "^2.2.0", "@semantic-release/error": "^2.2.0",
"@semantic-release/github": "^4.1.0", "@semantic-release/github": "^4.1.0",
"@semantic-release/npm": "^3.1.0", "@semantic-release/npm": "^3.2.0",
"@semantic-release/release-notes-generator": "^6.0.0", "@semantic-release/release-notes-generator": "^6.0.0",
"aggregate-error": "^1.0.0", "aggregate-error": "^1.0.0",
"chalk": "^2.3.0", "chalk": "^2.3.0",

View File

@ -53,6 +53,9 @@ test.serial('Pass options to semantic-release API', async t => {
'verify2', 'verify2',
'--generate-notes', '--generate-notes',
'notes', 'notes',
'--prepare',
'prepare1',
'prepare2',
'--publish', '--publish',
'publish1', 'publish1',
'publish2', 'publish2',
@ -76,6 +79,7 @@ test.serial('Pass options to semantic-release API', async t => {
t.is(run.args[0][0].analyzeCommits, 'analyze'); t.is(run.args[0][0].analyzeCommits, 'analyze');
t.deepEqual(run.args[0][0].verifyRelease, ['verify1', 'verify2']); t.deepEqual(run.args[0][0].verifyRelease, ['verify1', 'verify2']);
t.is(run.args[0][0].generateNotes, 'notes'); t.is(run.args[0][0].generateNotes, 'notes');
t.deepEqual(run.args[0][0].prepare, ['prepare1', 'prepare2']);
t.deepEqual(run.args[0][0].publish, ['publish1', 'publish2']); t.deepEqual(run.args[0][0].publish, ['publish1', 'publish2']);
t.deepEqual(run.args[0][0].success, ['success1', 'success2']); t.deepEqual(run.args[0][0].success, ['success1', 'success2']);
t.deepEqual(run.args[0][0].fail, ['fail1', 'fail2']); t.deepEqual(run.args[0][0].fail, ['fail1', 'fail2']);

View File

@ -46,6 +46,17 @@ test('The "generateNotes" plugin, if defined, must be a single plugin definition
t.true(plugins.generateNotes.config.validator(() => {})); t.true(plugins.generateNotes.config.validator(() => {}));
}); });
test('The "prepare" plugin, if defined, must be a single or an array of plugins definition', t => {
t.false(plugins.verifyRelease.config.validator({}));
t.false(plugins.verifyRelease.config.validator({path: null}));
t.true(plugins.verifyRelease.config.validator({path: 'plugin-path.js'}));
t.true(plugins.verifyRelease.config.validator());
t.true(plugins.verifyRelease.config.validator('plugin-path.js'));
t.true(plugins.verifyRelease.config.validator(() => {}));
t.true(plugins.verifyRelease.config.validator([{path: 'plugin-path.js'}, 'plugin-path.js', () => {}]));
});
test('The "publish" plugin is mandatory, and must be a single or an array of plugins definition', t => { test('The "publish" plugin is mandatory, and must be a single or an array of plugins definition', t => {
t.false(plugins.publish.config.validator({})); t.false(plugins.publish.config.validator({}));
t.false(plugins.publish.config.validator({path: null})); t.false(plugins.publish.config.validator({path: null}));

View File

@ -10,7 +10,6 @@ import {
push, push,
gitTags, gitTags,
isGitRepo, isGitRepo,
deleteTag,
verifyTagName, verifyTagName,
} from '../lib/git'; } from '../lib/git';
import { import {
@ -139,18 +138,6 @@ test.serial('Add tag on head commit', async t => {
await t.is(await gitCommitTag(commits[0].hash), 'tag_name'); await t.is(await gitCommitTag(commits[0].hash), 'tag_name');
}); });
test.serial('Delete a tag', async t => {
// Create a git repository with a remote, set the current working directory at the root of the repo
const repo = await gitRepo(true);
await gitCommits(['Test commit']);
await tag('tag_name');
await push(repo, 'master');
await deleteTag(repo, 'tag_name');
t.falsy(await gitTagHead('tag_name'));
t.falsy(await gitRemoteTagHead(repo, 'tag_name'));
});
test.serial('Push tag and commit to remote repository', async t => { test.serial('Push tag and commit to remote repository', async t => {
// Create a git repository with a remote, set the current working directory at the root of the repo // Create a git repository with a remote, set the current working directory at the root of the repo
const repo = await gitRepo(true); const repo = await gitRepo(true);

View File

@ -67,6 +67,7 @@ test.serial('Plugins are called with expected values', async t => {
const verifyRelease = stub().resolves(); const verifyRelease = stub().resolves();
const generateNotes = stub().resolves(notes); const generateNotes = stub().resolves(notes);
const release1 = {name: 'Release 1', url: 'https://release1.com'}; const release1 = {name: 'Release 1', url: 'https://release1.com'};
const prepare = stub().resolves();
const publish1 = stub().resolves(release1); const publish1 = stub().resolves(release1);
const success = stub().resolves(); const success = stub().resolves();
@ -77,6 +78,7 @@ test.serial('Plugins are called with expected values', async t => {
analyzeCommits, analyzeCommits,
verifyRelease, verifyRelease,
generateNotes, generateNotes,
prepare,
publish: [publish1, pluginNoop], publish: [publish1, pluginNoop],
success, success,
}; };
@ -119,6 +121,15 @@ test.serial('Plugins are called with expected values', async t => {
t.deepEqual(generateNotes.args[0][1].commits[0].message, commits[0].message); t.deepEqual(generateNotes.args[0][1].commits[0].message, commits[0].message);
t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease); t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease);
t.is(prepare.callCount, 1);
t.deepEqual(prepare.args[0][0], config);
t.deepEqual(prepare.args[0][1].options, options);
t.deepEqual(prepare.args[0][1].logger, t.context.logger);
t.deepEqual(prepare.args[0][1].lastRelease, lastRelease);
t.deepEqual(prepare.args[0][1].commits[0].hash, commits[0].hash);
t.deepEqual(prepare.args[0][1].commits[0].message, commits[0].message);
t.deepEqual(prepare.args[0][1].nextRelease, {...nextRelease, ...{notes}});
t.is(publish1.callCount, 1); t.is(publish1.callCount, 1);
t.deepEqual(publish1.args[0][0], config); t.deepEqual(publish1.args[0][0], config);
t.deepEqual(publish1.args[0][1].options, options); t.deepEqual(publish1.args[0][1].options, options);
@ -161,6 +172,7 @@ test.serial('Use custom tag format', async t => {
analyzeCommits: stub().resolves(nextRelease.type), analyzeCommits: stub().resolves(nextRelease.type),
verifyRelease: stub().resolves(), verifyRelease: stub().resolves(),
generateNotes: stub().resolves(notes), generateNotes: stub().resolves(notes),
prepare: stub().resolves(),
publish: stub().resolves(), publish: stub().resolves(),
success: stub().resolves(), success: stub().resolves(),
fail: stub().resolves(), fail: stub().resolves(),
@ -177,7 +189,7 @@ test.serial('Use custom tag format', async t => {
t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag), nextRelease.gitHead); t.is(await gitRemoteTagHead(repositoryUrl, nextRelease.gitTag), nextRelease.gitHead);
}); });
test.serial('Use new gitHead, and recreate release notes if a publish plugin create a commit', async t => { test.serial('Use new gitHead, and recreate release notes if a prepare plugin create a commit', async t => {
// Create a git repository, set the current working directory at the root of the repo // Create a git repository, set the current working directory at the root of the repo
const repositoryUrl = await gitRepo(true); const repositoryUrl = await gitRepo(true);
// Add commits to the master branch // Add commits to the master branch
@ -191,10 +203,11 @@ test.serial('Use new gitHead, and recreate release notes if a publish plugin cre
const notes = 'Release notes'; const notes = 'Release notes';
const generateNotes = stub().resolves(notes); const generateNotes = stub().resolves(notes);
const publish1 = stub().callsFake(async () => { const prepare1 = stub().callsFake(async () => {
commits = (await gitCommits(['Third'])).concat(commits); commits = (await gitCommits(['Third'])).concat(commits);
}); });
const publish2 = stub().resolves(); const prepare2 = stub().resolves();
const publish = stub().resolves();
const options = { const options = {
branch: 'master', branch: 'master',
@ -203,7 +216,8 @@ test.serial('Use new gitHead, and recreate release notes if a publish plugin cre
analyzeCommits: stub().resolves(nextRelease.type), analyzeCommits: stub().resolves(nextRelease.type),
verifyRelease: stub().resolves(), verifyRelease: stub().resolves(),
generateNotes, generateNotes,
publish: [publish1, publish2], prepare: [prepare1, prepare2],
publish,
success: stub().resolves(), success: stub().resolves(),
fail: stub().resolves(), fail: stub().resolves(),
}; };
@ -217,14 +231,17 @@ test.serial('Use new gitHead, and recreate release notes if a publish plugin cre
t.is(generateNotes.callCount, 2); t.is(generateNotes.callCount, 2);
t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease); t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease);
t.is(publish1.callCount, 1); t.is(prepare1.callCount, 1);
t.deepEqual(publish1.args[0][1].nextRelease, {...nextRelease, ...{notes}}); t.deepEqual(prepare1.args[0][1].nextRelease, {...nextRelease, ...{notes}});
nextRelease.gitHead = await getGitHead(); nextRelease.gitHead = await getGitHead();
t.deepEqual(generateNotes.secondCall.args[1].nextRelease, {...nextRelease, ...{notes}}); t.deepEqual(generateNotes.args[1][1].nextRelease, {...nextRelease, ...{notes}});
t.is(publish2.callCount, 1); t.is(prepare2.callCount, 1);
t.deepEqual(publish2.args[0][1].nextRelease, {...nextRelease, ...{notes}}); t.deepEqual(prepare2.args[0][1].nextRelease, {...nextRelease, ...{notes}});
t.is(publish.callCount, 1);
t.deepEqual(publish.args[0][1].nextRelease, {...nextRelease, ...{notes}});
// Verify the tag has been created on the local and remote repo and reference the last gitHead // Verify the tag has been created on the local and remote repo and reference the last gitHead
t.is(await gitTagHead(nextRelease.gitTag), commits[0].hash); t.is(await gitTagHead(nextRelease.gitTag), commits[0].hash);
@ -258,6 +275,7 @@ test.serial('Call all "success" plugins even if one errors out', async t => {
verifyConditions: [verifyConditions1, verifyConditions2], verifyConditions: [verifyConditions1, verifyConditions2],
analyzeCommits, analyzeCommits,
generateNotes, generateNotes,
prepare: stub().resolves(),
publish, publish,
success: [success1, success2], success: [success1, success2],
}; };
@ -383,6 +401,7 @@ test.serial('Dry-run skips publish and success', async t => {
analyzeCommits, analyzeCommits,
verifyRelease, verifyRelease,
generateNotes, generateNotes,
prepare: stub().resolves(),
publish, publish,
success, success,
}; };
@ -464,6 +483,7 @@ test.serial('Force a dry-run if not on a CI and "noCi" is not explicitly set', a
analyzeCommits, analyzeCommits,
verifyRelease, verifyRelease,
generateNotes, generateNotes,
prepare: stub().resolves(),
publish, publish,
success, success,
fail: stub().resolves(), fail: stub().resolves(),
@ -512,6 +532,7 @@ test.serial('Allow local releases with "noCi" option', async t => {
analyzeCommits, analyzeCommits,
verifyRelease, verifyRelease,
generateNotes, generateNotes,
prepare: stub().resolves(),
publish, publish,
success, success,
fail: stub().resolves(), fail: stub().resolves(),
@ -560,6 +581,7 @@ test.serial('Accept "undefined" value returned by the "generateNotes" plugins',
analyzeCommits, analyzeCommits,
verifyRelease, verifyRelease,
generateNotes, generateNotes,
prepare: stub().resolves(),
publish, publish,
success: stub().resolves(), success: stub().resolves(),
fail: stub().resolves(), fail: stub().resolves(),
@ -611,6 +633,7 @@ test.serial('Returns falsy value if not running from the configured branch', asy
analyzeCommits: stub().resolves(), analyzeCommits: stub().resolves(),
verifyRelease: stub().resolves(), verifyRelease: stub().resolves(),
generateNotes: stub().resolves(), generateNotes: stub().resolves(),
prepare: stub().resolves(),
publish: stub().resolves(), publish: stub().resolves(),
success: stub().resolves(), success: stub().resolves(),
fail: stub().resolves(), fail: stub().resolves(),
@ -646,6 +669,7 @@ test.serial('Returns falsy value if there is no relevant changes', async t => {
analyzeCommits, analyzeCommits,
verifyRelease, verifyRelease,
generateNotes, generateNotes,
prepare: stub().resolves(),
publish, publish,
success: stub().resolves(), success: stub().resolves(),
fail: stub().resolves(), fail: stub().resolves(),
@ -686,6 +710,7 @@ test.serial('Exclude commits with [skip release] or [release skip] from analysis
analyzeCommits, analyzeCommits,
verifyRelease: stub().resolves(), verifyRelease: stub().resolves(),
generateNotes: stub().resolves(), generateNotes: stub().resolves(),
prepare: stub().resolves(),
publish: stub().resolves(), publish: stub().resolves(),
success: stub().resolves(), success: stub().resolves(),
fail: stub().resolves(), fail: stub().resolves(),
@ -844,6 +869,7 @@ test.serial('Get all commits including the ones not in the shallow clone', async
analyzeCommits, analyzeCommits,
verifyRelease: stub().resolves(), verifyRelease: stub().resolves(),
generateNotes: stub().resolves(notes), generateNotes: stub().resolves(notes),
prepare: stub().resolves(),
publish: stub().resolves(), publish: stub().resolves(),
success: stub().resolves(), success: stub().resolves(),
fail: stub().resolves(), fail: stub().resolves(),

View File

@ -27,6 +27,7 @@ test('Export default plugins', t => {
t.is(typeof plugins.analyzeCommits, 'function'); t.is(typeof plugins.analyzeCommits, 'function');
t.is(typeof plugins.verifyRelease, 'function'); t.is(typeof plugins.verifyRelease, 'function');
t.is(typeof plugins.generateNotes, 'function'); t.is(typeof plugins.generateNotes, 'function');
t.is(typeof plugins.prepare, 'function');
t.is(typeof plugins.publish, 'function'); t.is(typeof plugins.publish, 'function');
t.is(typeof plugins.success, 'function'); t.is(typeof plugins.success, 'function');
t.is(typeof plugins.fail, 'function'); t.is(typeof plugins.fail, 'function');
@ -49,6 +50,7 @@ test('Export plugins based on config', t => {
t.is(typeof plugins.analyzeCommits, 'function'); t.is(typeof plugins.analyzeCommits, 'function');
t.is(typeof plugins.verifyRelease, 'function'); t.is(typeof plugins.verifyRelease, 'function');
t.is(typeof plugins.generateNotes, 'function'); t.is(typeof plugins.generateNotes, 'function');
t.is(typeof plugins.prepare, 'function');
t.is(typeof plugins.publish, 'function'); t.is(typeof plugins.publish, 'function');
t.is(typeof plugins.success, 'function'); t.is(typeof plugins.success, 'function');
t.is(typeof plugins.fail, 'function'); t.is(typeof plugins.fail, 'function');
@ -79,6 +81,7 @@ test.serial('Export plugins loaded from the dependency of a shareable config mod
t.is(typeof plugins.analyzeCommits, 'function'); t.is(typeof plugins.analyzeCommits, 'function');
t.is(typeof plugins.verifyRelease, 'function'); t.is(typeof plugins.verifyRelease, 'function');
t.is(typeof plugins.generateNotes, 'function'); t.is(typeof plugins.generateNotes, 'function');
t.is(typeof plugins.prepare, 'function');
t.is(typeof plugins.publish, 'function'); t.is(typeof plugins.publish, 'function');
t.is(typeof plugins.success, 'function'); t.is(typeof plugins.success, 'function');
t.is(typeof plugins.fail, 'function'); t.is(typeof plugins.fail, 'function');
@ -106,6 +109,7 @@ test.serial('Export plugins loaded from the dependency of a shareable config fil
t.is(typeof plugins.analyzeCommits, 'function'); t.is(typeof plugins.analyzeCommits, 'function');
t.is(typeof plugins.verifyRelease, 'function'); t.is(typeof plugins.verifyRelease, 'function');
t.is(typeof plugins.generateNotes, 'function'); t.is(typeof plugins.generateNotes, 'function');
t.is(typeof plugins.prepare, 'function');
t.is(typeof plugins.publish, 'function'); t.is(typeof plugins.publish, 'function');
t.is(typeof plugins.success, 'function'); t.is(typeof plugins.success, 'function');
t.is(typeof plugins.fail, 'function'); t.is(typeof plugins.fail, 'function');