diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index ae1a4c4627..a5c867fccd 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -20,8 +20,9 @@ import { Command } from 'commander'; import { resolve as resolvePath } from 'path'; import { paths } from '../../lib/paths'; import * as runObj from '../../lib/run'; -import bump, { bumpBackstageJsonVersion } from './bump'; +import bump, { bumpBackstageJsonVersion, createVersionFinder } from './bump'; import { withLogCollector } from '@backstage/test-utils'; +import { YarnInfoInspectData } from '../../lib/versioning/packages'; // Remove log coloring to simplify log matching jest.mock('chalk', () => ({ @@ -442,3 +443,92 @@ describe('bumpBackstageJsonVersion', () => { expect(json).toEqual({ version: '1.4.1' }); }); }); + +describe('createVersionFinder', () => { + async function findVersion(tag: string, data: Partial) { + const fetcher = () => + Promise.resolve({ + name: '@backstage/core', + 'dist-tags': {}, + versions: [], + time: {}, + ...data, + }); + + const versionFinder = createVersionFinder(tag, fetcher); + let result; + await withLogCollector(async () => { + result = await versionFinder('@backstage/core'); + }); + return result; + } + + it('should create version finder', async () => { + await expect( + findVersion('latest', { + time: { '1.0.0': '2020-01-01T00:00:00.000Z' }, + 'dist-tags': { latest: '1.0.0' }, + }), + ).resolves.toBe('1.0.0'); + + await expect( + findVersion('main', { + time: { '1.0.0': '2020-01-01T00:00:00.000Z' }, + 'dist-tags': { latest: '1.0.0' }, + }), + ).resolves.toBe('1.0.0'); + + await expect( + findVersion('next', { + time: { '1.0.0': '2020-01-01T00:00:00.000Z' }, + 'dist-tags': { latest: '1.0.0' }, + }), + ).resolves.toBe('1.0.0'); + + await expect( + findVersion('next', { + time: { + '1.0.0': '2020-01-01T00:00:00.000Z', + '0.9.0': '2010-01-01T00:00:00.000Z', + }, + 'dist-tags': { latest: '1.0.0', next: '0.9.0' }, + }), + ).resolves.toBe('1.0.0'); + + await expect( + findVersion('next', { + time: { + '1.0.0': '2020-01-01T00:00:00.000Z', + '0.9.0': '2020-02-01T00:00:00.000Z', + }, + 'dist-tags': { latest: '1.0.0', next: '0.9.0' }, + }), + ).resolves.toBe('0.9.0'); + + await expect(findVersion('next', {})).rejects.toThrow( + "No target 'latest' version found for @backstage/core", + ); + + await expect( + findVersion('next', { + time: { + '0.9.0': '2020-02-01T00:00:00.000Z', + }, + 'dist-tags': { latest: '1.0.0', next: '0.9.0' }, + }), + ).rejects.toThrow( + "No time available for version '1.0.0' of @backstage/core", + ); + + await expect( + findVersion('next', { + time: { + '1.0.0': '2020-01-01T00:00:00.000Z', + }, + 'dist-tags': { latest: '1.0.0', next: '0.9.0' }, + }), + ).rejects.toThrow( + "No time available for version '0.9.0' of @backstage/core", + ); + }); +}); diff --git a/packages/cli/src/commands/versions/bump.ts b/packages/cli/src/commands/versions/bump.ts index 2371011be3..af188cd472 100644 --- a/packages/cli/src/commands/versions/bump.ts +++ b/packages/cli/src/commands/versions/bump.ts @@ -284,7 +284,10 @@ export default async (cmd: Command) => { } }; -function createVersionFinder(releaseLine = 'latest') { +export function createVersionFinder( + releaseLine = 'latest', + packageInfoFetcher = fetchPackageInfo, +) { // The main release line is just an alias for latest const distTag = releaseLine === 'main' ? 'latest' : releaseLine; const found = new Map(); @@ -296,26 +299,35 @@ function createVersionFinder(releaseLine = 'latest') { } console.log(`Checking for updates of ${name}`); - const info = await fetchPackageInfo(name); + const info = await packageInfoFetcher(name); const latestVersion = info['dist-tags'].latest; if (!latestVersion) { throw new Error(`No target 'latest' version found for ${name}`); } - if (distTag === 'latest') { - found.set(name, latestVersion); - return latestVersion; - } + const taggedVersion = info['dist-tags'][distTag]; - if (!taggedVersion) { + if (distTag === 'latest' || !taggedVersion) { found.set(name, latestVersion); return latestVersion; } - const latestVersionRelease = new Date(info.time[latestVersion]); - const taggedVersionRelease = new Date(info.time[taggedVersion]); - if (latestVersionRelease > taggedVersionRelease) { - console.log( - `using 'latest' dist tag for ${name} as its newer than '${distTag}'`, + + const latestVersionDateStr = info.time[latestVersion]; + const taggedVersionDateStr = info.time[taggedVersion]; + if (!latestVersionDateStr) { + throw new Error( + `No time available for version '${latestVersion}' of ${name}`, ); + } + if (!taggedVersionDateStr) { + throw new Error( + `No time available for version '${taggedVersion}' of ${name}`, + ); + } + + const latestVersionRelease = new Date(latestVersionDateStr).getTime(); + const taggedVersionRelease = new Date(taggedVersionDateStr).getTime(); + if (latestVersionRelease > taggedVersionRelease) { + // Prefer latest version if it's newer. found.set(name, latestVersion); return latestVersion; }