diff --git a/__tests__/branch.test.ts b/__tests__/branch.test.ts index 174b22b..2b8ad57 100644 --- a/__tests__/branch.test.ts +++ b/__tests__/branch.test.ts @@ -10,6 +10,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: '', + ignoredBranches: [], majorVersion: 1, minorVersion: 19, nextMajorStableBranch: 'v2.0', @@ -23,6 +24,7 @@ describe('Branch', () => { name: '1.18', stableBranchNamePattern: '.', devBranchNamePattern: '', + ignoredBranches: [], majorVersion: 1, minorVersion: 18, nextMajorStableBranch: '2.0', @@ -36,6 +38,7 @@ describe('Branch', () => { name: '1.17.x', stableBranchNamePattern: '..x', devBranchNamePattern: '', + ignoredBranches: [], majorVersion: 1, minorVersion: 17, nextMajorStableBranch: '2.0.x', @@ -49,6 +52,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], majorVersion: 1, minorVersion: 19, nextMajorStableBranch: 'v2.0', @@ -62,6 +66,7 @@ describe('Branch', () => { name: 'v1.x', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], majorVersion: 1, minorVersion: null, nextMajorStableBranch: 'v2.0', @@ -69,6 +74,49 @@ describe('Branch', () => { nextMajorDevBranch: 'v2.x', nextMinorDevBranch: '', isStable: false + }, + { + description: 'v. with no dev branch and ignored branches', + name: 'v1.19', + stableBranchNamePattern: 'v.', + devBranchNamePattern: '', + ignoredBranches: ['v1.20', 'v1.21', 'v2.0'], + majorVersion: 1, + minorVersion: 19, + nextMajorStableBranch: 'v2.1', + nextMinorStableBranch: 'v1.22', + nextMajorDevBranch: '', + nextMinorDevBranch: '', + isStable: true + }, + { + description: 'v. with a dev branch and ignored branches', + name: 'v1.19', + stableBranchNamePattern: 'v.', + devBranchNamePattern: 'v.x', + ignoredBranches: ['v1.20', 'v1.21', 'v2.0'], + majorVersion: 1, + minorVersion: 19, + nextMajorStableBranch: 'v2.1', + nextMinorStableBranch: 'v1.22', + nextMajorDevBranch: 'v2.x', + nextMinorDevBranch: 'v1.x', + isStable: true + }, + { + description: + 'dev branch for v. and ignored next major dev branch', + name: 'v1.x', + stableBranchNamePattern: 'v.', + devBranchNamePattern: 'v.x', + ignoredBranches: ['v2.x'], + majorVersion: 1, + minorVersion: null, + nextMajorStableBranch: 'v2.0', + nextMinorStableBranch: '', + nextMajorDevBranch: 'v3.x', + nextMinorDevBranch: '', + isStable: false } ] @@ -78,6 +126,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: [], nextBranchName: 'fallback' }, @@ -86,6 +135,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: ['v1.20'], nextBranchName: 'v1.20' }, @@ -94,6 +144,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: ['v1.x'], nextBranchName: 'v1.x' }, @@ -102,6 +153,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: ['v2.0'], nextBranchName: 'v2.0' }, @@ -110,6 +162,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: ['v2.x'], nextBranchName: 'v2.x' }, @@ -118,6 +171,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: ['v1.20', 'v1.x'], nextBranchName: 'v1.20' }, @@ -126,6 +180,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: ['v1.20', 'v1.x', 'v2.0', 'v2.x'], nextBranchName: 'v1.20' }, @@ -134,6 +189,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: ['v2.0', 'v2.x'], nextBranchName: 'v2.0' }, @@ -142,6 +198,7 @@ describe('Branch', () => { name: 'v1.19', stableBranchNamePattern: 'v.', devBranchNamePattern: '', + ignoredBranches: [], existingBranches: ['v1.x', 'v2.x'], nextBranchName: 'fallback' }, @@ -150,6 +207,7 @@ describe('Branch', () => { name: 'v1.x', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: ['v1.x', 'v2.0', 'v2.x'], nextBranchName: 'v2.0' }, @@ -158,9 +216,83 @@ describe('Branch', () => { name: 'v1.x', stableBranchNamePattern: 'v.', devBranchNamePattern: 'v.x', + ignoredBranches: [], existingBranches: ['v1.x', 'v2.x'], nextBranchName: 'v2.x' + }, + { + description: 'Next minor version branch exists, but is ignored', + name: 'v1.19', + stableBranchNamePattern: 'v.', + devBranchNamePattern: 'v.x', + ignoredBranches: ['v1.20'], + existingBranches: ['v1.20', 'v1.x', 'v2.0', 'v2.x'], + nextBranchName: 'v1.x' + }, + { + description: 'Next minor version branches exists, but is ignored', + name: 'v1.19', + stableBranchNamePattern: 'v.', + devBranchNamePattern: 'v.x', + ignoredBranches: ['v1.20'], + existingBranches: ['v1.20', 'v1.21', 'v1.x', 'v2.0', 'v2.x'], + nextBranchName: 'v1.21' + }, + { + description: 'Next dev version branch exists, but is ignored', + name: 'v1.19', + stableBranchNamePattern: 'v.', + devBranchNamePattern: 'v.x', + ignoredBranches: ['v1.x'], + existingBranches: ['v1.x', 'v2.0', 'v2.x'], + nextBranchName: 'v2.0' + }, + { + description: 'Next major stable version branch exists, but is ignored', + name: 'v1.19', + stableBranchNamePattern: 'v.', + devBranchNamePattern: 'v.x', + ignoredBranches: ['v2.0'], + existingBranches: ['v2.0', 'v2.x'], + nextBranchName: 'v2.x' + }, + { + description: 'Next major stable version branches exists, but is ignored', + name: 'v1.19', + stableBranchNamePattern: 'v.', + devBranchNamePattern: 'v.x', + ignoredBranches: ['v2.0'], + existingBranches: ['v2.0', 'v2.1', 'v2.x'], + nextBranchName: 'v2.1' + }, + { + description: 'Next major dev version branch exists, but is ignored', + name: 'v1.19', + stableBranchNamePattern: 'v.', + devBranchNamePattern: 'v.x', + ignoredBranches: ['v2.x'], + existingBranches: ['v2.x'], + nextBranchName: 'fallback' + }, + { + description: 'Next major dev version branches exists, but is ignored', + name: 'v1.19', + stableBranchNamePattern: 'v.', + devBranchNamePattern: 'v.x', + ignoredBranches: ['v2.x'], + existingBranches: ['v2.x', 'v3.x'], + nextBranchName: 'v3.x' } + // TODO: The following test fails as we don't try stable branches for future major versions + // { + // description: 'All existing branches for next major version are ignored', + // name: 'v1.19', + // stableBranchNamePattern: 'v.', + // devBranchNamePattern: 'v.x', + // ignoredBranches: ['v2.x', 'v2.0'], + // existingBranches: ['v2.0', 'v2.x', 'v3.0', 'v3.x'], + // nextBranchName: 'v3.0' + // } ] describe('constructor', () => { @@ -170,6 +302,7 @@ describe('Branch', () => { name, stableBranchNamePattern, devBranchNamePattern, + ignoredBranches, majorVersion, minorVersion, isStable @@ -177,7 +310,8 @@ describe('Branch', () => { const branch = new Branch( name, stableBranchNamePattern, - devBranchNamePattern + devBranchNamePattern, + ignoredBranches ) expect(branch.name).toStrictEqual(name) @@ -191,7 +325,7 @@ describe('Branch', () => { ) it("rejects branches that don't match ($description)", () => { - expect(() => new Branch('1.19', 'v.', '')).toThrow( + expect(() => new Branch('1.19', 'v.', '', [])).toThrow( new Error( `Ref name "1.19" does not match branch name patterns "v." or "".` ) @@ -206,12 +340,14 @@ describe('Branch', () => { name, stableBranchNamePattern, devBranchNamePattern, + ignoredBranches, nextMajorStableBranch }) => { const branch = new Branch( name, stableBranchNamePattern, - devBranchNamePattern + devBranchNamePattern, + ignoredBranches ) expect(branch.getNextMajorStableBranch()).toStrictEqual( @@ -228,12 +364,14 @@ describe('Branch', () => { name, stableBranchNamePattern, devBranchNamePattern, + ignoredBranches, nextMinorStableBranch }) => { const branch = new Branch( name, stableBranchNamePattern, - devBranchNamePattern + devBranchNamePattern, + ignoredBranches ) expect(branch.getNextMinorStableBranch()).toStrictEqual( @@ -250,12 +388,14 @@ describe('Branch', () => { name, stableBranchNamePattern, devBranchNamePattern, + ignoredBranches, nextMajorDevBranch }) => { const branch = new Branch( name, stableBranchNamePattern, - devBranchNamePattern + devBranchNamePattern, + ignoredBranches ) expect(branch.getNextMajorDevBranch()).toStrictEqual(nextMajorDevBranch) @@ -270,12 +410,14 @@ describe('Branch', () => { name, stableBranchNamePattern, devBranchNamePattern, + ignoredBranches, nextMinorDevBranch }) => { const branch = new Branch( name, stableBranchNamePattern, - devBranchNamePattern + devBranchNamePattern, + ignoredBranches ) expect(branch.getNextMinorDevBranch()).toStrictEqual(nextMinorDevBranch) @@ -290,7 +432,7 @@ describe('Branch', () => { return false }) - const branch = new Branch('v1.20', 'v.', '') + const branch = new Branch('v1.20', 'v.', '', []) await expect(branch.getNextBranchName('')).rejects.toThrow( new Error( @@ -305,6 +447,7 @@ describe('Branch', () => { name, stableBranchNamePattern, devBranchNamePattern, + ignoredBranches, existingBranches, nextBranchName }) => { @@ -316,7 +459,8 @@ describe('Branch', () => { const branch = new Branch( name, stableBranchNamePattern, - devBranchNamePattern + devBranchNamePattern, + ignoredBranches ) expect(await branch.getNextBranchName('fallback')).toStrictEqual( diff --git a/__tests__/inputs.test.ts b/__tests__/inputs.test.ts index dbaf541..e124b52 100644 --- a/__tests__/inputs.test.ts +++ b/__tests__/inputs.test.ts @@ -11,7 +11,8 @@ describe('Inputs', () => { 'v.', 'v.x', 'main', - true + true, + ['v1.x'] ) expect(inputs.currentBranch).toStrictEqual('v1.19') @@ -19,6 +20,7 @@ describe('Inputs', () => { expect(inputs.devBranchNamePattern).toStrictEqual('v.x') expect(inputs.fallbackBranch).toStrictEqual('main') expect(inputs.enableAutoMerge).toStrictEqual(true) + expect(inputs.ignoredBranches).toStrictEqual(['v1.x']) }) it('retrieves values from input', async () => { @@ -33,6 +35,8 @@ describe('Inputs', () => { return 'v.x' case 'fallbackBranch': return 'main' + case 'ignoredBranches': + return '["v1.x"]' default: return '' } @@ -57,8 +61,9 @@ describe('Inputs', () => { expect(inputs.devBranchNamePattern).toStrictEqual('v.x') expect(inputs.enableAutoMerge).toStrictEqual(true) expect(inputs.fallbackBranch).toStrictEqual('main') + expect(inputs.ignoredBranches).toStrictEqual(['v1.x']) - expect(getInputMock).toHaveBeenCalledTimes(4) + expect(getInputMock).toHaveBeenCalledTimes(5) expect(getBooleanInputMock).toHaveBeenCalledTimes(1) }) @@ -72,6 +77,9 @@ describe('Inputs', () => { return 'v.' case 'fallbackBranch': return '' + case 'ignoredBranches': + // Return an empty string on purpose + return '' default: return '' } @@ -93,7 +101,7 @@ describe('Inputs', () => { expect(inputs.enableAutoMerge).toStrictEqual(false) - expect(getInputMock).toHaveBeenCalledTimes(4) + expect(getInputMock).toHaveBeenCalledTimes(5) expect(getBooleanInputMock).toHaveBeenCalledTimes(1) }) }) diff --git a/action.yml b/action.yml index 039bceb..41c24b8 100644 --- a/action.yml +++ b/action.yml @@ -31,6 +31,10 @@ inputs: description: 'If non-empty, enables auto-merge on the pull request' required: false default: 'false' + ignoredBranches: + description: 'JSON list of branches to ignore' + required: false + default: '[]' outputs: branchName: diff --git a/badges/coverage.svg b/badges/coverage.svg index 23db6ef..38ecb1e 100644 --- a/badges/coverage.svg +++ b/badges/coverage.svg @@ -1 +1 @@ -Coverage: 47.13%Coverage47.13% \ No newline at end of file +Coverage: 52.02%Coverage52.02% \ No newline at end of file diff --git a/dist/create-pr/index.js b/dist/create-pr/index.js index ac420e8..34096d0 100644 --- a/dist/create-pr/index.js +++ b/dist/create-pr/index.js @@ -25426,11 +25426,13 @@ class Branch { minorVersion; stableBranchNamePattern; devBranchNamePattern; + ignoredBranches; isStable = true; - constructor(name, stableBranchNamePattern, devBranchNamePattern) { + constructor(name, stableBranchNamePattern, devBranchNamePattern, ignoredBranches) { this.name = name; this.stableBranchNamePattern = stableBranchNamePattern; this.devBranchNamePattern = devBranchNamePattern; + this.ignoredBranches = ignoredBranches; const stableBranchPatternRegex = (0, regex_1.createRegexFromPattern)(stableBranchNamePattern); const devBranchPatternRegex = (0, regex_1.createRegexFromPattern)(devBranchNamePattern); let versions = name.match(stableBranchPatternRegex); @@ -25447,24 +25449,43 @@ class Branch { this.minorVersion = versions[2] ? Number(versions[2]) : null; } getNextMajorStableBranch() { - return this.stableBranchNamePattern - .replace('', (this.majorVersion + 1).toString()) - .replace('', '0'); + return this.getNextNotIgnoredStableBranch(this.majorVersion + 1, 0); } getNextMajorDevBranch() { - return this.devBranchNamePattern.replace('', (this.majorVersion + 1).toString()); + return this.getNextNotIgnoredDevBranch(this.majorVersion + 1); } getNextMinorStableBranch() { return this.isStable && this.minorVersion != null - ? this.stableBranchNamePattern - .replace('', this.majorVersion.toString()) - .replace('', (this.minorVersion + 1).toString()) + ? this.getNextNotIgnoredStableBranch(this.majorVersion, this.minorVersion + 1) : ''; } getNextMinorDevBranch() { - return this.isStable - ? this.devBranchNamePattern.replace('', this.majorVersion.toString()) - : ''; + if (!this.isStable) { + return ''; + } + const nextBranchName = this.devBranchNamePattern.replace('', this.majorVersion.toString()); + // If the next minor dev branch is ignored, return an empty string to skip this branch + return this.ignoredBranches.includes(nextBranchName) ? '' : nextBranchName; + } + getNextNotIgnoredStableBranch(majorVersion, minorVersion) { + let nextMinorVersion = minorVersion; + let nextBranchName; + do { + nextBranchName = this.stableBranchNamePattern + .replace('', majorVersion.toString()) + .replace('', nextMinorVersion.toString()); + nextMinorVersion++; + } while (this.ignoredBranches.includes(nextBranchName)); + return nextBranchName; + } + getNextNotIgnoredDevBranch(majorVersion) { + let nextMajorVersion = majorVersion; + let nextBranchName; + do { + nextBranchName = this.devBranchNamePattern.replace('', nextMajorVersion.toString()); + nextMajorVersion++; + } while (this.ignoredBranches.includes(nextBranchName)); + return nextBranchName; } async getNextBranchName(fallbackBranch) { // Assemble candidate branches, skipping empty branch names @@ -25690,15 +25711,18 @@ class Inputs { devBranchNamePattern; fallbackBranch; enableAutoMerge; - constructor(currentBranch, stableBranchNamePattern, devBranchNamePattern, fallbackBranch, enableAutoMerge) { + ignoredBranches; + constructor(currentBranch, stableBranchNamePattern, devBranchNamePattern, fallbackBranch, enableAutoMerge, ignoredBranches) { this.currentBranch = currentBranch; this.stableBranchNamePattern = stableBranchNamePattern; this.devBranchNamePattern = devBranchNamePattern; this.fallbackBranch = fallbackBranch; this.enableAutoMerge = enableAutoMerge; + this.ignoredBranches = ignoredBranches; } static fromActionsInput(includeAutoMergeOption = true) { - return new Inputs(core.getInput('ref'), core.getInput('branchNamePattern'), core.getInput('devBranchNamePattern'), core.getInput('fallbackBranch'), includeAutoMergeOption ? core.getBooleanInput('enableAutoMerge') : false); + const ignoredBranches = core.getInput('ignoredBranches'); + return new Inputs(core.getInput('ref'), core.getInput('branchNamePattern'), core.getInput('devBranchNamePattern'), core.getInput('fallbackBranch'), includeAutoMergeOption ? core.getBooleanInput('enableAutoMerge') : false, ignoredBranches ? JSON.parse(ignoredBranches) : []); } } exports.Inputs = Inputs; @@ -25850,7 +25874,7 @@ async function getNextBranch() { core.setOutput('branchName', nextBranchName); } async function getNextBranchName(inputs) { - const branch = new branch_1.Branch(inputs.currentBranch, inputs.stableBranchNamePattern, inputs.devBranchNamePattern); + const branch = new branch_1.Branch(inputs.currentBranch, inputs.stableBranchNamePattern, inputs.devBranchNamePattern, inputs.ignoredBranches); core.debug(`Matched the following versions in branch name "${branch.name}" with patterns "${branch.stableBranchNamePattern}", "${branch.devBranchNamePattern}":`); core.debug(`Major version: ${branch.majorVersion}`); core.debug(`Minor version: ${branch.minorVersion}`); diff --git a/dist/get-next-branch/index.js b/dist/get-next-branch/index.js index d86b904..92e2816 100644 --- a/dist/get-next-branch/index.js +++ b/dist/get-next-branch/index.js @@ -25426,11 +25426,13 @@ class Branch { minorVersion; stableBranchNamePattern; devBranchNamePattern; + ignoredBranches; isStable = true; - constructor(name, stableBranchNamePattern, devBranchNamePattern) { + constructor(name, stableBranchNamePattern, devBranchNamePattern, ignoredBranches) { this.name = name; this.stableBranchNamePattern = stableBranchNamePattern; this.devBranchNamePattern = devBranchNamePattern; + this.ignoredBranches = ignoredBranches; const stableBranchPatternRegex = (0, regex_1.createRegexFromPattern)(stableBranchNamePattern); const devBranchPatternRegex = (0, regex_1.createRegexFromPattern)(devBranchNamePattern); let versions = name.match(stableBranchPatternRegex); @@ -25447,24 +25449,43 @@ class Branch { this.minorVersion = versions[2] ? Number(versions[2]) : null; } getNextMajorStableBranch() { - return this.stableBranchNamePattern - .replace('', (this.majorVersion + 1).toString()) - .replace('', '0'); + return this.getNextNotIgnoredStableBranch(this.majorVersion + 1, 0); } getNextMajorDevBranch() { - return this.devBranchNamePattern.replace('', (this.majorVersion + 1).toString()); + return this.getNextNotIgnoredDevBranch(this.majorVersion + 1); } getNextMinorStableBranch() { return this.isStable && this.minorVersion != null - ? this.stableBranchNamePattern - .replace('', this.majorVersion.toString()) - .replace('', (this.minorVersion + 1).toString()) + ? this.getNextNotIgnoredStableBranch(this.majorVersion, this.minorVersion + 1) : ''; } getNextMinorDevBranch() { - return this.isStable - ? this.devBranchNamePattern.replace('', this.majorVersion.toString()) - : ''; + if (!this.isStable) { + return ''; + } + const nextBranchName = this.devBranchNamePattern.replace('', this.majorVersion.toString()); + // If the next minor dev branch is ignored, return an empty string to skip this branch + return this.ignoredBranches.includes(nextBranchName) ? '' : nextBranchName; + } + getNextNotIgnoredStableBranch(majorVersion, minorVersion) { + let nextMinorVersion = minorVersion; + let nextBranchName; + do { + nextBranchName = this.stableBranchNamePattern + .replace('', majorVersion.toString()) + .replace('', nextMinorVersion.toString()); + nextMinorVersion++; + } while (this.ignoredBranches.includes(nextBranchName)); + return nextBranchName; + } + getNextNotIgnoredDevBranch(majorVersion) { + let nextMajorVersion = majorVersion; + let nextBranchName; + do { + nextBranchName = this.devBranchNamePattern.replace('', nextMajorVersion.toString()); + nextMajorVersion++; + } while (this.ignoredBranches.includes(nextBranchName)); + return nextBranchName; } async getNextBranchName(fallbackBranch) { // Assemble candidate branches, skipping empty branch names @@ -25690,15 +25711,18 @@ class Inputs { devBranchNamePattern; fallbackBranch; enableAutoMerge; - constructor(currentBranch, stableBranchNamePattern, devBranchNamePattern, fallbackBranch, enableAutoMerge) { + ignoredBranches; + constructor(currentBranch, stableBranchNamePattern, devBranchNamePattern, fallbackBranch, enableAutoMerge, ignoredBranches) { this.currentBranch = currentBranch; this.stableBranchNamePattern = stableBranchNamePattern; this.devBranchNamePattern = devBranchNamePattern; this.fallbackBranch = fallbackBranch; this.enableAutoMerge = enableAutoMerge; + this.ignoredBranches = ignoredBranches; } static fromActionsInput(includeAutoMergeOption = true) { - return new Inputs(core.getInput('ref'), core.getInput('branchNamePattern'), core.getInput('devBranchNamePattern'), core.getInput('fallbackBranch'), includeAutoMergeOption ? core.getBooleanInput('enableAutoMerge') : false); + const ignoredBranches = core.getInput('ignoredBranches'); + return new Inputs(core.getInput('ref'), core.getInput('branchNamePattern'), core.getInput('devBranchNamePattern'), core.getInput('fallbackBranch'), includeAutoMergeOption ? core.getBooleanInput('enableAutoMerge') : false, ignoredBranches ? JSON.parse(ignoredBranches) : []); } } exports.Inputs = Inputs; @@ -25850,7 +25874,7 @@ async function getNextBranch() { core.setOutput('branchName', nextBranchName); } async function getNextBranchName(inputs) { - const branch = new branch_1.Branch(inputs.currentBranch, inputs.stableBranchNamePattern, inputs.devBranchNamePattern); + const branch = new branch_1.Branch(inputs.currentBranch, inputs.stableBranchNamePattern, inputs.devBranchNamePattern, inputs.ignoredBranches); core.debug(`Matched the following versions in branch name "${branch.name}" with patterns "${branch.stableBranchNamePattern}", "${branch.devBranchNamePattern}":`); core.debug(`Major version: ${branch.majorVersion}`); core.debug(`Minor version: ${branch.minorVersion}`); diff --git a/get-next-branch/action.yml b/get-next-branch/action.yml index 430ed3c..b599b8a 100644 --- a/get-next-branch/action.yml +++ b/get-next-branch/action.yml @@ -21,6 +21,10 @@ inputs: description: 'A branch to fall back on if no next branch matching the pattern was found' required: false + ignoredBranches: + description: 'JSON list of branches to ignore' + required: false + default: '[]' outputs: hasNextBranch: diff --git a/src/branch.ts b/src/branch.ts index 75df45f..df6bb8a 100644 --- a/src/branch.ts +++ b/src/branch.ts @@ -7,16 +7,19 @@ export class Branch { readonly minorVersion: number | null readonly stableBranchNamePattern: string readonly devBranchNamePattern: string + readonly ignoredBranches: string[] readonly isStable: boolean = true constructor( name: string, stableBranchNamePattern: string, - devBranchNamePattern: string + devBranchNamePattern: string, + ignoredBranches: string[] ) { this.name = name this.stableBranchNamePattern = stableBranchNamePattern this.devBranchNamePattern = devBranchNamePattern + this.ignoredBranches = ignoredBranches const stableBranchPatternRegex = createRegexFromPattern( stableBranchNamePattern @@ -43,33 +46,66 @@ export class Branch { } getNextMajorStableBranch(): string { - return this.stableBranchNamePattern - .replace('', (this.majorVersion + 1).toString()) - .replace('', '0') + return this.getNextNotIgnoredStableBranch(this.majorVersion + 1, 0) } getNextMajorDevBranch(): string { - return this.devBranchNamePattern.replace( - '', - (this.majorVersion + 1).toString() - ) + return this.getNextNotIgnoredDevBranch(this.majorVersion + 1) } getNextMinorStableBranch(): string { return this.isStable && this.minorVersion != null - ? this.stableBranchNamePattern - .replace('', this.majorVersion.toString()) - .replace('', (this.minorVersion + 1).toString()) + ? this.getNextNotIgnoredStableBranch( + this.majorVersion, + this.minorVersion + 1 + ) : '' } getNextMinorDevBranch(): string { - return this.isStable - ? this.devBranchNamePattern.replace( - '', - this.majorVersion.toString() - ) - : '' + if (!this.isStable) { + return '' + } + + const nextBranchName = this.devBranchNamePattern.replace( + '', + this.majorVersion.toString() + ) + + // If the next minor dev branch is ignored, return an empty string to skip this branch + return this.ignoredBranches.includes(nextBranchName) ? '' : nextBranchName + } + + getNextNotIgnoredStableBranch( + majorVersion: number, + minorVersion: number + ): string { + let nextMinorVersion = minorVersion + let nextBranchName: string + + do { + nextBranchName = this.stableBranchNamePattern + .replace('', majorVersion.toString()) + .replace('', nextMinorVersion.toString()) + nextMinorVersion++ + } while (this.ignoredBranches.includes(nextBranchName)) + + return nextBranchName + } + + getNextNotIgnoredDevBranch(majorVersion: number): string { + let nextMajorVersion = majorVersion + let nextBranchName: string + + do { + nextBranchName = this.devBranchNamePattern.replace( + '', + nextMajorVersion.toString() + ) + nextMajorVersion++ + } while (this.ignoredBranches.includes(nextBranchName)) + + return nextBranchName } async getNextBranchName(fallbackBranch: string): Promise { diff --git a/src/inputs.ts b/src/inputs.ts index 25d3bb6..7d50fdf 100644 --- a/src/inputs.ts +++ b/src/inputs.ts @@ -6,28 +6,34 @@ export class Inputs { readonly devBranchNamePattern: string readonly fallbackBranch: string readonly enableAutoMerge: boolean + readonly ignoredBranches: string[] constructor( currentBranch: string, stableBranchNamePattern: string, devBranchNamePattern: string, fallbackBranch: string, - enableAutoMerge: boolean + enableAutoMerge: boolean, + ignoredBranches: string[] ) { this.currentBranch = currentBranch this.stableBranchNamePattern = stableBranchNamePattern this.devBranchNamePattern = devBranchNamePattern this.fallbackBranch = fallbackBranch this.enableAutoMerge = enableAutoMerge + this.ignoredBranches = ignoredBranches } static fromActionsInput(includeAutoMergeOption = true): Inputs { + const ignoredBranches = core.getInput('ignoredBranches') + return new Inputs( core.getInput('ref'), core.getInput('branchNamePattern'), core.getInput('devBranchNamePattern'), core.getInput('fallbackBranch'), - includeAutoMergeOption ? core.getBooleanInput('enableAutoMerge') : false + includeAutoMergeOption ? core.getBooleanInput('enableAutoMerge') : false, + ignoredBranches ? JSON.parse(ignoredBranches) : [] ) } } diff --git a/src/main.ts b/src/main.ts index 89c8146..9544f17 100644 --- a/src/main.ts +++ b/src/main.ts @@ -129,7 +129,8 @@ async function getNextBranchName(inputs: Inputs): Promise { const branch = new Branch( inputs.currentBranch, inputs.stableBranchNamePattern, - inputs.devBranchNamePattern + inputs.devBranchNamePattern, + inputs.ignoredBranches ) core.debug(