From 3de6f90752b04f8324c4e30823a39e009ef0587b Mon Sep 17 00:00:00 2001 From: Jamie Mason Date: Mon, 3 Jan 2022 15:52:59 +0000 Subject: [PATCH] feat(groups): pin a version group to a specific version Closes #44 Closes #53 Closes #63 Closes #64 --- src/bin-fix-mismatches/fix-mismatches.ts | 2 +- .../get-expected-version.spec.ts | 57 +++++++++++++++++++ .../get-pinned-version.ts | 7 +++ .../get-expected-version/index.ts | 10 ++-- src/bin-list-mismatches/list-mismatches.ts | 7 ++- src/bin-list/list-version-groups.ts | 9 ++- src/constants.ts | 4 ++ 7 files changed, 88 insertions(+), 8 deletions(-) create mode 100644 src/bin-fix-mismatches/get-expected-version/get-expected-version.spec.ts create mode 100644 src/bin-fix-mismatches/get-expected-version/get-pinned-version.ts diff --git a/src/bin-fix-mismatches/fix-mismatches.ts b/src/bin-fix-mismatches/fix-mismatches.ts index b3f342ce..c938dc7b 100644 --- a/src/bin-fix-mismatches/fix-mismatches.ts +++ b/src/bin-fix-mismatches/fix-mismatches.ts @@ -21,7 +21,7 @@ export function fixMismatches(input: ProgramInput, disk: Disk): void { groups.forEach(({ hasMismatches, instances, name }) => { if (hasMismatches) { - const nextVersion = getExpectedVersion(input, name, instances); + const nextVersion = getExpectedVersion(name, versionGroup, input); instances.forEach(({ dependencyType, version, wrapper }) => { const root: any = wrapper.contents; if (version !== nextVersion) { diff --git a/src/bin-fix-mismatches/get-expected-version/get-expected-version.spec.ts b/src/bin-fix-mismatches/get-expected-version/get-expected-version.spec.ts new file mode 100644 index 00000000..51d796a1 --- /dev/null +++ b/src/bin-fix-mismatches/get-expected-version/get-expected-version.spec.ts @@ -0,0 +1,57 @@ +import { getExpectedVersion } from '.'; +import type { Instance } from '../../lib/get-input/get-instances'; + +it('applies pinned versions first', () => { + expect( + getExpectedVersion( + 'foo', + { instances: [], pinVersion: '2.2.2' }, + { wrappers: [] }, + ), + ).toEqual('2.2.2'); +}); + +it('applies matching local package versions second', () => { + expect( + getExpectedVersion( + 'foo', + { instances: [] }, + { + wrappers: [ + { + contents: { name: 'bar', version: '0.1.0' }, + filePath: '', + json: '', + }, + { + contents: { name: 'foo', version: '1.2.3' }, + filePath: '', + json: '', + }, + ], + }, + ), + ).toEqual('1.2.3'); +}); + +it('applies the highest installed version third', () => { + expect( + getExpectedVersion( + 'foo', + { + instances: [ + { version: '2.0.0' }, + { version: '3.0.0' }, + { version: '1.0.0' }, + ] as Instance[], + }, + { wrappers: [] }, + ), + ).toEqual('3.0.0'); +}); + +it('returns an empty string if nothing matches', () => { + expect( + getExpectedVersion('foo', { instances: [] }, { wrappers: [] }), + ).toEqual(''); +}); diff --git a/src/bin-fix-mismatches/get-expected-version/get-pinned-version.ts b/src/bin-fix-mismatches/get-expected-version/get-pinned-version.ts new file mode 100644 index 00000000..ca5d97cd --- /dev/null +++ b/src/bin-fix-mismatches/get-expected-version/get-pinned-version.ts @@ -0,0 +1,7 @@ +import type { IndexedVersionGroup } from '../../lib/get-input/get-instances'; + +export function getPinnedVersion( + versionGroup: Pick, +): string { + return versionGroup.pinVersion || ''; +} diff --git a/src/bin-fix-mismatches/get-expected-version/index.ts b/src/bin-fix-mismatches/get-expected-version/index.ts index 81542fa4..ad9ea871 100644 --- a/src/bin-fix-mismatches/get-expected-version/index.ts +++ b/src/bin-fix-mismatches/get-expected-version/index.ts @@ -1,15 +1,17 @@ import type { ProgramInput } from '../../lib/get-input'; -import type { Instance } from '../../lib/get-input/get-instances'; +import type { IndexedVersionGroup } from '../../lib/get-input/get-instances'; import { getHighestVersion } from './get-highest-version'; +import { getPinnedVersion } from './get-pinned-version'; import { getWorkspaceVersion } from './get-workspace-version'; export function getExpectedVersion( - input: ProgramInput, name: string, - instances: Instance[], + versionGroup: Pick, + input: Pick, ): string { return ( + getPinnedVersion(versionGroup) || getWorkspaceVersion(name, input.wrappers) || - getHighestVersion(instances.map(({ version }) => version)) + getHighestVersion(versionGroup.instances.map(({ version }) => version)) ); } diff --git a/src/bin-list-mismatches/list-mismatches.ts b/src/bin-list-mismatches/list-mismatches.ts index 0dd8c662..65ed0444 100644 --- a/src/bin-list-mismatches/list-mismatches.ts +++ b/src/bin-list-mismatches/list-mismatches.ts @@ -1,4 +1,6 @@ import chalk from 'chalk'; +import { version } from 'os'; +import { getExpectedVersion } from '../bin-fix-mismatches/get-expected-version'; import { listVersionGroups } from '../bin-list/list-version-groups'; import type { ProgramInput } from '../lib/get-input'; @@ -20,10 +22,11 @@ export function listMismatches(input: ProgramInput): void { groups.forEach(({ hasMismatches, instances, name }) => { if (hasMismatches) { - console.log(chalk`{red ✕ ${name}}`); + const expectedVersion = getExpectedVersion(name, versionGroup, input); + console.log(chalk`{dim -} ${name} {green.dim ${expectedVersion}}`); instances.forEach(({ dependencyType, version, wrapper }) => { console.log( - chalk`{dim -} ${version} {dim in ${dependencyType} of} ${wrapper.contents.name}`, + chalk`{red ${version} {dim in ${dependencyType} of ${wrapper.contents.name}}}`, ); }); } diff --git a/src/bin-list/list-version-groups.ts b/src/bin-list/list-version-groups.ts index 8fec09c1..dc83fb3a 100644 --- a/src/bin-list/list-version-groups.ts +++ b/src/bin-list/list-version-groups.ts @@ -1,3 +1,4 @@ +import { isNonEmptyString } from 'expect-more'; import type { IndexedVersionGroup, Instance, @@ -20,9 +21,15 @@ export function listVersionGroups( versionGroup.instances.sort(sortByName), ); return Object.entries(instancesByName).map(([name, instances]) => { + const pinnedVersion = versionGroup.pinVersion; + const hasPinnedVersion = isNonEmptyString(pinnedVersion); const versions = instances.map(({ version }) => version); const uniques = Array.from(new Set(versions)); - const hasMismatches = uniques.length > 1; + const hasMismatches = versions.some( + (version, i) => + (hasPinnedVersion && version !== pinnedVersion) || + (i > 0 && version !== versions[i - 1]), + ); return { hasMismatches, instances, diff --git a/src/constants.ts b/src/constants.ts index 845effe6..2994d511 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -47,6 +47,10 @@ export interface VersionGroup { * the names of the dependencies (eg. "lodash") which belong to this group */ dependencies: string[]; + /** + * optionally force all dependencies in this group to have this version + */ + pinVersion?: string; } export type SyncpackConfig = Readonly<{