diff --git a/src/command-line-arguments.ts b/src/command-line-arguments.ts index fecac70..887ca89 100644 --- a/src/command-line-arguments.ts +++ b/src/command-line-arguments.ts @@ -5,7 +5,6 @@ export type CommandLineArguments = { projectDirectory: string; tempDirectory: string | undefined; reset: boolean; - backport: boolean; }; /** @@ -38,12 +37,6 @@ export async function readCommandLineArguments( type: 'boolean', default: false, }) - .option('backport', { - describe: - 'Instructs the tool to bump the second part of the version rather than the first for a backport release.', - type: 'boolean', - default: false, - }) .help() .strict() .parse(); diff --git a/src/functional.test.ts b/src/functional.test.ts index 45a35b7..08f8954 100644 --- a/src/functional.test.ts +++ b/src/functional.test.ts @@ -116,118 +116,6 @@ describe('create-release-branch (functional)', () => { ); }); - it('bumps the backport part of the root package and updates the versions of the specified packages according to the release spec if --backport is provided', async () => { - await withMonorepoProjectEnvironment( - { - packages: { - $root$: { - name: '@scope/monorepo', - version: '1.0.0', - directoryPath: '.', - }, - a: { - name: '@scope/a', - version: '0.1.2', - directoryPath: 'packages/a', - }, - b: { - name: '@scope/b', - version: '1.1.4', - directoryPath: 'packages/b', - }, - c: { - name: '@scope/c', - version: '2.0.13', - directoryPath: 'packages/c', - }, - d: { - name: '@scope/d', - version: '1.2.3', - directoryPath: 'packages/d', - }, - }, - workspaces: { - '.': ['packages/*'], - }, - }, - async (environment) => { - await environment.updateJsonFile('package.json', { - scripts: { - foo: 'bar', - }, - }); - await environment.updateJsonFileWithinPackage('a', 'package.json', { - scripts: { - foo: 'bar', - }, - }); - await environment.updateJsonFileWithinPackage('b', 'package.json', { - scripts: { - foo: 'bar', - }, - }); - await environment.updateJsonFileWithinPackage('c', 'package.json', { - scripts: { - foo: 'bar', - }, - }); - await environment.updateJsonFileWithinPackage('d', 'package.json', { - scripts: { - foo: 'bar', - }, - }); - - await environment.runTool({ - args: ['--backport'], - releaseSpecification: { - packages: { - a: 'major', - b: 'minor', - c: 'patch', - d: '1.2.4', - }, - }, - }); - - expect(await environment.readJsonFile('package.json')).toStrictEqual({ - name: '@scope/monorepo', - version: '1.1.0', - private: true, - workspaces: ['packages/*'], - scripts: { foo: 'bar' }, - }); - expect( - await environment.readJsonFileWithinPackage('a', 'package.json'), - ).toStrictEqual({ - name: '@scope/a', - version: '1.0.0', - scripts: { foo: 'bar' }, - }); - expect( - await environment.readJsonFileWithinPackage('b', 'package.json'), - ).toStrictEqual({ - name: '@scope/b', - version: '1.2.0', - scripts: { foo: 'bar' }, - }); - expect( - await environment.readJsonFileWithinPackage('c', 'package.json'), - ).toStrictEqual({ - name: '@scope/c', - version: '2.0.14', - scripts: { foo: 'bar' }, - }); - expect( - await environment.readJsonFileWithinPackage('d', 'package.json'), - ).toStrictEqual({ - name: '@scope/d', - version: '1.2.4', - scripts: { foo: 'bar' }, - }); - }, - ); - }); - it("updates each of the specified packages' changelogs by adding a new section which lists all commits concerning the package over the entire history of the repo", async () => { await withMonorepoProjectEnvironment( { diff --git a/src/initial-parameters.test.ts b/src/initial-parameters.test.ts index 7b76583..8a38a32 100644 --- a/src/initial-parameters.test.ts +++ b/src/initial-parameters.test.ts @@ -34,7 +34,6 @@ describe('initial-parameters', () => { projectDirectory: '/path/to/project', tempDirectory: '/path/to/temp', reset: true, - backport: false, }); jest .spyOn(envModule, 'getEnvironmentVariables') @@ -53,7 +52,6 @@ describe('initial-parameters', () => { project, tempDirectoryPath: '/path/to/temp', reset: true, - releaseType: 'ordinary', }); }); @@ -68,7 +66,6 @@ describe('initial-parameters', () => { projectDirectory: 'project', tempDirectory: undefined, reset: true, - backport: false, }); jest .spyOn(envModule, 'getEnvironmentVariables') @@ -97,7 +94,6 @@ describe('initial-parameters', () => { projectDirectory: '/path/to/project', tempDirectory: 'tmp', reset: true, - backport: false, }); jest .spyOn(envModule, 'getEnvironmentVariables') @@ -126,7 +122,6 @@ describe('initial-parameters', () => { projectDirectory: '/path/to/project', tempDirectory: undefined, reset: true, - backport: false, }); jest .spyOn(envModule, 'getEnvironmentVariables') @@ -155,7 +150,6 @@ describe('initial-parameters', () => { projectDirectory: '/path/to/project', tempDirectory: '/path/to/temp', reset: true, - backport: false, }); jest .spyOn(envModule, 'getEnvironmentVariables') @@ -182,7 +176,6 @@ describe('initial-parameters', () => { projectDirectory: '/path/to/project', tempDirectory: '/path/to/temp', reset: false, - backport: false, }); jest .spyOn(envModule, 'getEnvironmentVariables') @@ -199,59 +192,5 @@ describe('initial-parameters', () => { expect(initialParameters.reset).toBe(false); }); - - it('returns initial parameters including a releaseType of "backport", derived from a command-line argument of "--backport true"', async () => { - const project = buildMockProject(); - const stderr = createNoopWriteStream(); - when(jest.spyOn(commandLineArgumentsModule, 'readCommandLineArguments')) - .calledWith(['arg1', 'arg2']) - .mockResolvedValue({ - projectDirectory: '/path/to/project', - tempDirectory: '/path/to/temp', - reset: false, - backport: true, - }); - jest - .spyOn(envModule, 'getEnvironmentVariables') - .mockReturnValue({ EDITOR: undefined }); - when(jest.spyOn(projectModule, 'readProject')) - .calledWith('/path/to/project', { stderr }) - .mockResolvedValue(project); - - const initialParameters = await determineInitialParameters({ - argv: ['arg1', 'arg2'], - cwd: '/path/to/somewhere', - stderr, - }); - - expect(initialParameters.releaseType).toBe('backport'); - }); - - it('returns initial parameters including a releaseType of "ordinary", derived from a command-line argument of "--backport false"', async () => { - const project = buildMockProject(); - const stderr = createNoopWriteStream(); - when(jest.spyOn(commandLineArgumentsModule, 'readCommandLineArguments')) - .calledWith(['arg1', 'arg2']) - .mockResolvedValue({ - projectDirectory: '/path/to/project', - tempDirectory: '/path/to/temp', - reset: false, - backport: false, - }); - jest - .spyOn(envModule, 'getEnvironmentVariables') - .mockReturnValue({ EDITOR: undefined }); - when(jest.spyOn(projectModule, 'readProject')) - .calledWith('/path/to/project', { stderr }) - .mockResolvedValue(project); - - const initialParameters = await determineInitialParameters({ - argv: ['arg1', 'arg2'], - cwd: '/path/to/somewhere', - stderr, - }); - - expect(initialParameters.releaseType).toBe('ordinary'); - }); }); }); diff --git a/src/initial-parameters.ts b/src/initial-parameters.ts index a6086a3..381b7f0 100644 --- a/src/initial-parameters.ts +++ b/src/initial-parameters.ts @@ -4,22 +4,10 @@ import { readCommandLineArguments } from './command-line-arguments'; import { WriteStreamLike } from './fs'; import { readProject, Project } from './project'; -/** - * The type of release being created as determined by the parent release. - * - * - An *ordinary* release includes features or fixes applied against the - * latest release and is designated by bumping the first part of that release's - * version string. - * - A *backport* release includes fixes applied against a previous release and - * is designated by bumping the second part of that release's version string. - */ -export type ReleaseType = 'ordinary' | 'backport'; - type InitialParameters = { project: Project; tempDirectoryPath: string; reset: boolean; - releaseType: ReleaseType; }; /** @@ -58,6 +46,5 @@ export async function determineInitialParameters({ project, tempDirectoryPath, reset: args.reset, - releaseType: args.backport ? 'backport' : 'ordinary', }; } diff --git a/src/main.test.ts b/src/main.test.ts index 82dff54..df8a8b3 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -18,7 +18,6 @@ describe('main', () => { project, tempDirectoryPath: '/path/to/temp/directory', reset: true, - releaseType: 'backport', }); const followMonorepoWorkflowSpy = jest .spyOn(monorepoWorkflowOperations, 'followMonorepoWorkflow') @@ -35,7 +34,6 @@ describe('main', () => { project, tempDirectoryPath: '/path/to/temp/directory', firstRemovingExistingReleaseSpecification: true, - releaseType: 'backport', stdout, stderr, }); @@ -51,7 +49,6 @@ describe('main', () => { project, tempDirectoryPath: '/path/to/temp/directory', reset: false, - releaseType: 'backport', }); const followMonorepoWorkflowSpy = jest .spyOn(monorepoWorkflowOperations, 'followMonorepoWorkflow') diff --git a/src/main.ts b/src/main.ts index 7c5e876..e1a2568 100644 --- a/src/main.ts +++ b/src/main.ts @@ -25,7 +25,7 @@ export async function main({ stdout: Pick; stderr: Pick; }) { - const { project, tempDirectoryPath, reset, releaseType } = + const { project, tempDirectoryPath, reset } = await determineInitialParameters({ argv, cwd, stderr }); if (project.isMonorepo) { @@ -36,7 +36,6 @@ export async function main({ project, tempDirectoryPath, firstRemovingExistingReleaseSpecification: reset, - releaseType, stdout, stderr, }); diff --git a/src/monorepo-workflow-operations.test.ts b/src/monorepo-workflow-operations.test.ts index e1c1e20..5f27259 100644 --- a/src/monorepo-workflow-operations.test.ts +++ b/src/monorepo-workflow-operations.test.ts @@ -7,7 +7,6 @@ import { buildMockProject, Require } from '../tests/unit/helpers'; import { followMonorepoWorkflow } from './monorepo-workflow-operations'; import * as editorModule from './editor'; import type { Editor } from './editor'; -import { ReleaseType } from './initial-parameters'; import * as releaseSpecificationModule from './release-specification'; import type { ReleaseSpecification } from './release-specification'; import * as releasePlanModule from './release-plan'; @@ -148,7 +147,6 @@ function buildMockEditor({ * `executeReleasePlan` will throw. * @param args.releaseVersion - The new version that the release plan will * contain. - * @param args.releaseType - The type of release. * @returns Mock functions and other data that can be used in tests to make * assertions. */ @@ -161,7 +159,6 @@ async function setupFollowMonorepoWorkflow({ errorUponPlanningRelease, errorUponExecutingReleasePlan, releaseVersion = '1.0.0', - releaseType = 'ordinary', }: { sandbox: Sandbox; doesReleaseSpecFileExist: boolean; @@ -171,7 +168,6 @@ async function setupFollowMonorepoWorkflow({ errorUponPlanningRelease?: Error; errorUponExecutingReleasePlan?: Error; releaseVersion?: string; - releaseType?: ReleaseType; }) { const { determineEditorSpy, @@ -222,11 +218,11 @@ async function setupFollowMonorepoWorkflow({ if (errorUponPlanningRelease) { when(planReleaseSpy) - .calledWith({ project, releaseSpecification, releaseType }) + .calledWith({ project, releaseSpecification }) .mockRejectedValue(errorUponPlanningRelease); } else { when(planReleaseSpy) - .calledWith({ project, releaseSpecification, releaseType }) + .calledWith({ project, releaseSpecification }) .mockResolvedValue(releasePlan); } @@ -273,7 +269,7 @@ async function setupFollowMonorepoWorkflow({ describe('monorepo-workflow-operations', () => { describe('followMonorepoWorkflow', () => { describe('when firstRemovingExistingReleaseSpecification is false, the release spec file does not already exist, and an editor is available', () => { - it('plans an ordinary release if given releaseType: "ordinary"', async () => { + it('plans an ordinary release', async () => { await withSandbox(async (sandbox) => { const { project, @@ -285,14 +281,12 @@ describe('monorepo-workflow-operations', () => { sandbox, doesReleaseSpecFileExist: false, isEditorAvailable: true, - releaseType: 'ordinary', }); await followMonorepoWorkflow({ project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -300,39 +294,6 @@ describe('monorepo-workflow-operations', () => { expect(planReleaseSpy).toHaveBeenCalledWith({ project, releaseSpecification, - releaseType: 'ordinary', - }); - }); - }); - - it('plans a backport release if given releaseType: "backport"', async () => { - await withSandbox(async (sandbox) => { - const { - project, - stdout, - stderr, - releaseSpecification, - planReleaseSpy, - } = await setupFollowMonorepoWorkflow({ - sandbox, - doesReleaseSpecFileExist: false, - isEditorAvailable: true, - releaseType: 'backport', - }); - - await followMonorepoWorkflow({ - project, - tempDirectoryPath: sandbox.directoryPath, - firstRemovingExistingReleaseSpecification: false, - releaseType: 'backport', - stdout, - stderr, - }); - - expect(planReleaseSpy).toHaveBeenCalledWith({ - project, - releaseSpecification, - releaseType: 'backport', }); }); }); @@ -355,7 +316,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -387,7 +347,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -412,7 +371,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -436,7 +394,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -461,7 +418,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -486,7 +442,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -512,7 +467,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -536,7 +490,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -562,7 +515,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -588,7 +540,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -613,7 +564,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -635,7 +585,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -658,7 +607,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -682,7 +630,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -709,7 +656,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -720,38 +666,7 @@ describe('monorepo-workflow-operations', () => { }); }); - it('plans an ordinary release if given releaseType: "ordinary"', async () => { - await withSandbox(async (sandbox) => { - const { - project, - stdout, - stderr, - releaseSpecification, - planReleaseSpy, - } = await setupFollowMonorepoWorkflow({ - sandbox, - doesReleaseSpecFileExist: true, - releaseType: 'ordinary', - }); - - await followMonorepoWorkflow({ - project, - tempDirectoryPath: sandbox.directoryPath, - firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', - stdout, - stderr, - }); - - expect(planReleaseSpy).toHaveBeenCalledWith({ - project, - releaseSpecification, - releaseType: 'ordinary', - }); - }); - }); - - it('plans a backport release if given releaseType: "backport"', async () => { + it('plans an ordinary release', async () => { await withSandbox(async (sandbox) => { const { project, @@ -762,14 +677,12 @@ describe('monorepo-workflow-operations', () => { } = await setupFollowMonorepoWorkflow({ sandbox, doesReleaseSpecFileExist: true, - releaseType: 'backport', }); await followMonorepoWorkflow({ project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'backport', stdout, stderr, }); @@ -777,7 +690,6 @@ describe('monorepo-workflow-operations', () => { expect(planReleaseSpy).toHaveBeenCalledWith({ project, releaseSpecification, - releaseType: 'backport', }); }); }); @@ -799,7 +711,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -830,7 +741,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -854,7 +764,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }); @@ -878,7 +787,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -903,7 +811,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -928,7 +835,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: false, - releaseType: 'ordinary', stdout, stderr, }), @@ -940,7 +846,7 @@ describe('monorepo-workflow-operations', () => { }); describe('when firstRemovingExistingReleaseSpecification is true, the release spec file does not already exist, and an editor is available', () => { - it('plans an ordinary release if given releaseType: "ordinary"', async () => { + it('plans an ordinary release', async () => { await withSandbox(async (sandbox) => { const { project, @@ -952,14 +858,12 @@ describe('monorepo-workflow-operations', () => { sandbox, doesReleaseSpecFileExist: false, isEditorAvailable: true, - releaseType: 'ordinary', }); await followMonorepoWorkflow({ project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -967,39 +871,6 @@ describe('monorepo-workflow-operations', () => { expect(planReleaseSpy).toHaveBeenCalledWith({ project, releaseSpecification, - releaseType: 'ordinary', - }); - }); - }); - - it('plans a backport release if given releaseType: "backport"', async () => { - await withSandbox(async (sandbox) => { - const { - project, - stdout, - stderr, - releaseSpecification, - planReleaseSpy, - } = await setupFollowMonorepoWorkflow({ - sandbox, - doesReleaseSpecFileExist: false, - isEditorAvailable: true, - releaseType: 'backport', - }); - - await followMonorepoWorkflow({ - project, - tempDirectoryPath: sandbox.directoryPath, - firstRemovingExistingReleaseSpecification: true, - releaseType: 'backport', - stdout, - stderr, - }); - - expect(planReleaseSpy).toHaveBeenCalledWith({ - project, - releaseSpecification, - releaseType: 'backport', }); }); }); @@ -1022,7 +893,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1054,7 +924,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1079,7 +948,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1103,7 +971,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1128,7 +995,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1153,7 +1019,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1179,7 +1044,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1203,7 +1067,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1229,7 +1092,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1255,7 +1117,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1280,7 +1141,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1302,7 +1162,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1325,7 +1184,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1349,7 +1207,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1377,7 +1234,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1391,70 +1247,6 @@ describe('monorepo-workflow-operations', () => { }); }); - it('plans an ordinary release if given releaseType: "ordinary"', async () => { - await withSandbox(async (sandbox) => { - const { - project, - stdout, - stderr, - releaseSpecification, - planReleaseSpy, - } = await setupFollowMonorepoWorkflow({ - sandbox, - doesReleaseSpecFileExist: true, - isEditorAvailable: true, - releaseType: 'ordinary', - }); - - await followMonorepoWorkflow({ - project, - tempDirectoryPath: sandbox.directoryPath, - firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', - stdout, - stderr, - }); - - expect(planReleaseSpy).toHaveBeenCalledWith({ - project, - releaseSpecification, - releaseType: 'ordinary', - }); - }); - }); - - it('plans a backport release if given releaseType: "backport"', async () => { - await withSandbox(async (sandbox) => { - const { - project, - stdout, - stderr, - releaseSpecification, - planReleaseSpy, - } = await setupFollowMonorepoWorkflow({ - sandbox, - doesReleaseSpecFileExist: true, - isEditorAvailable: true, - releaseType: 'backport', - }); - - await followMonorepoWorkflow({ - project, - tempDirectoryPath: sandbox.directoryPath, - firstRemovingExistingReleaseSpecification: true, - releaseType: 'backport', - stdout, - stderr, - }); - - expect(planReleaseSpy).toHaveBeenCalledWith({ - project, - releaseSpecification, - releaseType: 'backport', - }); - }); - }); - it('attempts to execute the release spec if it was successfully edited', async () => { await withSandbox(async (sandbox) => { const { @@ -1473,7 +1265,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1505,7 +1296,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1530,7 +1320,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1554,7 +1343,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1579,7 +1367,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1604,7 +1391,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1630,7 +1416,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1654,7 +1439,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1680,7 +1464,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1706,7 +1489,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }), @@ -1735,7 +1517,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1762,7 +1543,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1784,7 +1564,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1807,7 +1586,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); @@ -1831,7 +1609,6 @@ describe('monorepo-workflow-operations', () => { project, tempDirectoryPath: sandbox.directoryPath, firstRemovingExistingReleaseSpecification: true, - releaseType: 'ordinary', stdout, stderr, }); diff --git a/src/monorepo-workflow-operations.ts b/src/monorepo-workflow-operations.ts index 5409ba5..b1f5ae9 100644 --- a/src/monorepo-workflow-operations.ts +++ b/src/monorepo-workflow-operations.ts @@ -7,7 +7,6 @@ import { writeFile, } from './fs'; import { determineEditor } from './editor'; -import { ReleaseType } from './initial-parameters'; import { Project } from './project'; import { planRelease, executeReleasePlan } from './release-plan'; import { captureChangesInReleaseBranch } from './repo'; @@ -44,8 +43,6 @@ import { * possible for a release specification that was created in a previous run to * stick around (due to an error). This will ensure that the file is removed * first. - * @param args.releaseType - The type of release ("ordinary" or "backport"), - * which affects how the version is bumped. * @param args.stdout - A stream that can be used to write to standard out. * @param args.stderr - A stream that can be used to write to standard error. */ @@ -53,14 +50,12 @@ export async function followMonorepoWorkflow({ project, tempDirectoryPath, firstRemovingExistingReleaseSpecification, - releaseType, stdout, stderr, }: { project: Project; tempDirectoryPath: string; firstRemovingExistingReleaseSpecification: boolean; - releaseType: ReleaseType; stdout: Pick; stderr: Pick; }) { @@ -115,7 +110,6 @@ export async function followMonorepoWorkflow({ const releasePlan = await planRelease({ project, releaseSpecification, - releaseType, }); await executeReleasePlan(project, releasePlan, stderr); await removeFile(releaseSpecificationPath); diff --git a/src/project.test.ts b/src/project.test.ts index 20bb02f..141e386 100644 --- a/src/project.test.ts +++ b/src/project.test.ts @@ -112,10 +112,7 @@ describe('project', () => { rootPackage, workspacePackages, isMonorepo: true, - releaseVersion: { - ordinaryNumber: 4, - backportNumber: 38, - }, + releaseVersion: rootPackageVersion, }); }); }); diff --git a/src/project.ts b/src/project.ts index 931f3ea..81c5284 100644 --- a/src/project.ts +++ b/src/project.ts @@ -13,20 +13,8 @@ import { PackageManifestFieldNames } from './package-manifest'; /** * The release version of the root package of a monorepo extracted from its * version string. - * - * @property ordinaryNumber - The number assigned to the release if it - * introduces new changes that haven't appeared in any previous release; it will - * be 0 if there haven't been any releases yet. - * @property backportNumber - A backport release is a change ported from one - * ordinary release to a previous ordinary release. This, then, is the number - * which identifies this release relative to other backport releases under the - * same ordinary release, starting from 1; it will be 0 if there aren't any - * backport releases for the ordinary release yet. */ -type ReleaseVersion = { - ordinaryNumber: number; - backportNumber: number; -}; +export type ReleaseVersion = SemVer; /** * Represents the entire codebase on which this tool is operating. @@ -48,22 +36,6 @@ export type Project = { releaseVersion: ReleaseVersion; }; -/** - * Given a SemVer version object, interprets the "major" part of the version - * as the ordinary release number and the "minor" part as the backport release - * number in the context of the ordinary release. - * - * @param packageVersion - The version of the package. - * @returns An object containing the ordinary and backport numbers in the - * version. - */ -function examineReleaseVersion(packageVersion: SemVer): ReleaseVersion { - return { - ordinaryNumber: packageVersion.major, - backportNumber: packageVersion.minor, - }; -} - /** * Collects information about a monorepo — its root package as well as any * packages within workspaces specified via the root `package.json`. @@ -87,9 +59,7 @@ export async function readProject( projectDirectoryPath, projectTagNames: tagNames, }); - const releaseVersion = examineReleaseVersion( - rootPackage.validatedManifest.version, - ); + const releaseVersion = rootPackage.validatedManifest.version; const workspaceDirectories = await getWorkspaceLocations( rootPackage.validatedManifest[PackageManifestFieldNames.Workspaces], diff --git a/src/release-plan.test.ts b/src/release-plan.test.ts index d49e9ea..c9c9c14 100644 --- a/src/release-plan.test.ts +++ b/src/release-plan.test.ts @@ -1,13 +1,136 @@ import fs from 'fs'; import { SemVer } from 'semver'; import { buildMockProject, buildMockPackage } from '../tests/unit/helpers'; -import { planRelease, executeReleasePlan } from './release-plan'; +import { + planRelease, + executeReleasePlan, + getNewReleaseVersion, +} from './release-plan'; import { IncrementableVersionParts } from './release-specification'; import * as packageUtils from './package'; jest.mock('./package'); describe('release-plan-utils', () => { + describe('getNewReleaseVersion', () => { + it('returns `2.0.0` if the highest version increment is `major`', () => { + const project = buildMockProject({ + rootPackage: buildMockPackage('root', '1.0.0'), + workspacePackages: { + a: buildMockPackage('a', '1.0.0'), + b: buildMockPackage('b', '1.0.0'), + c: buildMockPackage('c', '1.0.0'), + d: buildMockPackage('d', '1.0.0'), + }, + }); + + const releaseSpecification = { + packages: { + a: IncrementableVersionParts.major, + b: IncrementableVersionParts.minor, + c: IncrementableVersionParts.patch, + d: new SemVer('1.2.3'), + }, + path: '/path/to/release/spec', + }; + + const newReleaseVersion = getNewReleaseVersion({ + project, + releaseSpecification, + }); + + expect(newReleaseVersion).toBe('2.0.0'); + }); + + it('returns `1.1.0` if the highest version increment is `minor`', () => { + const project = buildMockProject({ + rootPackage: buildMockPackage('root', '1.0.0'), + workspacePackages: { + a: buildMockPackage('a', '1.0.0'), + b: buildMockPackage('b', '1.0.0'), + c: buildMockPackage('c', '1.0.0'), + d: buildMockPackage('d', '1.0.0'), + }, + }); + + const releaseSpecification = { + packages: { + a: IncrementableVersionParts.patch, + b: IncrementableVersionParts.minor, + c: IncrementableVersionParts.minor, + d: new SemVer('1.2.3'), + }, + path: '/path/to/release/spec', + }; + + const newReleaseVersion = getNewReleaseVersion({ + project, + releaseSpecification, + }); + + expect(newReleaseVersion).toBe('1.1.0'); + }); + + it('returns `1.0.1` if the highest version increment is `patch`', () => { + const project = buildMockProject({ + rootPackage: buildMockPackage('root', '1.0.0'), + workspacePackages: { + a: buildMockPackage('a', '1.0.0'), + b: buildMockPackage('b', '1.0.0'), + c: buildMockPackage('c', '1.0.0'), + d: buildMockPackage('d', '1.0.0'), + }, + }); + + const releaseSpecification = { + packages: { + a: IncrementableVersionParts.patch, + b: IncrementableVersionParts.patch, + c: IncrementableVersionParts.patch, + d: new SemVer('1.0.3'), + }, + path: '/path/to/release/spec', + }; + + const newReleaseVersion = getNewReleaseVersion({ + project, + releaseSpecification, + }); + + expect(newReleaseVersion).toBe('1.0.1'); + }); + + it('returns `2.0.0` if the highest version increment is `major`, and the release specification has a prerelease version', () => { + const project = buildMockProject({ + rootPackage: buildMockPackage('root', '1.0.0'), + workspacePackages: { + a: buildMockPackage('a', '1.0.0'), + b: buildMockPackage('b', '1.0.0'), + c: buildMockPackage('c', '1.0.0'), + d: buildMockPackage('d', '1.0.0'), + }, + }); + + const releaseSpecification = { + packages: { + a: new SemVer('1.2.3-alpha.0'), + b: IncrementableVersionParts.minor, + c: IncrementableVersionParts.patch, + d: IncrementableVersionParts.major, + }, + path: '/path/to/release/spec', + prerelease: 'alpha', + }; + + const newReleaseVersion = getNewReleaseVersion({ + project, + releaseSpecification, + }); + + expect(newReleaseVersion).toBe('2.0.0'); + }); + }); + describe('planRelease', () => { it('calculates final versions for all packages in the release spec, including bumping the ordinary part of the root package if this is an ordinary release', async () => { const project = buildMockProject({ @@ -32,7 +155,6 @@ describe('release-plan-utils', () => { const releasePlan = await planRelease({ project, releaseSpecification, - releaseType: 'ordinary', }); expect(releasePlan).toMatchObject({ @@ -66,18 +188,18 @@ describe('release-plan-utils', () => { const project = buildMockProject({ rootPackage: buildMockPackage('root', '1.0.0'), workspacePackages: { - a: buildMockPackage('a', '1.0.0'), - b: buildMockPackage('b', '1.0.0'), - c: buildMockPackage('c', '1.0.0'), - d: buildMockPackage('d', '1.0.0'), + a: buildMockPackage('a', '1.0.1'), + b: buildMockPackage('b', '1.0.4'), + c: buildMockPackage('c', '1.0.2'), + d: buildMockPackage('d', '1.0.3'), }, }); const releaseSpecification = { packages: { - a: IncrementableVersionParts.major, - b: IncrementableVersionParts.minor, + a: IncrementableVersionParts.patch, + b: IncrementableVersionParts.patch, c: IncrementableVersionParts.patch, - d: new SemVer('1.2.3'), + d: new SemVer('1.0.4'), }, path: '/path/to/release/spec', }; @@ -85,31 +207,30 @@ describe('release-plan-utils', () => { const releasePlan = await planRelease({ project, releaseSpecification, - releaseType: 'backport', }); expect(releasePlan).toMatchObject({ - newVersion: '1.1.0', + newVersion: '1.0.1', packages: [ { package: project.rootPackage, - newVersion: '1.1.0', + newVersion: '1.0.1', }, { package: project.workspacePackages.a, - newVersion: '2.0.0', + newVersion: '1.0.2', }, { package: project.workspacePackages.b, - newVersion: '1.1.0', + newVersion: '1.0.5', }, { package: project.workspacePackages.c, - newVersion: '1.0.1', + newVersion: '1.0.3', }, { package: project.workspacePackages.d, - newVersion: '1.2.3', + newVersion: '1.0.4', }, ], }); @@ -138,7 +259,6 @@ describe('release-plan-utils', () => { const releasePlan = await planRelease({ project, releaseSpecification, - releaseType: 'ordinary', }); expect(releasePlan).toMatchObject({ diff --git a/src/release-plan.ts b/src/release-plan.ts index 0ee5223..b34bd69 100644 --- a/src/release-plan.ts +++ b/src/release-plan.ts @@ -1,10 +1,15 @@ import type { WriteStream } from 'fs'; import { SemVer } from 'semver'; -import { ReleaseType } from './initial-parameters'; +import { assert } from '@metamask/utils'; import { debug } from './misc-utils'; import { Package, updatePackage } from './package'; import { Project } from './project'; -import { ReleaseSpecification } from './release-specification'; +import { + IncrementableVersionParts, + ReleaseSpecification, + VersionSpecifier, +} from './release-specification'; +import { semver } from './semver'; /** * Instructions for how to update the project in order to prepare it for a new @@ -46,6 +51,93 @@ export type PackageReleasePlan = { shouldUpdateChangelog: boolean; }; +/** + * Get the new version for a package, based on the release specification. + * + * @param currentVersion - The current version of the package. + * @param versionSpecifier - The version specifier from the release + * specification. + * @returns The new version for the package. + */ +export function getNewPackageVersion( + currentVersion: SemVer, + versionSpecifier: VersionSpecifier, +) { + return versionSpecifier instanceof SemVer + ? versionSpecifier + : new SemVer(currentVersion.toString()).inc(versionSpecifier); +} + +/** + * Get the new release version for a monorepo, based on the release + * specification. + * + * @param args - The arguments. + * @param args.project - Information about the whole project (e.g., names of + * packages and where they can found). + * @param args.releaseSpecification - A parsed version of the release spec + * entered by the user. + * @returns The new release version. + */ +export function getNewReleaseVersion({ + project, + releaseSpecification, +}: { + project: Project; + releaseSpecification: ReleaseSpecification; +}): string { + const versionIncrement = Object.entries( + releaseSpecification.packages, + ).reduce( + (currentIncrementableVersion, [packageName, versionSpecifier]) => { + // If the current incrementable version is "major", we can stop + // immediately, since we can't increment the version any further. + if (currentIncrementableVersion === IncrementableVersionParts.major) { + return currentIncrementableVersion; + } + + const currentVersion = + project.workspacePackages[packageName].validatedManifest.version; + const newVersion = getNewPackageVersion(currentVersion, versionSpecifier); + + // `diff` returns null if the versions are the same, or a string + // representing the type of change otherwise (e.g., "major", "minor", + // "patch"). We then convert that string to the enum value. + const diff = semver.diff( + currentVersion, + newVersion, + ) as IncrementableVersionParts; + + if ( + diff === null || + !Object.values(IncrementableVersionParts).includes(diff) + ) { + return currentIncrementableVersion; + } + + // Assuming that the `IncrementableVersionParts` enum is ordered from + // most to least significant, we can compare the weights of the two + // versions to determine which one is more significant. For example, if + // the current incrementable version is "patch" and the diff is "minor", + // we check the weight of "minor" and "patch" and find that "minor" is + // more significant, so we return "minor" as the new incrementable + // version. + const weight = Object.values(IncrementableVersionParts).indexOf(diff); + const currentWeight = Object.values(IncrementableVersionParts).indexOf( + currentIncrementableVersion, + ); + + return weight < currentWeight ? diff : currentIncrementableVersion; + }, + IncrementableVersionParts.patch, + ); + + const newVersion = semver.inc(project.releaseVersion, versionIncrement); + assert(newVersion !== null, 'Invalid new version.'); + + return newVersion; +} + /** * Uses the release specification to calculate the final versions of all of the * packages that we want to update, as well as a new release name. @@ -55,25 +147,19 @@ export type PackageReleasePlan = { * packages and where they can found). * @param args.releaseSpecification - A parsed version of the release spec * entered by the user. - * @param args.releaseType - The type of release ("ordinary" or "backport"), - * which affects how the version is bumped. * @returns A promise for information about the new release. */ export async function planRelease({ project, releaseSpecification, - releaseType, }: { project: Project; releaseSpecification: ReleaseSpecification; - releaseType: ReleaseType; }): Promise { - const newReleaseVersion = - releaseType === 'backport' - ? `${project.releaseVersion.ordinaryNumber}.${ - project.releaseVersion.backportNumber + 1 - }.0` - : `${project.releaseVersion.ordinaryNumber + 1}.0.0`; + const newReleaseVersion = getNewReleaseVersion({ + project, + releaseSpecification, + }); const rootReleasePlan: PackageReleasePlan = { package: project.rootPackage, @@ -87,10 +173,7 @@ export async function planRelease({ const pkg = project.workspacePackages[packageName]; const versionSpecifier = releaseSpecification.packages[packageName]; const currentVersion = pkg.validatedManifest.version; - const newVersion = - versionSpecifier instanceof SemVer - ? versionSpecifier - : new SemVer(currentVersion.toString()).inc(versionSpecifier); + const newVersion = getNewPackageVersion(currentVersion, versionSpecifier); return { package: pkg, diff --git a/src/release-specification.ts b/src/release-specification.ts index 3dc89fb..12caa3d 100644 --- a/src/release-specification.ts +++ b/src/release-specification.ts @@ -26,7 +26,7 @@ export enum IncrementableVersionParts { * Describes how to update the version for a package, either by bumping a part * of the version or by setting that version exactly. */ -type VersionSpecifier = IncrementableVersionParts | SemVer; +export type VersionSpecifier = IncrementableVersionParts | SemVer; /** * User-provided instructions for how to update this project in order to prepare diff --git a/tests/unit/helpers.ts b/tests/unit/helpers.ts index ac2e0fc..28a0c97 100644 --- a/tests/unit/helpers.ts +++ b/tests/unit/helpers.ts @@ -51,10 +51,7 @@ export function buildMockProject(overrides: Partial = {}): Project { rootPackage: buildMockPackage('root'), workspacePackages: {}, isMonorepo: false, - releaseVersion: { - ordinaryNumber: 1, - backportNumber: 0, - }, + releaseVersion: new SemVer('1.0.0'), ...overrides, }; }