From 532dae9c4c11d5246607046bf536ee24e22dc8e8 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Thu, 10 Feb 2022 13:30:10 +0100 Subject: [PATCH] cli: versions:bump prefer latest manifest when next release is specified Signed-off-by: Johan Haals --- .changeset/blue-jobs-know.md | 5 + .../cli/src/commands/versions/bump.test.ts | 103 ++++++++++++++++++ packages/cli/src/commands/versions/bump.ts | 21 +++- 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 .changeset/blue-jobs-know.md diff --git a/.changeset/blue-jobs-know.md b/.changeset/blue-jobs-know.md new file mode 100644 index 0000000000000..35feed552bbfe --- /dev/null +++ b/.changeset/blue-jobs-know.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +The `versions:bump --release next` command is updated to compare the `main` and `next` release manifests and prefer the latest. diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index d2d3cf1573b65..73ecc0284e441 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -418,6 +418,109 @@ describe('bump', () => { expect(await fs.readJson('/backstage.json')).toEqual({ version: '2.0.0' }); }); + it('should prefer versions from the highest manifest version when main is not specified', async () => { + mockFs({ + '/yarn.lock': lockfileMock, + '/package.json': JSON.stringify({ + workspaces: { + packages: ['packages/*'], + }, + }), + '/packages/a/package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), + '/packages/b/package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + }, + }), + }); + + jest + .spyOn(paths, 'resolveTargetRoot') + .mockImplementation((...path) => resolvePath('/', ...path)); + jest.spyOn(runObj, 'runPlain').mockImplementation(async (...[, , , name]) => + JSON.stringify({ + type: 'inspect', + data: { + name: name, + 'dist-tags': { + latest: REGISTRY_VERSIONS[name], + }, + }, + }), + ); + jest.spyOn(runObj, 'run').mockResolvedValue(undefined); + worker.use( + rest.get( + 'https://versions.backstage.io/v1/tags/main/manifest.json', + (_, res, ctx) => + res( + ctx.status(200), + ctx.json({ + releaseVersion: '1.0.0', + packages: [ + { + name: '@backstage/theme', + version: '5.0.0', + }, + { + name: '@backstage/create-app', + version: '3.0.0', + }, + ], + }), + ), + ), + rest.get( + 'https://versions.backstage.io/v1/tags/next/manifest.json', + (_, res, ctx) => + res( + ctx.status(200), + ctx.json({ + releaseVersion: '1.0.0-next.1', + packages: [ + { + name: '@backstage/theme', + version: '4.0.0', + }, + { + name: '@backstage/create-app', + version: '2.0.0', + }, + ], + }), + ), + ), + ); + const { log: logs } = await withLogCollector(['log'], async () => { + await bump({ pattern: null, release: 'next' } as unknown as Command); + }); + expect(logs.filter(Boolean)).toEqual([ + 'Using default pattern glob @backstage/*', + 'Checking for updates of @backstage/core', + 'Checking for updates of @backstage/theme', + 'Checking for updates of @backstage/theme', + 'Checking for updates of @backstage/core-api', + 'Some packages are outdated, updating', + 'unlocking @backstage/core@^1.0.3 ~> 1.0.6', + 'unlocking @backstage/core-api@^1.0.6 ~> 1.0.7', + 'unlocking @backstage/core-api@^1.0.3 ~> 1.0.7', + 'bumping @backstage/theme in b to ^5.0.0', + 'Creating backstage.json', + 'Running yarn install to install new versions', + '⚠️ The following packages may have breaking changes:', + ' @backstage/theme : 1.0.0 ~> 5.0.0', + ' https://github.com/backstage/backstage/blob/master/packages/theme/CHANGELOG.md', + 'Version bump complete!', + ]); + }); + it('should bump backstage dependencies and dependencies matching pattern glob', async () => { const customLockfileMock = `${lockfileMock} "@backstage-extra/custom@^1.1.0": diff --git a/packages/cli/src/commands/versions/bump.ts b/packages/cli/src/commands/versions/bump.ts index fc455b9fbd8a6..8c3c6619965ad 100644 --- a/packages/cli/src/commands/versions/bump.ts +++ b/packages/cli/src/commands/versions/bump.ts @@ -68,15 +68,30 @@ export default async (cmd: Command) => { let findTargetVersion: (name: string) => Promise; let releaseManifest: ReleaseManifest; + // Specific release specified. Be strict when resolving versions if (semver.valid(cmd.release)) { releaseManifest = await getManifestByVersion({ version: cmd.release }); findTargetVersion = createStrictVersionFinder({ releaseManifest, }); } else { - releaseManifest = await getManifestByReleaseLine({ - releaseLine: cmd.release, - }); + // Release line specified. Be lenient when resolving versions. + if (cmd.release === 'next') { + const next = await getManifestByReleaseLine({ + releaseLine: 'next', + }); + const main = await getManifestByReleaseLine({ + releaseLine: 'main', + }); + // Prefer manifest with the latest release version + releaseManifest = semver.gt(next.releaseVersion, main.releaseVersion) + ? next + : main; + } else { + releaseManifest = await getManifestByReleaseLine({ + releaseLine: cmd.release, + }); + } findTargetVersion = createVersionFinder({ releaseLine: cmd.releaseLine, releaseManifest,