From 8af3e39b9731627e5a3a3878355ab6dfed44a6a0 Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Fri, 8 Oct 2021 10:04:29 -0700 Subject: [PATCH] fix(ng-dev): allow deprecations in PRs during feature freeze Currently our tooling does not distinguish between when RC is occurring and when feature freeze is occurring. Since they are treated as the same state, we are unable to allow deprecations messages on feature freeze without allowing it during RC periods. By creating this distinction we can properly handle this case. --- ng-dev/caretaker/check/ci.spec.ts | 7 +- ng-dev/caretaker/check/ci.ts | 5 +- ng-dev/pr/common/targeting/labels.ts | 4 +- ng-dev/pr/common/targeting/target-label.ts | 12 ++- ng-dev/pr/common/validation/validations.ts | 4 +- ng-dev/pr/merge/integration.spec.ts | 10 ++- ng-dev/release/publish/test/common.spec.ts | 8 +- .../test/configure-next-as-major.spec.ts | 50 ++++++----- .../publish/test/cut-lts-patch.spec.ts | 58 +++++++----- .../publish/test/cut-new-patch.spec.ts | 56 +++++++----- .../publish/test/cut-next-prerelease.spec.ts | 56 +++++++----- ...lease-candidate-for-feature-freeze.spec.ts | 56 +++++++----- .../release/publish/test/cut-stable.spec.ts | 88 +++++++++++-------- .../move-next-into-feature-freeze.spec.ts | 67 ++++++++------ .../move-next-into-release-candidate.spec.ts | 67 ++++++++------ .../test/tag-recent-major-as-latest.spec.ts | 21 ++--- .../versioning/active-release-trains.ts | 27 ++++-- 17 files changed, 357 insertions(+), 239 deletions(-) diff --git a/ng-dev/caretaker/check/ci.spec.ts b/ng-dev/caretaker/check/ci.spec.ts index fb1041e3a..adf71aac6 100644 --- a/ng-dev/caretaker/check/ci.spec.ts +++ b/ng-dev/caretaker/check/ci.spec.ts @@ -89,7 +89,8 @@ describe('CiModule', () => { status: 'failed', }, ]); - fetchActiveReleaseTrainsSpy.and.resolveTo([]); + const trains = buildMockActiveReleaseTrains(true); + fetchActiveReleaseTrainsSpy.and.resolveTo(trains); const module = new CiModule({caretaker: {}, ...mockNgDevConfig}); Object.defineProperty(module, 'data', {value: fakeData}); @@ -113,9 +114,9 @@ function buildMockActiveReleaseTrains(withRc: boolean): versioning.ActiveRelease isMajor: false, version: new SemVer('0.0.0'), }; - return { + return new versioning.ActiveReleaseTrains({ releaseCandidate: withRc ? {branchName: 'rc-branch', ...baseResult} : null, latest: {branchName: 'latest-branch', ...baseResult}, next: {branchName: 'next-branch', ...baseResult}, - }; + }); } diff --git a/ng-dev/caretaker/check/ci.ts b/ng-dev/caretaker/check/ci.ts index 37e3f7980..7ef92ed07 100644 --- a/ng-dev/caretaker/check/ci.ts +++ b/ng-dev/caretaker/check/ci.ts @@ -36,9 +36,8 @@ export class CiModule extends BaseModule { ...this.git.remoteConfig, nextBranchName, }; - const releaseTrains = await fetchActiveReleaseTrains(repo); - - const ciResultPromises = Object.entries(releaseTrains).map( + const {latest, next, releaseCandidate} = await fetchActiveReleaseTrains(repo); + const ciResultPromises = Object.entries({releaseCandidate, latest, next}).map( async ([trainName, train]: [string, ReleaseTrain | null]) => { if (train === null) { return { diff --git a/ng-dev/pr/common/targeting/labels.ts b/ng-dev/pr/common/targeting/labels.ts index 82e54cee3..007cdee69 100644 --- a/ng-dev/pr/common/targeting/labels.ts +++ b/ng-dev/pr/common/targeting/labels.ts @@ -8,7 +8,7 @@ import {assertValidReleaseConfig, ReleaseConfig} from '../../../release/config/index'; import { - fetchActiveReleaseTrains, + ActiveReleaseTrains, getNextBranchName, isVersionBranch, ReleaseRepoWithApi, @@ -38,6 +38,7 @@ import {debug} from '../../../utils/console'; * NPM version data when LTS version branches are validated. */ export async function getTargetLabelsForActiveReleaseTrains( + {latest, releaseCandidate, next}: ActiveReleaseTrains, api: GithubClient, config: Partial<{github: GithubConfig; release: ReleaseConfig}>, ): Promise { @@ -50,7 +51,6 @@ export async function getTargetLabelsForActiveReleaseTrains( nextBranchName, api, }; - const {latest, releaseCandidate, next} = await fetchActiveReleaseTrains(repo); const targetLabels: TargetLabel[] = [ { diff --git a/ng-dev/pr/common/targeting/target-label.ts b/ng-dev/pr/common/targeting/target-label.ts index 0c8bb70f9..dab85043b 100644 --- a/ng-dev/pr/common/targeting/target-label.ts +++ b/ng-dev/pr/common/targeting/target-label.ts @@ -13,6 +13,7 @@ import {Commit} from '../../../commit-message/parse'; import {assertChangesAllowForTargetLabel} from '../validation/validations'; import {PullRequestFailure} from '../validation/failures'; import {GithubClient} from '../../../utils/git/github'; +import {fetchActiveReleaseTrains} from '../../../release/versioning'; /** * Enum capturing available target label names in the Angular organization. A target @@ -111,7 +112,14 @@ export async function getTargetBranchesForPullRequest( // can lazily compute branches for a target label and throw. e.g. if an invalid target // label is applied, we want to exit the script gracefully with an error message. try { - const targetLabels = await getTargetLabelsForActiveReleaseTrains(api, config); + const {mainBranchName, name, owner} = config.github; + const releaseTrains = await fetchActiveReleaseTrains({ + name, + nextBranchName: mainBranchName, + owner, + api, + }); + const targetLabels = await getTargetLabelsForActiveReleaseTrains(releaseTrains, api, config); const matchingLabel = await getMatchingTargetLabelForPullRequest( config.pullRequest, labelsOnPullRequest, @@ -119,7 +127,7 @@ export async function getTargetBranchesForPullRequest( ); const targetBranches = await getBranchesFromTargetLabel(matchingLabel, githubTargetBranch); - assertChangesAllowForTargetLabel(commits, matchingLabel, config.pullRequest); + assertChangesAllowForTargetLabel(commits, matchingLabel, config.pullRequest, releaseTrains); return targetBranches; } catch (error) { diff --git a/ng-dev/pr/common/validation/validations.ts b/ng-dev/pr/common/validation/validations.ts index fdae26c34..5256683df 100644 --- a/ng-dev/pr/common/validation/validations.ts +++ b/ng-dev/pr/common/validation/validations.ts @@ -16,6 +16,7 @@ import { PullRequestFromGithub, PullRequestStatus, } from '../fetch-pull-request'; +import {ActiveReleaseTrains} from '../../../release/versioning'; /** * Assert the commits provided are allowed to merge to the provided target label, @@ -26,6 +27,7 @@ export function assertChangesAllowForTargetLabel( commits: Commit[], label: TargetLabel, config: PullRequestConfig, + releaseTrains: ActiveReleaseTrains, ) { /** * List of commit scopes which are exempted from target label content requirements. i.e. no `feat` @@ -57,7 +59,7 @@ export function assertChangesAllowForTargetLabel( // Deprecations should not be merged into RC, patch or LTS branches. // https://semver.org/#spec-item-7. Deprecations should be part of // minor releases, or major releases according to SemVer. - if (hasDeprecations) { + if (hasDeprecations && !releaseTrains.isFeatureFreeze()) { throw PullRequestFailure.hasDeprecations(label); } break; diff --git a/ng-dev/pr/merge/integration.spec.ts b/ng-dev/pr/merge/integration.spec.ts index 1a4cfac55..096ae91dd 100644 --- a/ng-dev/pr/merge/integration.spec.ts +++ b/ng-dev/pr/merge/integration.spec.ts @@ -20,6 +20,7 @@ import { } from '../common/targeting/target-label'; import {fakeGithubPaginationResponse} from '../../utils/testing/github-interception'; import {getTargetLabelsForActiveReleaseTrains} from '../common/targeting/labels'; +import {fetchActiveReleaseTrains} from '../../release/versioning'; const API_ENDPOINT = `https://api.github.com`; @@ -103,7 +104,14 @@ describe('default target labels', () => { name: string, githubTargetBranch = 'master', ): Promise { - const targetLabels = await getTargetLabelsForActiveReleaseTrains(api, { + const {mainBranchName, name: repoName, owner} = githubConfig; + const releaseTrains = await fetchActiveReleaseTrains({ + name: repoName, + nextBranchName: mainBranchName, + owner, + api, + }); + const targetLabels = await getTargetLabelsForActiveReleaseTrains(releaseTrains, api, { github: githubConfig, release: releaseConfig, }); diff --git a/ng-dev/release/publish/test/common.spec.ts b/ng-dev/release/publish/test/common.spec.ts index e46aa236e..c114f74ce 100644 --- a/ng-dev/release/publish/test/common.spec.ts +++ b/ng-dev/release/publish/test/common.spec.ts @@ -33,18 +33,18 @@ import {getMockGitClient} from '../../../utils/testing'; import {SandboxGitRepo} from '../../../utils/testing'; describe('common release action logic', () => { - const baseReleaseTrains: ActiveReleaseTrains = { + const baseReleaseTrains = new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.1')), - }; + }); describe('version computation', () => { - const testReleaseTrain: ActiveReleaseTrains = { + const testReleaseTrain = new ActiveReleaseTrains({ releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.3')), next: new ReleaseTrain('master', parse('10.2.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.1')), - }; + }); it('should not modify release train versions and cause invalid other actions', async () => { const {releaseConfig, githubConfig} = getTestConfigurationsForAction(); diff --git a/ng-dev/release/publish/test/configure-next-as-major.spec.ts b/ng-dev/release/publish/test/configure-next-as-major.spec.ts index 5bcdee014..f2753d329 100644 --- a/ng-dev/release/publish/test/configure-next-as-major.spec.ts +++ b/ng-dev/release/publish/test/configure-next-as-major.spec.ts @@ -7,6 +7,7 @@ */ import {getBranchPushMatcher} from '../../../utils/testing'; +import {ActiveReleaseTrains} from '../../versioning'; import {ReleaseTrain} from '../../versioning/release-trains'; import {ConfigureNextAsMajorAction} from '../actions/configure-next-as-major'; import {parse, setupReleaseActionForTesting} from './test-utils/test-utils'; @@ -14,40 +15,49 @@ import {parse, setupReleaseActionForTesting} from './test-utils/test-utils'; describe('configure next as major action', () => { it('should be active if the next branch is for a minor', async () => { expect( - await ConfigureNextAsMajorAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.3')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await ConfigureNextAsMajorAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.3')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); it('should be active regardless of a feature-freeze/release-candidate train', async () => { expect( - await ConfigureNextAsMajorAction.isActive({ - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.1')), - next: new ReleaseTrain('master', parse('10.2.0-next.3')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await ConfigureNextAsMajorAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.1')), + next: new ReleaseTrain('master', parse('10.2.0-next.3')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); it('should not be active if the next branch is for a major', async () => { expect( - await ConfigureNextAsMajorAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('11.0.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await ConfigureNextAsMajorAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('11.0.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should compute proper version and create staging pull request', async () => { - const action = setupReleaseActionForTesting(ConfigureNextAsMajorAction, { - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.3')), - latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }); + const action = setupReleaseActionForTesting( + ConfigureNextAsMajorAction, + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.3')), + latest: new ReleaseTrain('10.0.x', parse('10.0.2')), + }), + ); const {repo, fork, gitClient} = action; const expectedVersion = `11.0.0-next.0`; diff --git a/ng-dev/release/publish/test/cut-lts-patch.spec.ts b/ng-dev/release/publish/test/cut-lts-patch.spec.ts index 39ad09176..82147295d 100644 --- a/ng-dev/release/publish/test/cut-lts-patch.spec.ts +++ b/ng-dev/release/publish/test/cut-lts-patch.spec.ts @@ -25,44 +25,54 @@ import {readFileSync} from 'fs'; import {testTmpDir} from '../../../utils/testing'; import {SandboxGitRepo} from '../../../utils/testing'; import {getMockGitClient} from '../../../utils/testing'; +import {ActiveReleaseTrains} from '../../versioning'; describe('cut an LTS patch action', () => { it('should be active', async () => { expect( - await CutLongTermSupportPatchAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.3')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutLongTermSupportPatchAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.3')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); it('should be active if there is a feature-freeze train', async () => { expect( - await CutLongTermSupportPatchAction.isActive({ - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.3')), - next: new ReleaseTrain('master', parse('10.2.0-next.3')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutLongTermSupportPatchAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.3')), + next: new ReleaseTrain('master', parse('10.2.0-next.3')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); it('should be active if there is a release-candidate train', async () => { expect( - await CutLongTermSupportPatchAction.isActive({ - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.3')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutLongTermSupportPatchAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.3')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); it('should compute proper new version and select correct branch', async () => { - const action = setupReleaseActionForTesting(CutLongTermSupportPatchAction, { - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.3')), - latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }); + const action = setupReleaseActionForTesting( + CutLongTermSupportPatchAction, + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.3')), + latest: new ReleaseTrain('10.0.x', parse('10.0.2')), + }), + ); spyOn(action.instance, '_promptForTargetLtsBranch').and.resolveTo({ name: '9.2.x', @@ -76,11 +86,11 @@ describe('cut an LTS patch action', () => { it('should generate release notes capturing changes to previous latest LTS version', async () => { const action = setupReleaseActionForTesting( CutLongTermSupportPatchAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.3')), latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }, + }), true, {useSandboxGitClient: true}, ); @@ -118,11 +128,11 @@ describe('cut an LTS patch action', () => { it('should include number of active LTS branches in action description', async () => { const {releaseConfig, githubConfig} = getTestConfigurationsForAction(); const gitClient = getMockGitClient(githubConfig, /* useSandboxGitClient */ false); - const activeReleaseTrains = { + const activeReleaseTrains = new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.3')), latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }; + }); fakeNpmPackageQueryRequest(releaseConfig.npmPackages[0], { 'dist-tags': {'v9-lts': '9.1.2', 'v8-lts': '8.2.2'}, diff --git a/ng-dev/release/publish/test/cut-new-patch.spec.ts b/ng-dev/release/publish/test/cut-new-patch.spec.ts index 72173480e..37ac6c937 100644 --- a/ng-dev/release/publish/test/cut-new-patch.spec.ts +++ b/ng-dev/release/publish/test/cut-new-patch.spec.ts @@ -16,44 +16,56 @@ import { import {readFileSync} from 'fs'; import {testTmpDir} from '../../../utils/testing'; import {SandboxGitRepo} from '../../../utils/testing'; +import {ActiveReleaseTrains} from '../../versioning'; describe('cut new patch action', () => { it('should be active', async () => { expect( - await CutNewPatchAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.3')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutNewPatchAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.3')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); it('should compute proper new version and select correct branch', async () => { - const action = setupReleaseActionForTesting(CutNewPatchAction, { - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.3')), - latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }); + const action = setupReleaseActionForTesting( + CutNewPatchAction, + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.3')), + latest: new ReleaseTrain('10.0.x', parse('10.0.2')), + }), + ); await expectStagingAndPublishWithCherryPick(action, '10.0.x', '10.0.3', 'latest'); }); it('should create a proper new version if there is a feature-freeze release-train', async () => { - const action = setupReleaseActionForTesting(CutNewPatchAction, { - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.3')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.9')), - }); + const action = setupReleaseActionForTesting( + CutNewPatchAction, + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.3')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.9')), + }), + ); await expectStagingAndPublishWithCherryPick(action, '10.0.x', '10.0.10', 'latest'); }); it('should create a proper new version if there is a release-candidate train', async () => { - const action = setupReleaseActionForTesting(CutNewPatchAction, { - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.9')), - }); + const action = setupReleaseActionForTesting( + CutNewPatchAction, + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.9')), + }), + ); await expectStagingAndPublishWithCherryPick(action, '10.0.x', '10.0.10', 'latest'); }); @@ -61,11 +73,11 @@ describe('cut new patch action', () => { it('should generate release notes capturing changes to the previous latest patch version', async () => { const action = setupReleaseActionForTesting( CutNewPatchAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.3')), latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }, + }), true, {useSandboxGitClient: true}, ); diff --git a/ng-dev/release/publish/test/cut-next-prerelease.spec.ts b/ng-dev/release/publish/test/cut-next-prerelease.spec.ts index 6243241f7..b4c57c87f 100644 --- a/ng-dev/release/publish/test/cut-next-prerelease.spec.ts +++ b/ng-dev/release/publish/test/cut-next-prerelease.spec.ts @@ -20,6 +20,7 @@ import { } from './test-utils/staging-test'; import {testTmpDir} from '../../../utils/testing'; import {SandboxGitRepo} from '../../../utils/testing'; +import {ActiveReleaseTrains} from '../../versioning'; describe('cut next pre-release action', () => { it('should always be active regardless of release-trains', async () => { @@ -27,11 +28,14 @@ describe('cut next pre-release action', () => { }); it('should cut a pre-release for the next branch if there is no FF/RC branch', async () => { - const action = setupReleaseActionForTesting(CutNextPrereleaseAction, { - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.1.x', parse('10.1.2')), - }); + const action = setupReleaseActionForTesting( + CutNextPrereleaseAction, + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.1.x', parse('10.1.2')), + }), + ); await expectStagingAndPublishWithoutCherryPick(action, 'master', '10.2.0-next.1', 'next'); }); @@ -47,11 +51,11 @@ describe('cut next pre-release action', () => { it('should not bump the version', async () => { const action = setupReleaseActionForTesting( CutNextPrereleaseAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.2.0-next.0')), latest: new ReleaseTrain('10.1.x', parse('10.1.0')), - }, + }), /* isNextPublishedToNpm */ false, ); @@ -68,11 +72,11 @@ describe('cut next pre-release action', () => { async () => { const action = setupReleaseActionForTesting( CutNextPrereleaseAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.2.0-next.0')), latest: new ReleaseTrain('10.1.x', parse('10.1.0')), - }, + }), /* isNextPublishedToNpm */ false, {useSandboxGitClient: true}, ); @@ -111,11 +115,14 @@ describe('cut next pre-release action', () => { describe('with active feature-freeze', () => { it('should create a proper new version and select correct branch', async () => { - const action = setupReleaseActionForTesting(CutNextPrereleaseAction, { - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.4')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }); + const action = setupReleaseActionForTesting( + CutNextPrereleaseAction, + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.4')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.2')), + }), + ); await expectStagingAndPublishWithCherryPick(action, '10.1.x', '10.1.0-next.5', 'next'); }); @@ -123,11 +130,11 @@ describe('cut next pre-release action', () => { it('should generate release notes capturing changes to the previous pre-release', async () => { const action = setupReleaseActionForTesting( CutNextPrereleaseAction, - { + new ActiveReleaseTrains({ releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.4')), next: new ReleaseTrain('master', parse('10.2.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }, + }), true, {useSandboxGitClient: true}, ); @@ -159,11 +166,14 @@ describe('cut next pre-release action', () => { describe('with active release-candidate', () => { it('should create a proper new version and select correct branch', async () => { - const action = setupReleaseActionForTesting(CutNextPrereleaseAction, { - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }); + const action = setupReleaseActionForTesting( + CutNextPrereleaseAction, + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.2')), + }), + ); await expectStagingAndPublishWithCherryPick(action, '10.1.x', '10.1.0-rc.1', 'next'); }); @@ -171,11 +181,11 @@ describe('cut next pre-release action', () => { it('should generate release notes capturing changes to the previous pre-release', async () => { const action = setupReleaseActionForTesting( CutNextPrereleaseAction, - { + new ActiveReleaseTrains({ releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), next: new ReleaseTrain('master', parse('10.2.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.2')), - }, + }), true, {useSandboxGitClient: true}, ); diff --git a/ng-dev/release/publish/test/cut-release-candidate-for-feature-freeze.spec.ts b/ng-dev/release/publish/test/cut-release-candidate-for-feature-freeze.spec.ts index 4241e8b4b..150535473 100644 --- a/ng-dev/release/publish/test/cut-release-candidate-for-feature-freeze.spec.ts +++ b/ng-dev/release/publish/test/cut-release-candidate-for-feature-freeze.spec.ts @@ -16,45 +16,55 @@ import { import {readFileSync} from 'fs'; import {testTmpDir} from '../../../utils/testing'; import {SandboxGitRepo} from '../../../utils/testing'; +import {ActiveReleaseTrains} from '../../versioning'; describe('cut release candidate for feature-freeze action', () => { it('should activate if a feature-freeze release-train is active', async () => { expect( - await CutReleaseCandidateForFeatureFreezeAction.isActive({ - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutReleaseCandidateForFeatureFreezeAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); it('should not activate if release-candidate release-train is active', async () => { expect( - await CutReleaseCandidateForFeatureFreezeAction.isActive({ - // No longer in feature-freeze but in release-candidate phase. - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutReleaseCandidateForFeatureFreezeAction.isActive( + new ActiveReleaseTrains({ + // No longer in feature-freeze but in release-candidate phase. + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should not activate if no FF/RC release-train is active', async () => { expect( - await CutReleaseCandidateForFeatureFreezeAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutReleaseCandidateForFeatureFreezeAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should create a proper new version and select correct branch', async () => { - const action = setupReleaseActionForTesting(CutReleaseCandidateForFeatureFreezeAction, { - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }); + const action = setupReleaseActionForTesting( + CutReleaseCandidateForFeatureFreezeAction, + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ); await expectStagingAndPublishWithCherryPick(action, '10.1.x', '10.1.0-rc.0', 'next'); }); @@ -62,11 +72,11 @@ describe('cut release candidate for feature-freeze action', () => { it('should generate release notes capturing changes to the previous pre-release', async () => { const action = setupReleaseActionForTesting( CutReleaseCandidateForFeatureFreezeAction, - { + new ActiveReleaseTrains({ releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), next: new ReleaseTrain('master', parse('10.2.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), true, {useSandboxGitClient: true}, ); diff --git a/ng-dev/release/publish/test/cut-stable.spec.ts b/ng-dev/release/publish/test/cut-stable.spec.ts index cd692230d..f645d2a24 100644 --- a/ng-dev/release/publish/test/cut-stable.spec.ts +++ b/ng-dev/release/publish/test/cut-stable.spec.ts @@ -19,69 +19,85 @@ import { } from './test-utils/staging-test'; import {testTmpDir} from '../../../utils/testing'; import {SandboxGitRepo} from '../../../utils/testing'; +import {ActiveReleaseTrains} from '../../versioning'; describe('cut stable action', () => { it('should not activate if a feature-freeze release-train is active', async () => { expect( - await CutStableAction.isActive({ - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutStableAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should activate if release-candidate release-train is active', async () => { expect( - await CutStableAction.isActive({ - // No longer in feature-freeze but in release-candidate phase. - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutStableAction.isActive( + new ActiveReleaseTrains({ + // No longer in feature-freeze but in release-candidate phase. + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); it('should not activate if no FF/RC release-train is active', async () => { expect( - await CutStableAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await CutStableAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should create a proper new version and select correct branch', async () => { - const action = setupReleaseActionForTesting(CutStableAction, { - // No longer in feature-freeze but in release-candidate phase. - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }); + const action = setupReleaseActionForTesting( + CutStableAction, + new ActiveReleaseTrains({ + // No longer in feature-freeze but in release-candidate phase. + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ); await expectStagingAndPublishWithCherryPick(action, '10.1.x', '10.1.0', 'latest'); }); it('should not tag the previous latest release-train if a minor has been cut', async () => { - const action = setupReleaseActionForTesting(CutStableAction, { - // No longer in feature-freeze but in release-candidate phase. - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }); + const action = setupReleaseActionForTesting( + CutStableAction, + new ActiveReleaseTrains({ + // No longer in feature-freeze but in release-candidate phase. + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ); await expectStagingAndPublishWithCherryPick(action, '10.1.x', '10.1.0', 'latest'); expect(externalCommands.invokeSetNpmDistCommand).toHaveBeenCalledTimes(0); }); it('should tag the previous latest release-train if a major has been cut', async () => { - const action = setupReleaseActionForTesting(CutStableAction, { - // No longer in feature-freeze but in release-candidate phase. - releaseCandidate: new ReleaseTrain('11.0.x', parse('11.0.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }); + const action = setupReleaseActionForTesting( + CutStableAction, + new ActiveReleaseTrains({ + // No longer in feature-freeze but in release-candidate phase. + releaseCandidate: new ReleaseTrain('11.0.x', parse('11.0.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ); // Ensure that the NPM dist tag is set only for packages that were available in the previous // major version. A spy has already been installed on the function. @@ -106,11 +122,11 @@ describe('cut stable action', () => { async () => { const action = setupReleaseActionForTesting( CutStableAction, - { + new ActiveReleaseTrains({ releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), next: new ReleaseTrain('master', parse('10.2.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), true, {useSandboxGitClient: true}, ); diff --git a/ng-dev/release/publish/test/move-next-into-feature-freeze.spec.ts b/ng-dev/release/publish/test/move-next-into-feature-freeze.spec.ts index 29787b23a..fa45d5422 100644 --- a/ng-dev/release/publish/test/move-next-into-feature-freeze.spec.ts +++ b/ng-dev/release/publish/test/move-next-into-feature-freeze.spec.ts @@ -7,6 +7,7 @@ */ import {SandboxGitRepo} from '../../../utils/testing'; +import {ActiveReleaseTrains} from '../../versioning'; import {ReleaseTrain} from '../../versioning/release-trains'; import {MoveNextIntoFeatureFreezeAction} from '../actions/move-next-into-feature-freeze'; @@ -19,53 +20,61 @@ import {changelogPattern, parse} from './test-utils/test-utils'; describe('move next into feature-freeze action', () => { it('should not activate if a feature-freeze release-train is active', async () => { expect( - await MoveNextIntoFeatureFreezeAction.isActive({ - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await MoveNextIntoFeatureFreezeAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should not activate if release-candidate release-train is active', async () => { expect( - await MoveNextIntoFeatureFreezeAction.isActive({ - // No longer in feature-freeze but in release-candidate phase. - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await MoveNextIntoFeatureFreezeAction.isActive( + new ActiveReleaseTrains({ + // No longer in feature-freeze but in release-candidate phase. + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should not activate if the next release-train is for a minor', async () => { expect( - await MoveNextIntoFeatureFreezeAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.2')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await MoveNextIntoFeatureFreezeAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.2')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should activate if no FF/RC release-train is active', async () => { expect( - await MoveNextIntoFeatureFreezeAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('11.0.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await MoveNextIntoFeatureFreezeAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('11.0.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); it('should create pull requests and feature-freeze branch', async () => { await expectBranchOffActionToRun( MoveNextIntoFeatureFreezeAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), /* isNextPublishedToNpm */ true, '10.2.0-next.0', '10.1.0-next.1', @@ -81,11 +90,11 @@ describe('move next into feature-freeze action', () => { it('should not increment the version', async () => { await expectBranchOffActionToRun( MoveNextIntoFeatureFreezeAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), /* isNextPublishedToNpm */ false, '10.2.0-next.0', '10.1.0-next.0', @@ -99,11 +108,11 @@ describe('move next into feature-freeze action', () => { async () => { const {action, buildChangelog} = prepareBranchOffActionForChangelog( MoveNextIntoFeatureFreezeAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), /* isNextPublishedToNpm */ false, '10.2.0-next.0', '10.1.0-next.0', @@ -139,11 +148,11 @@ describe('move next into feature-freeze action', () => { it('should generate release notes capturing changes to the previous next pre-release', async () => { const {action, buildChangelog} = prepareBranchOffActionForChangelog( MoveNextIntoFeatureFreezeAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), /* isNextPublishedToNpm */ true, '10.2.0-next.0', '10.1.0-next.1', diff --git a/ng-dev/release/publish/test/move-next-into-release-candidate.spec.ts b/ng-dev/release/publish/test/move-next-into-release-candidate.spec.ts index 7cc0bece6..eabe0e1ad 100644 --- a/ng-dev/release/publish/test/move-next-into-release-candidate.spec.ts +++ b/ng-dev/release/publish/test/move-next-into-release-candidate.spec.ts @@ -7,6 +7,7 @@ */ import {SandboxGitRepo} from '../../../utils/testing'; +import {ActiveReleaseTrains} from '../../versioning'; import {ReleaseTrain} from '../../versioning/release-trains'; import {MoveNextIntoReleaseCandidateAction} from '../actions/move-next-into-release-candidate'; @@ -19,42 +20,50 @@ import {changelogPattern, parse} from './test-utils/test-utils'; describe('move next into release-candidate action', () => { it('should not activate if a feature-freeze release-train is active', async () => { expect( - await MoveNextIntoReleaseCandidateAction.isActive({ - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await MoveNextIntoReleaseCandidateAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-next.1')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should not activate if release-candidate release-train is active', async () => { expect( - await MoveNextIntoReleaseCandidateAction.isActive({ - // No longer in feature-freeze but in release-candidate phase. - releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), - next: new ReleaseTrain('master', parse('10.2.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await MoveNextIntoReleaseCandidateAction.isActive( + new ActiveReleaseTrains({ + // No longer in feature-freeze but in release-candidate phase. + releaseCandidate: new ReleaseTrain('10.1.x', parse('10.1.0-rc.0')), + next: new ReleaseTrain('master', parse('10.2.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should not activate if the next release-train is for a major', async () => { expect( - await MoveNextIntoReleaseCandidateAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('11.0.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await MoveNextIntoReleaseCandidateAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('11.0.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(false); }); it('should activate if no FF/RC release-train is active', async () => { expect( - await MoveNextIntoReleaseCandidateAction.isActive({ - releaseCandidate: null, - next: new ReleaseTrain('master', parse('10.1.0-next.0')), - latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }), + await MoveNextIntoReleaseCandidateAction.isActive( + new ActiveReleaseTrains({ + releaseCandidate: null, + next: new ReleaseTrain('master', parse('10.1.0-next.0')), + latest: new ReleaseTrain('10.0.x', parse('10.0.3')), + }), + ), ).toBe(true); }); @@ -64,11 +73,11 @@ describe('move next into release-candidate action', () => { it('should update the version regardless', async () => { await expectBranchOffActionToRun( MoveNextIntoReleaseCandidateAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), /* isNextPublishedToNpm */ false, '10.2.0-next.0', '10.1.0-rc.0', @@ -82,11 +91,11 @@ describe('move next into release-candidate action', () => { async () => { const {action, buildChangelog} = prepareBranchOffActionForChangelog( MoveNextIntoReleaseCandidateAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), /* isNextPublishedToNpm */ false, '10.2.0-next.0', '10.1.0-rc.0', @@ -122,11 +131,11 @@ describe('move next into release-candidate action', () => { it('should generate release notes capturing changes to the previous next pre-release', async () => { const {action, buildChangelog} = prepareBranchOffActionForChangelog( MoveNextIntoReleaseCandidateAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), /* isNextPublishedToNpm */ true, '10.2.0-next.0', '10.1.0-rc.0', @@ -154,11 +163,11 @@ describe('move next into release-candidate action', () => { it('should create pull requests and new version-branch', async () => { await expectBranchOffActionToRun( MoveNextIntoReleaseCandidateAction, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.3')), - }, + }), /* isNextPublishedToNpm */ true, '10.2.0-next.0', '10.1.0-rc.0', diff --git a/ng-dev/release/publish/test/tag-recent-major-as-latest.spec.ts b/ng-dev/release/publish/test/tag-recent-major-as-latest.spec.ts index 7bf7fae56..b7622ea1e 100644 --- a/ng-dev/release/publish/test/tag-recent-major-as-latest.spec.ts +++ b/ng-dev/release/publish/test/tag-recent-major-as-latest.spec.ts @@ -7,6 +7,7 @@ */ import {matchesVersion} from '../../../utils/testing'; +import {ActiveReleaseTrains} from '../../versioning'; import {ReleaseTrain} from '../../versioning/release-trains'; import {TagRecentMajorAsLatest} from '../actions/tag-recent-major-as-latest'; import * as externalCommands from '../external-commands'; @@ -22,11 +23,11 @@ describe('tag recent major as latest action', () => { const {releaseConfig} = getTestConfigurationsForAction(); expect( await TagRecentMajorAsLatest.isActive( - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.1')), - }, + }), releaseConfig, ), ).toBe(false); @@ -47,11 +48,11 @@ describe('tag recent major as latest action', () => { expect( await TagRecentMajorAsLatest.isActive( - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.0')), - }, + }), releaseConfig, ), ).toBe(false); @@ -74,11 +75,11 @@ describe('tag recent major as latest action', () => { expect( await TagRecentMajorAsLatest.isActive( - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.0')), - }, + }), releaseConfig, ), ).toBe(false); @@ -98,11 +99,11 @@ describe('tag recent major as latest action', () => { expect( await TagRecentMajorAsLatest.isActive( - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.0')), - }, + }), releaseConfig, ), ).toBe(true); @@ -112,11 +113,11 @@ describe('tag recent major as latest action', () => { it('should re-tag the version in the NPM registry and update the Github release', async () => { const {instance, gitClient, releaseConfig, repo} = setupReleaseActionForTesting( TagRecentMajorAsLatest, - { + new ActiveReleaseTrains({ releaseCandidate: null, next: new ReleaseTrain('master', parse('10.1.0-next.0')), latest: new ReleaseTrain('10.0.x', parse('10.0.0')), - }, + }), ); // NPM `@latest` will point to a patch release of the previous major. diff --git a/ng-dev/release/versioning/active-release-trains.ts b/ng-dev/release/versioning/active-release-trains.ts index c549b9ba4..434da86fc 100644 --- a/ng-dev/release/versioning/active-release-trains.ts +++ b/ng-dev/release/versioning/active-release-trains.ts @@ -16,14 +16,27 @@ import { VersionBranch, } from './version-branches'; -/** Interface describing determined active release trains for a project. */ -export interface ActiveReleaseTrains { +/** The active release trains for a project. */ +export class ActiveReleaseTrains { /** Release-train currently in the "release-candidate" or "feature-freeze" phase. */ - releaseCandidate: ReleaseTrain | null; - /** Release-train currently in the "latest" phase. */ - latest: ReleaseTrain; + readonly releaseCandidate: ReleaseTrain | null = this.trains.releaseCandidate || null; /** Release-train in the `next` phase. */ - next: ReleaseTrain; + readonly next: ReleaseTrain = this.trains.next; + /** Release-train currently in the "latest" phase. */ + readonly latest: ReleaseTrain = this.trains.latest; + + constructor( + private trains: { + releaseCandidate: ReleaseTrain | null; + next: ReleaseTrain; + latest: ReleaseTrain; + }, + ) {} + + /** Whether the active release trains indicate the repository is in a feature freeze state. */ + isFeatureFreeze() { + return this.releaseCandidate !== null && this.releaseCandidate.version.prerelease[0] === 'next'; + } } /** Fetches the active release trains for the configured project. */ @@ -78,7 +91,7 @@ export async function fetchActiveReleaseTrains( ); } - return {releaseCandidate, latest, next}; + return new ActiveReleaseTrains({releaseCandidate, next, latest}); } /** Finds the currently active release trains from the specified version branches. */