fix: allow multiple branches with same channel
This commit is contained in:
		
							parent
							
								
									20e7a38cdb
								
							
						
					
					
						commit
						63f51ae6dd
					
				| @ -48,8 +48,10 @@ For example the configuration `['+([0-9])?(.{+([0-9]),x}).x', 'master', 'next']` | |||||||
| 
 | 
 | ||||||
| ### channel | ### channel | ||||||
| 
 | 
 | ||||||
| The `channel` can be defined for any branch type. If it's not defined, releases will be done on the default distribution channel (for example the `@latest` [dist-tag](https://docs.npmjs.com/cli/dist-tag) for npm). | The `channel` can be defined for any branch type. By default releases will be done on the default distribution channel (for example the `@latest` [dist-tag](https://docs.npmjs.com/cli/dist-tag) for npm) for the first [release branch](#release-branches) and on a distribution channel named based on the branch `name` for any other branch. | ||||||
| The value of `channel`, if defined, is generated with [Lodash template](https://lodash.com/docs#template) with the variable `name` available. | If the `channel` property is set to `false` the default channel will be used. | ||||||
|  | 
 | ||||||
|  | The value of `channel`, if defined as a string, is generated with [Lodash template](https://lodash.com/docs#template) with the variable `name` available. | ||||||
| 
 | 
 | ||||||
| For example the configuration `['master', {name: 'next', channel: 'channel-${name}'}]` will be expanded as: | For example the configuration `['master', {name: 'next', channel: 'channel-${name}'}]` will be expanded as: | ||||||
| ```js | ```js | ||||||
| @ -78,7 +80,7 @@ For example the configuration `['1.1.x', '1.2.x', 'master']` will be expanded as | |||||||
| 
 | 
 | ||||||
| ### prerelease | ### prerelease | ||||||
| 
 | 
 | ||||||
| A `prerelease` property applies only to pre-release branches, is required and The `prerelease` value must be valid per the [Semantic Versioning Specification](https://semver.org/#spec-item-9). It will determine the name of versions (for example if `prerelease` is set to `beta` the version be formatted like `2.0.0-beta.1`, `2.0.0-beta.2` etc...). | A `prerelease` property applies only to pre-release branches and the `prerelease` value must be valid per the [Semantic Versioning Specification](https://semver.org/#spec-item-9). It will determine the name of versions (for example if `prerelease` is set to `beta` the version be formatted like `2.0.0-beta.1`, `2.0.0-beta.2` etc...). | ||||||
| If the `prerelease` property is set to `true` the `name` value will be used. | If the `prerelease` property is set to `true` the `name` value will be used. | ||||||
| 
 | 
 | ||||||
| The value of `prerelease`, if defined as a string, is generated with [Lodash template](https://lodash.com/docs#template) with the variable `name` available. | The value of `prerelease`, if defined as a string, is generated with [Lodash template](https://lodash.com/docs#template) with the variable `name` available. | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| const {isUndefined} = require('lodash'); | const {isUndefined} = require('lodash'); | ||||||
| const semver = require('semver'); | const semver = require('semver'); | ||||||
| const {makeTag} = require('./utils'); | const {makeTag, isSameChannel} = require('./utils'); | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Last release. |  * Last release. | ||||||
| @ -28,7 +28,10 @@ const {makeTag} = require('./utils'); | |||||||
|  */ |  */ | ||||||
| module.exports = ({branch, options: {tagFormat}}, {before} = {}) => { | module.exports = ({branch, options: {tagFormat}}, {before} = {}) => { | ||||||
|   const [{version, gitTag, channel} = {}] = branch.tags |   const [{version, gitTag, channel} = {}] = branch.tags | ||||||
|     .filter(tag => (branch.type === 'prerelease' && branch.channel === tag.channel) || !semver.prerelease(tag.version)) |     .filter( | ||||||
|  |       tag => | ||||||
|  |         (branch.type === 'prerelease' && isSameChannel(branch.channel, tag.channel)) || !semver.prerelease(tag.version) | ||||||
|  |     ) | ||||||
|     .filter(tag => isUndefined(before) || semver.lt(tag.version, before)) |     .filter(tag => isUndefined(before) || semver.lt(tag.version, before)) | ||||||
|     .sort((a, b) => semver.rcompare(a.version, b.version)); |     .sort((a, b) => semver.rcompare(a.version, b.version)); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| const semver = require('semver'); | const semver = require('semver'); | ||||||
| const {FIRST_RELEASE, FIRSTPRERELEASE} = require('./definitions/constants'); | const {FIRST_RELEASE, FIRSTPRERELEASE} = require('./definitions/constants'); | ||||||
|  | const {isSameChannel} = require('./utils'); | ||||||
| 
 | 
 | ||||||
| module.exports = ({branch, nextRelease: {type, channel}, lastRelease, logger}) => { | module.exports = ({branch, nextRelease: {type, channel}, lastRelease, logger}) => { | ||||||
|   let version; |   let version; | ||||||
| @ -7,7 +8,7 @@ module.exports = ({branch, nextRelease: {type, channel}, lastRelease, logger}) = | |||||||
|     const {major, minor, patch} = semver.parse(lastRelease.version); |     const {major, minor, patch} = semver.parse(lastRelease.version); | ||||||
|     version = |     version = | ||||||
|       branch.type === 'prerelease' |       branch.type === 'prerelease' | ||||||
|         ? semver.prerelease(lastRelease.version) && lastRelease.channel === channel |         ? semver.prerelease(lastRelease.version) && isSameChannel(lastRelease.channel, channel) | ||||||
|           ? semver.inc(lastRelease.version, 'prerelease') |           ? semver.inc(lastRelease.version, 'prerelease') | ||||||
|           : `${semver.inc(`${major}.${minor}.${patch}`, type)}-${branch.prerelease}.${FIRSTPRERELEASE}` |           : `${semver.inc(`${major}.${minor}.${patch}`, type)}-${branch.prerelease}.${FIRSTPRERELEASE}` | ||||||
|         : semver.inc(lastRelease.version, type); |         : semver.inc(lastRelease.version, type); | ||||||
|  | |||||||
| @ -71,6 +71,10 @@ function makeTag(tagFormat, version, channel) { | |||||||
|   return template(tagFormat)({version: `${version}${channel ? `@${channel}` : ''}`}); |   return template(tagFormat)({version: `${version}${channel ? `@${channel}` : ''}`}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function isSameChannel(channel, otherChannel) { | ||||||
|  |   return channel === otherChannel || (!channel && !otherChannel); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| module.exports = { | module.exports = { | ||||||
|   extractErrors, |   extractErrors, | ||||||
|   hideSensitiveValues, |   hideSensitiveValues, | ||||||
| @ -86,4 +90,5 @@ module.exports = { | |||||||
|   getFirstVersion, |   getFirstVersion, | ||||||
|   getRange, |   getRange, | ||||||
|   makeTag, |   makeTag, | ||||||
|  |   isSameChannel, | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -581,6 +581,117 @@ test('Publish a pre-release version', async t => { | |||||||
|   t.is(releases[0].gitTag, 'v1.1.0-beta.2@beta'); |   t.is(releases[0].gitTag, 'v1.1.0-beta.2@beta'); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | test('Publish releases from different branch on the same channel', async t => { | ||||||
|  |   const {cwd, repositoryUrl} = await gitRepo(true); | ||||||
|  |   await gitCommits(['feat: initial commit'], {cwd}); | ||||||
|  |   await gitTagVersion('v1.0.0', undefined, {cwd}); | ||||||
|  |   await gitPush(repositoryUrl, 'master', {cwd}); | ||||||
|  |   await gitCheckout('next-major', true, {cwd}); | ||||||
|  |   await gitPush(repositoryUrl, 'next-major', {cwd}); | ||||||
|  |   await gitCheckout('next', true, {cwd}); | ||||||
|  |   await gitCommits(['feat: a feature'], {cwd}); | ||||||
|  |   await gitPush(repositoryUrl, 'next', {cwd}); | ||||||
|  | 
 | ||||||
|  |   const config = { | ||||||
|  |     branches: ['master', {name: 'next', channel: false}, {name: 'next-major', channel: false}], | ||||||
|  |     repositoryUrl, | ||||||
|  |   }; | ||||||
|  |   const addChannel = stub().resolves({}); | ||||||
|  |   const options = { | ||||||
|  |     ...config, | ||||||
|  |     verifyConditions: stub().resolves(), | ||||||
|  |     verifyRelease: stub().resolves(), | ||||||
|  |     generateNotes: stub().resolves(''), | ||||||
|  |     addChannel, | ||||||
|  |     prepare: stub().resolves(), | ||||||
|  |     publish: stub().resolves(), | ||||||
|  |     success: stub().resolves(), | ||||||
|  |     fail: stub().resolves(), | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   let semanticRelease = requireNoCache('..', { | ||||||
|  |     './lib/get-logger': () => t.context.logger, | ||||||
|  |     'env-ci': () => ({isCi: true, branch: 'next', isPr: false}), | ||||||
|  |   }); | ||||||
|  |   let {releases} = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}); | ||||||
|  | 
 | ||||||
|  |   t.is(releases.length, 1); | ||||||
|  |   t.is(releases[0].version, '1.1.0'); | ||||||
|  |   t.is(releases[0].gitTag, 'v1.1.0'); | ||||||
|  | 
 | ||||||
|  |   await gitCommits(['fix: a fix'], {cwd}); | ||||||
|  |   ({releases} = await semanticRelease(options, { | ||||||
|  |     cwd, | ||||||
|  |     env: {}, | ||||||
|  |     stdout: {write: () => {}}, | ||||||
|  |     stderr: {write: () => {}}, | ||||||
|  |   })); | ||||||
|  | 
 | ||||||
|  |   t.is(releases.length, 1); | ||||||
|  |   t.is(releases[0].version, '1.1.1'); | ||||||
|  |   t.is(releases[0].gitTag, 'v1.1.1'); | ||||||
|  | 
 | ||||||
|  |   await gitCheckout('master', false, {cwd}); | ||||||
|  |   await merge('next', {cwd}); | ||||||
|  |   await gitPush('origin', 'master', {cwd}); | ||||||
|  | 
 | ||||||
|  |   semanticRelease = requireNoCache('..', { | ||||||
|  |     './lib/get-logger': () => t.context.logger, | ||||||
|  |     'env-ci': () => ({isCi: true, branch: 'master', isPr: false}), | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   t.falsy(await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}})); | ||||||
|  |   t.is(addChannel.callCount, 0); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | test('Publish pre-releases the same channel as regular releases', async t => { | ||||||
|  |   const {cwd, repositoryUrl} = await gitRepo(true); | ||||||
|  |   await gitCommits(['feat: initial commit'], {cwd}); | ||||||
|  |   await gitTagVersion('v1.0.0', undefined, {cwd}); | ||||||
|  |   await gitPush(repositoryUrl, 'master', {cwd}); | ||||||
|  |   await gitCheckout('beta', true, {cwd}); | ||||||
|  |   await gitCommits(['feat: a feature'], {cwd}); | ||||||
|  |   await gitPush(repositoryUrl, 'beta', {cwd}); | ||||||
|  | 
 | ||||||
|  |   const config = { | ||||||
|  |     branches: ['master', {name: 'beta', channel: false, prerelease: true}], | ||||||
|  |     repositoryUrl, | ||||||
|  |   }; | ||||||
|  |   const options = { | ||||||
|  |     ...config, | ||||||
|  |     verifyConditions: stub().resolves(), | ||||||
|  |     verifyRelease: stub().resolves(), | ||||||
|  |     generateNotes: stub().resolves(''), | ||||||
|  |     addChannel: false, | ||||||
|  |     prepare: stub().resolves(), | ||||||
|  |     publish: stub().resolves(), | ||||||
|  |     success: stub().resolves(), | ||||||
|  |     fail: stub().resolves(), | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   const semanticRelease = requireNoCache('..', { | ||||||
|  |     './lib/get-logger': () => t.context.logger, | ||||||
|  |     'env-ci': () => ({isCi: true, branch: 'beta', isPr: false}), | ||||||
|  |   }); | ||||||
|  |   let {releases} = await semanticRelease(options, {cwd, env: {}, stdout: {write: () => {}}, stderr: {write: () => {}}}); | ||||||
|  | 
 | ||||||
|  |   t.is(releases.length, 1); | ||||||
|  |   t.is(releases[0].version, '1.1.0-beta.1'); | ||||||
|  |   t.is(releases[0].gitTag, 'v1.1.0-beta.1'); | ||||||
|  | 
 | ||||||
|  |   await gitCommits(['fix: a fix'], {cwd}); | ||||||
|  |   ({releases} = await semanticRelease(options, { | ||||||
|  |     cwd, | ||||||
|  |     env: {}, | ||||||
|  |     stdout: {write: () => {}}, | ||||||
|  |     stderr: {write: () => {}}, | ||||||
|  |   })); | ||||||
|  | 
 | ||||||
|  |   t.is(releases.length, 1); | ||||||
|  |   t.is(releases[0].version, '1.1.0-beta.2'); | ||||||
|  |   t.is(releases[0].gitTag, 'v1.1.0-beta.2'); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
| test('Do not add pre-releases to a different channel', async t => { | test('Do not add pre-releases to a different channel', async t => { | ||||||
|   const {cwd, repositoryUrl} = await gitRepo(true); |   const {cwd, repositoryUrl} = await gitRepo(true); | ||||||
|   const commits = await gitCommits(['feat: initial release'], {cwd}); |   const commits = await gitCommits(['feat: initial release'], {cwd}); | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ import { | |||||||
|   getFirstVersion, |   getFirstVersion, | ||||||
|   getRange, |   getRange, | ||||||
|   makeTag, |   makeTag, | ||||||
|  |   isSameChannel, | ||||||
| } from '../lib/utils'; | } from '../lib/utils'; | ||||||
| 
 | 
 | ||||||
| test('extractErrors', t => { | test('extractErrors', t => { | ||||||
| @ -178,3 +179,12 @@ test('makeTag', t => { | |||||||
|   t.is(makeTag(`v\${version}`, '1.0.0', 'next'), 'v1.0.0@next'); |   t.is(makeTag(`v\${version}`, '1.0.0', 'next'), 'v1.0.0@next'); | ||||||
|   t.is(makeTag(`v\${version}@test`, '1.0.0', 'next'), 'v1.0.0@next@test'); |   t.is(makeTag(`v\${version}@test`, '1.0.0', 'next'), 'v1.0.0@next@test'); | ||||||
| }); | }); | ||||||
|  | 
 | ||||||
|  | test('isSameChannel', t => { | ||||||
|  |   t.true(isSameChannel('next', 'next')); | ||||||
|  |   t.true(isSameChannel(null, undefined)); | ||||||
|  |   t.true(isSameChannel(false, undefined)); | ||||||
|  |   t.true(isSameChannel('', false)); | ||||||
|  | 
 | ||||||
|  |   t.false(isSameChannel('next', false)); | ||||||
|  | }); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user