feat: allow to define multiple generateNotes plugins
				
					
				
			Each `generateNotes` plugin will be called in the order defined and will receive the concatenation of the previous one in `nextRelease.notes`. That gives each plugin the ability to test if there is a notes part that will precede it's own. Each plugin is expected to return it's own part of the release notes only. **semantic-release** will take care of concatenating all the notes parts.
This commit is contained in:
		
							parent
							
								
									576eb6027f
								
							
						
					
					
						commit
						5989989452
					
				| @ -167,13 +167,13 @@ See [Plugins configuration](plugins.md#configuration) for more details. | |||||||
| 
 | 
 | ||||||
| ### generateNotes | ### generateNotes | ||||||
| 
 | 
 | ||||||
| Type: `String`, `Object` | Type: `Array`, `String`, `Object` | ||||||
| 
 | 
 | ||||||
| Default: `['@semantic-release/release-notes-generator']` | Default: `['@semantic-release/release-notes-generator']` | ||||||
| 
 | 
 | ||||||
| CLI argument: `--generate-notes` | CLI argument: `--generate-notes` | ||||||
| 
 | 
 | ||||||
| Define the [generate notes plugin](plugins.md#generatenotes-plugin). | Define the [generate notes plugins](plugins.md#generatenotes-plugin). | ||||||
| 
 | 
 | ||||||
| See [Plugins configuration](plugins.md#configuration) for more details. | See [Plugins configuration](plugins.md#configuration) for more details. | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -26,7 +26,7 @@ Default implementation: none. | |||||||
| 
 | 
 | ||||||
| ### generateNotes plugin | ### generateNotes plugin | ||||||
| 
 | 
 | ||||||
| Responsible for generating release notes. | Responsible for generating release notes. If multiple `generateNotes` plugins are defined, the release notes will be the result of the concatenation of plugin output. | ||||||
| 
 | 
 | ||||||
| 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). | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										41
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								index.js
									
									
									
									
									
								
							| @ -15,7 +15,7 @@ const getGitAuthUrl = require('./lib/get-git-auth-url'); | |||||||
| const logger = require('./lib/logger'); | const logger = require('./lib/logger'); | ||||||
| const {fetch, verifyAuth, isBranchUpToDate, gitHead: getGitHead, tag, push} = require('./lib/git'); | const {fetch, verifyAuth, isBranchUpToDate, gitHead: getGitHead, tag, push} = require('./lib/git'); | ||||||
| const getError = require('./lib/get-error'); | const getError = require('./lib/get-error'); | ||||||
| const {COMMIT_NAME, COMMIT_EMAIL} = require('./lib/definitions/constants'); | const {COMMIT_NAME, COMMIT_EMAIL, RELEASE_NOTES_SEPARATOR} = require('./lib/definitions/constants'); | ||||||
| 
 | 
 | ||||||
| marked.setOptions({renderer: new TerminalRenderer()}); | marked.setOptions({renderer: new TerminalRenderer()}); | ||||||
| 
 | 
 | ||||||
| @ -101,14 +101,34 @@ async function run(options, plugins) { | |||||||
| 
 | 
 | ||||||
|   if (options.dryRun) { |   if (options.dryRun) { | ||||||
|     logger.log('Call plugin %s', 'generate-notes'); |     logger.log('Call plugin %s', 'generate-notes'); | ||||||
|     const [notes] = await plugins.generateNotes(generateNotesParam); |     const notes = (await plugins.generateNotes(generateNotesParam, { | ||||||
|  |       getNextInput: ({nextRelease, ...generateNotesParam}, notes) => ({ | ||||||
|  |         ...generateNotesParam, | ||||||
|  |         nextRelease: { | ||||||
|  |           ...nextRelease, | ||||||
|  |           notes: `${nextRelease.notes ? `${nextRelease.notes}${RELEASE_NOTES_SEPARATOR}` : ''}${notes}`, | ||||||
|  |         }, | ||||||
|  |       }), | ||||||
|  |     })) | ||||||
|  |       .filter(Boolean) | ||||||
|  |       .join(RELEASE_NOTES_SEPARATOR); | ||||||
|     logger.log('Release note for version %s:\n', nextRelease.version); |     logger.log('Release note for version %s:\n', nextRelease.version); | ||||||
|     if (notes) { |     if (notes) { | ||||||
|       process.stdout.write(`${marked(notes)}\n`); |       process.stdout.write(`${marked(notes)}\n`); | ||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
|     logger.log('Call plugin %s', 'generateNotes'); |     logger.log('Call plugin %s', 'generateNotes'); | ||||||
|     [nextRelease.notes] = await plugins.generateNotes(generateNotesParam); |     nextRelease.notes = (await plugins.generateNotes(generateNotesParam, { | ||||||
|  |       getNextInput: ({nextRelease, ...generateNotesParam}, notes) => ({ | ||||||
|  |         ...generateNotesParam, | ||||||
|  |         nextRelease: { | ||||||
|  |           ...nextRelease, | ||||||
|  |           notes: `${nextRelease.notes ? `${nextRelease.notes}${RELEASE_NOTES_SEPARATOR}` : ''}${notes}`, | ||||||
|  |         }, | ||||||
|  |       }), | ||||||
|  |     })) | ||||||
|  |       .filter(Boolean) | ||||||
|  |       .join(RELEASE_NOTES_SEPARATOR); | ||||||
| 
 | 
 | ||||||
|     logger.log('Call plugin %s', 'prepare'); |     logger.log('Call plugin %s', 'prepare'); | ||||||
|     await plugins.prepare( |     await plugins.prepare( | ||||||
| @ -121,7 +141,20 @@ async function run(options, plugins) { | |||||||
|             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'); | ||||||
|             [nextRelease.notes] = await plugins.generateNotes({nextRelease, ...prepareParam}); |             nextRelease.notes = (await plugins.generateNotes( | ||||||
|  |               {nextRelease, ...prepareParam}, | ||||||
|  |               { | ||||||
|  |                 getNextInput: ({nextRelease, ...generateNotesParam}, notes) => ({ | ||||||
|  |                   ...generateNotesParam, | ||||||
|  |                   nextRelease: { | ||||||
|  |                     ...nextRelease, | ||||||
|  |                     notes: `${nextRelease.notes ? `${nextRelease.notes}${RELEASE_NOTES_SEPARATOR}` : ''}${notes}`, | ||||||
|  |                   }, | ||||||
|  |                 }), | ||||||
|  |               } | ||||||
|  |             )) | ||||||
|  |               .filter(Boolean) | ||||||
|  |               .join(RELEASE_NOTES_SEPARATOR); | ||||||
|           } |           } | ||||||
|           // Call the next publish plugin with the updated `nextRelease`
 |           // Call the next publish plugin with the updated `nextRelease`
 | ||||||
|           return {...prepareParam, nextRelease}; |           return {...prepareParam, nextRelease}; | ||||||
|  | |||||||
| @ -6,4 +6,6 @@ const COMMIT_NAME = 'semantic-release-bot'; | |||||||
| 
 | 
 | ||||||
| const COMMIT_EMAIL = 'semantic-release-bot@martynus.net'; | const COMMIT_EMAIL = 'semantic-release-bot@martynus.net'; | ||||||
| 
 | 
 | ||||||
| module.exports = {RELEASE_TYPE, FIRST_RELEASE, COMMIT_NAME, COMMIT_EMAIL}; | const RELEASE_NOTES_SEPARATOR = '\n\n'; | ||||||
|  | 
 | ||||||
|  | module.exports = {RELEASE_TYPE, FIRST_RELEASE, COMMIT_NAME, COMMIT_EMAIL, RELEASE_NOTES_SEPARATOR}; | ||||||
|  | |||||||
| @ -18,8 +18,8 @@ module.exports = { | |||||||
|     configValidator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)), |     configValidator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)), | ||||||
|   }, |   }, | ||||||
|   generateNotes: { |   generateNotes: { | ||||||
|     default: '@semantic-release/release-notes-generator', |     default: ['@semantic-release/release-notes-generator'], | ||||||
|     configValidator: conf => !conf || validatePluginConfig(conf), |     configValidator: conf => !conf || (isArray(conf) ? conf : [conf]).every(conf => validatePluginConfig(conf)), | ||||||
|     outputValidator: output => !output || isString(output), |     outputValidator: output => !output || isString(output), | ||||||
|   }, |   }, | ||||||
|   prepare: { |   prepare: { | ||||||
|  | |||||||
| @ -34,15 +34,15 @@ test('The "verifyRelease" plugin, if defined, must be a single or an array of pl | |||||||
|   t.true(plugins.verifyRelease.configValidator([{path: 'plugin-path.js'}, 'plugin-path.js', () => {}])); |   t.true(plugins.verifyRelease.configValidator([{path: 'plugin-path.js'}, 'plugin-path.js', () => {}])); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test('The "generateNotes" plugin, if defined, must be a single plugin definition', t => { | test('The "generateNotes" plugin, if defined, must be a single or an array of plugins definition', t => { | ||||||
|   t.false(plugins.generateNotes.configValidator({})); |   t.false(plugins.generateNotes.configValidator({})); | ||||||
|   t.false(plugins.generateNotes.configValidator({path: null})); |   t.false(plugins.generateNotes.configValidator({path: null})); | ||||||
|   t.false(plugins.generateNotes.configValidator([])); |  | ||||||
| 
 | 
 | ||||||
|   t.true(plugins.generateNotes.configValidator()); |  | ||||||
|   t.true(plugins.generateNotes.configValidator({path: 'plugin-path.js'})); |   t.true(plugins.generateNotes.configValidator({path: 'plugin-path.js'})); | ||||||
|  |   t.true(plugins.generateNotes.configValidator()); | ||||||
|   t.true(plugins.generateNotes.configValidator('plugin-path.js')); |   t.true(plugins.generateNotes.configValidator('plugin-path.js')); | ||||||
|   t.true(plugins.generateNotes.configValidator(() => {})); |   t.true(plugins.generateNotes.configValidator(() => {})); | ||||||
|  |   t.true(plugins.generateNotes.configValidator([{path: 'plugin-path.js'}, 'plugin-path.js', () => {}])); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test('The "prepare" plugin, if defined, must be a single or an array of plugins definition', t => { | test('The "prepare" plugin, if defined, must be a single or an array of plugins definition', t => { | ||||||
|  | |||||||
| @ -61,12 +61,16 @@ test.serial('Plugins are called with expected values', async t => { | |||||||
| 
 | 
 | ||||||
|   const lastRelease = {version: '1.0.0', gitHead: commits[commits.length - 1].hash, gitTag: 'v1.0.0'}; |   const lastRelease = {version: '1.0.0', gitHead: commits[commits.length - 1].hash, gitTag: 'v1.0.0'}; | ||||||
|   const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead(), gitTag: 'v2.0.0'}; |   const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead(), gitTag: 'v2.0.0'}; | ||||||
|   const notes = 'Release notes'; |   const notes1 = 'Release notes 1'; | ||||||
|  |   const notes2 = 'Release notes 2'; | ||||||
|  |   const notes3 = 'Release notes 3'; | ||||||
|   const verifyConditions1 = stub().resolves(); |   const verifyConditions1 = stub().resolves(); | ||||||
|   const verifyConditions2 = stub().resolves(); |   const verifyConditions2 = stub().resolves(); | ||||||
|   const analyzeCommits = stub().resolves(nextRelease.type); |   const analyzeCommits = stub().resolves(nextRelease.type); | ||||||
|   const verifyRelease = stub().resolves(); |   const verifyRelease = stub().resolves(); | ||||||
|   const generateNotes = stub().resolves(notes); |   const generateNotes1 = stub().resolves(notes1); | ||||||
|  |   const generateNotes2 = stub().resolves(notes2); | ||||||
|  |   const generateNotes3 = stub().resolves(notes3); | ||||||
|   const release1 = {name: 'Release 1', url: 'https://release1.com'}; |   const release1 = {name: 'Release 1', url: 'https://release1.com'}; | ||||||
|   const prepare = stub().resolves(); |   const prepare = stub().resolves(); | ||||||
|   const publish1 = stub().resolves(release1); |   const publish1 = stub().resolves(release1); | ||||||
| @ -78,7 +82,7 @@ test.serial('Plugins are called with expected values', async t => { | |||||||
|     verifyConditions: [verifyConditions1, verifyConditions2], |     verifyConditions: [verifyConditions1, verifyConditions2], | ||||||
|     analyzeCommits, |     analyzeCommits, | ||||||
|     verifyRelease, |     verifyRelease, | ||||||
|     generateNotes, |     generateNotes: [generateNotes1, generateNotes2, generateNotes3], | ||||||
|     prepare, |     prepare, | ||||||
|     publish: [publish1, pluginNoop], |     publish: [publish1, pluginNoop], | ||||||
|     success, |     success, | ||||||
| @ -113,14 +117,32 @@ test.serial('Plugins are called with expected values', async t => { | |||||||
|   t.deepEqual(verifyRelease.args[0][1].commits[0].message, commits[0].message); |   t.deepEqual(verifyRelease.args[0][1].commits[0].message, commits[0].message); | ||||||
|   t.deepEqual(verifyRelease.args[0][1].nextRelease, nextRelease); |   t.deepEqual(verifyRelease.args[0][1].nextRelease, nextRelease); | ||||||
| 
 | 
 | ||||||
|   t.is(generateNotes.callCount, 1); |   t.is(generateNotes1.callCount, 1); | ||||||
|   t.deepEqual(generateNotes.args[0][0], config); |   t.deepEqual(generateNotes1.args[0][0], config); | ||||||
|   t.deepEqual(generateNotes.args[0][1].options, options); |   t.deepEqual(generateNotes1.args[0][1].options, options); | ||||||
|   t.deepEqual(generateNotes.args[0][1].logger, t.context.logger); |   t.deepEqual(generateNotes1.args[0][1].logger, t.context.logger); | ||||||
|   t.deepEqual(generateNotes.args[0][1].lastRelease, lastRelease); |   t.deepEqual(generateNotes1.args[0][1].lastRelease, lastRelease); | ||||||
|   t.deepEqual(generateNotes.args[0][1].commits[0].hash, commits[0].hash); |   t.deepEqual(generateNotes1.args[0][1].commits[0].hash, commits[0].hash); | ||||||
|   t.deepEqual(generateNotes.args[0][1].commits[0].message, commits[0].message); |   t.deepEqual(generateNotes1.args[0][1].commits[0].message, commits[0].message); | ||||||
|   t.deepEqual(generateNotes.args[0][1].nextRelease, nextRelease); |   t.deepEqual(generateNotes1.args[0][1].nextRelease, nextRelease); | ||||||
|  | 
 | ||||||
|  |   t.is(generateNotes2.callCount, 1); | ||||||
|  |   t.deepEqual(generateNotes2.args[0][0], config); | ||||||
|  |   t.deepEqual(generateNotes2.args[0][1].options, options); | ||||||
|  |   t.deepEqual(generateNotes2.args[0][1].logger, t.context.logger); | ||||||
|  |   t.deepEqual(generateNotes2.args[0][1].lastRelease, lastRelease); | ||||||
|  |   t.deepEqual(generateNotes2.args[0][1].commits[0].hash, commits[0].hash); | ||||||
|  |   t.deepEqual(generateNotes2.args[0][1].commits[0].message, commits[0].message); | ||||||
|  |   t.deepEqual(generateNotes2.args[0][1].nextRelease, {...nextRelease, notes: notes1}); | ||||||
|  | 
 | ||||||
|  |   t.is(generateNotes3.callCount, 1); | ||||||
|  |   t.deepEqual(generateNotes3.args[0][0], config); | ||||||
|  |   t.deepEqual(generateNotes3.args[0][1].options, options); | ||||||
|  |   t.deepEqual(generateNotes3.args[0][1].logger, t.context.logger); | ||||||
|  |   t.deepEqual(generateNotes3.args[0][1].lastRelease, lastRelease); | ||||||
|  |   t.deepEqual(generateNotes3.args[0][1].commits[0].hash, commits[0].hash); | ||||||
|  |   t.deepEqual(generateNotes3.args[0][1].commits[0].message, commits[0].message); | ||||||
|  |   t.deepEqual(generateNotes3.args[0][1].nextRelease, {...nextRelease, notes: `${notes1}\n\n${notes2}`}); | ||||||
| 
 | 
 | ||||||
|   t.is(prepare.callCount, 1); |   t.is(prepare.callCount, 1); | ||||||
|   t.deepEqual(prepare.args[0][0], config); |   t.deepEqual(prepare.args[0][0], config); | ||||||
| @ -129,7 +151,7 @@ test.serial('Plugins are called with expected values', async t => { | |||||||
|   t.deepEqual(prepare.args[0][1].lastRelease, lastRelease); |   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].hash, commits[0].hash); | ||||||
|   t.deepEqual(prepare.args[0][1].commits[0].message, commits[0].message); |   t.deepEqual(prepare.args[0][1].commits[0].message, commits[0].message); | ||||||
|   t.deepEqual(prepare.args[0][1].nextRelease, {...nextRelease, ...{notes}}); |   t.deepEqual(prepare.args[0][1].nextRelease, {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`}); | ||||||
| 
 | 
 | ||||||
|   t.is(publish1.callCount, 1); |   t.is(publish1.callCount, 1); | ||||||
|   t.deepEqual(publish1.args[0][0], config); |   t.deepEqual(publish1.args[0][0], config); | ||||||
| @ -138,7 +160,7 @@ test.serial('Plugins are called with expected values', async t => { | |||||||
|   t.deepEqual(publish1.args[0][1].lastRelease, lastRelease); |   t.deepEqual(publish1.args[0][1].lastRelease, lastRelease); | ||||||
|   t.deepEqual(publish1.args[0][1].commits[0].hash, commits[0].hash); |   t.deepEqual(publish1.args[0][1].commits[0].hash, commits[0].hash); | ||||||
|   t.deepEqual(publish1.args[0][1].commits[0].message, commits[0].message); |   t.deepEqual(publish1.args[0][1].commits[0].message, commits[0].message); | ||||||
|   t.deepEqual(publish1.args[0][1].nextRelease, {...nextRelease, ...{notes}}); |   t.deepEqual(publish1.args[0][1].nextRelease, {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`}); | ||||||
| 
 | 
 | ||||||
|   t.is(success.callCount, 1); |   t.is(success.callCount, 1); | ||||||
|   t.deepEqual(success.args[0][0], config); |   t.deepEqual(success.args[0][0], config); | ||||||
| @ -147,10 +169,10 @@ test.serial('Plugins are called with expected values', async t => { | |||||||
|   t.deepEqual(success.args[0][1].lastRelease, lastRelease); |   t.deepEqual(success.args[0][1].lastRelease, lastRelease); | ||||||
|   t.deepEqual(success.args[0][1].commits[0].hash, commits[0].hash); |   t.deepEqual(success.args[0][1].commits[0].hash, commits[0].hash); | ||||||
|   t.deepEqual(success.args[0][1].commits[0].message, commits[0].message); |   t.deepEqual(success.args[0][1].commits[0].message, commits[0].message); | ||||||
|   t.deepEqual(success.args[0][1].nextRelease, {...nextRelease, ...{notes}}); |   t.deepEqual(success.args[0][1].nextRelease, {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`}); | ||||||
|   t.deepEqual(success.args[0][1].releases, [ |   t.deepEqual(success.args[0][1].releases, [ | ||||||
|     {...release1, ...nextRelease, ...{notes}, ...{pluginName: '[Function: proxy]'}}, |     {...release1, ...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`, pluginName: '[Function: proxy]'}, | ||||||
|     {...nextRelease, ...{notes}, ...{pluginName: pluginNoop}}, |     {...nextRelease, notes: `${notes1}\n\n${notes2}\n\n${notes3}`, pluginName: pluginNoop}, | ||||||
|   ]); |   ]); | ||||||
| 
 | 
 | ||||||
|   // Verify the tag has been created on the local and remote repo and reference the gitHead
 |   // Verify the tag has been created on the local and remote repo and reference the gitHead
 | ||||||
| @ -625,7 +647,9 @@ test.serial('Accept "undefined" value returned by the "generateNotes" plugins', | |||||||
|   const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead(), gitTag: 'v2.0.0'}; |   const nextRelease = {type: 'major', version: '2.0.0', gitHead: await getGitHead(), gitTag: 'v2.0.0'}; | ||||||
|   const analyzeCommits = stub().resolves(nextRelease.type); |   const analyzeCommits = stub().resolves(nextRelease.type); | ||||||
|   const verifyRelease = stub().resolves(); |   const verifyRelease = stub().resolves(); | ||||||
|   const generateNotes = stub().resolves(); |   const generateNotes1 = stub().resolves(); | ||||||
|  |   const notes2 = 'Release notes 2'; | ||||||
|  |   const generateNotes2 = stub().resolves(notes2); | ||||||
|   const publish = stub().resolves(); |   const publish = stub().resolves(); | ||||||
| 
 | 
 | ||||||
|   const options = { |   const options = { | ||||||
| @ -634,7 +658,7 @@ test.serial('Accept "undefined" value returned by the "generateNotes" plugins', | |||||||
|     verifyConditions: stub().resolves(), |     verifyConditions: stub().resolves(), | ||||||
|     analyzeCommits, |     analyzeCommits, | ||||||
|     verifyRelease, |     verifyRelease, | ||||||
|     generateNotes, |     generateNotes: [generateNotes1, generateNotes2], | ||||||
|     prepare: stub().resolves(), |     prepare: stub().resolves(), | ||||||
|     publish, |     publish, | ||||||
|     success: stub().resolves(), |     success: stub().resolves(), | ||||||
| @ -653,12 +677,15 @@ test.serial('Accept "undefined" value returned by the "generateNotes" plugins', | |||||||
|   t.is(verifyRelease.callCount, 1); |   t.is(verifyRelease.callCount, 1); | ||||||
|   t.deepEqual(verifyRelease.args[0][1].lastRelease, lastRelease); |   t.deepEqual(verifyRelease.args[0][1].lastRelease, lastRelease); | ||||||
| 
 | 
 | ||||||
|   t.is(generateNotes.callCount, 1); |   t.is(generateNotes1.callCount, 1); | ||||||
|   t.deepEqual(generateNotes.args[0][1].lastRelease, lastRelease); |   t.deepEqual(generateNotes1.args[0][1].lastRelease, lastRelease); | ||||||
|  | 
 | ||||||
|  |   t.is(generateNotes2.callCount, 1); | ||||||
|  |   t.deepEqual(generateNotes2.args[0][1].lastRelease, lastRelease); | ||||||
| 
 | 
 | ||||||
|   t.is(publish.callCount, 1); |   t.is(publish.callCount, 1); | ||||||
|   t.deepEqual(publish.args[0][1].lastRelease, lastRelease); |   t.deepEqual(publish.args[0][1].lastRelease, lastRelease); | ||||||
|   t.falsy(publish.args[0][1].nextRelease.notes); |   t.is(publish.args[0][1].nextRelease.notes, notes2); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial('Returns falsy value if triggered by a PR', async t => { | test.serial('Returns falsy value if triggered by a PR', async t => { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user