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:
		
							parent
							
								
									20246c02b1
								
							
						
					
					
						commit
						c2beb643fa
					
				| @ -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
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								cli.js
									
									
									
									
									
								
							| @ -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'}) | ||||||
|  | |||||||
| @ -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 | ||||||
|  | |||||||
| @ -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` | ||||||
|  | |||||||
| @ -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. | ||||||
|  | |||||||
							
								
								
									
										36
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								index.js
									
									
									
									
									
								
							| @ -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} | ||||||
|  | |||||||
| @ -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: { | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								lib/git.js
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								lib/git.js
									
									
									
									
									
								
							| @ -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, | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -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", | ||||||
|  | |||||||
| @ -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']); | ||||||
|  | |||||||
| @ -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})); | ||||||
|  | |||||||
| @ -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); | ||||||
|  | |||||||
| @ -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(), | ||||||
|  | |||||||
| @ -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'); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user