Skip to content

Commit

Permalink
feat(list-mismatches): show reason for mismatches
Browse files Browse the repository at this point in the history
Refs #65
Refs #77
Closes #79
  • Loading branch information
JamieMason committed Jun 4, 2022
1 parent a3edcf2 commit 81160b5
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 52 deletions.
79 changes: 43 additions & 36 deletions src/bin-list-mismatches/list-mismatches.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'expect-more-jest';
import { scenarios } from '../../test/scenarios';
import type { TestScenario } from '../../test/scenarios/create-scenario';
import { getInput } from '../lib/get-input';
import { listMismatches } from './list-mismatches';

Expand All @@ -11,34 +10,42 @@ describe('listMismatches', () => {

describe('when dependencies are installed with different versions', () => {
describe('when the dependency is a package maintained in this workspace', () => {
const variants: [string, () => TestScenario, string][] = [
[
'when using a typical workspace',
scenarios.dependentDoesNotMatchWorkspaceVersion,
'packages/c/package.json',
],
[
'when using nested workspaces',
scenarios.dependentDoesNotMatchNestedWorkspaceVersion,
'workspaces/b/packages/c/package.json',
],
];
variants.forEach(([context, getScenario, originPath]) => {
describe(context, () => {
it('warns about the workspace version', () => {
const scenario = getScenario();
listMismatches(
getInput(scenario.disk, scenario.config),
scenario.disk,
);
expect(scenario.log.mock.calls).toEqual([
['- c 0.0.1'],
[' 0.1.0 in dependencies of a'],
[' 0.2.0 in devDependencies of b'],
[` 0.0.1 at ${originPath}`],
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});
describe('when using a typical workspace', () => {
it('warns about the workspace version', () => {
const scenario = scenarios.dependentDoesNotMatchWorkspaceVersion();
listMismatches(
getInput(scenario.disk, scenario.config),
scenario.disk,
);
expect(scenario.log.mock.calls).toEqual([
['- c 0.0.1 is developed in this repo at packages/c/package.json'],
[' 0.1.0 in dependencies of packages/a/package.json'],
[' 0.2.0 in devDependencies of packages/b/package.json'],
[' 0.0.1 in version of packages/c/package.json'],
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});
});

describe('when using nested workspaces', () => {
it('warns about the workspace version', () => {
const scenario =
scenarios.dependentDoesNotMatchNestedWorkspaceVersion();
listMismatches(
getInput(scenario.disk, scenario.config),
scenario.disk,
);
expect(scenario.log.mock.calls).toEqual([
[
'- c 0.0.1 is developed in this repo at workspaces/b/packages/c/package.json',
],
[' 0.1.0 in dependencies of workspaces/a/packages/a/package.json'],
[
' 0.2.0 in devDependencies of workspaces/b/packages/b/package.json',
],
[' 0.0.1 in version of workspaces/b/packages/c/package.json'],
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});
});
});
Expand All @@ -47,11 +54,11 @@ describe('listMismatches', () => {
const scenario = scenarios.mismatchesIncludeNonSemverVersions();
listMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.log.mock.calls).toEqual([
['- foo 0.3.0'],
[' link:vendor/foo-0.1.0 in dependencies of a'],
[' link:vendor/foo-0.2.0 in dependencies of b'],
[' 0.3.0 in dependencies of c'],
[' 0.2.0 in dependencies of d'],
['- foo 0.3.0 is the highest valid semver version in use'],
[' link:vendor/foo-0.1.0 in dependencies of packages/a/package.json'],
[' link:vendor/foo-0.2.0 in dependencies of packages/b/package.json'],
[' 0.3.0 in dependencies of packages/c/package.json'],
[' 0.2.0 in dependencies of packages/d/package.json'],
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});
Expand All @@ -61,8 +68,8 @@ describe('listMismatches', () => {
listMismatches(getInput(scenario.disk, scenario.config), scenario.disk);
expect(scenario.log.mock.calls).toEqual([
[expect.stringMatching(/Version Group 1/)],
[' bar remove this dependency'],
[' 0.2.0 in dependencies of b'],
[' bar is defined in this version group as banned from use'],
[' 0.2.0 in dependencies of packages/b/package.json'],
]);
expect(scenario.disk.process.exit).toHaveBeenCalledWith(1);
});
Expand Down
48 changes: 37 additions & 11 deletions src/bin-list-mismatches/list-mismatches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import chalk from 'chalk';
import { relative } from 'path';
import { getExpectedVersion } from '../bin-fix-mismatches/get-expected-version';
import { listVersionGroups } from '../bin-list/list-version-groups';
import { CWD } from '../constants';
import { CWD, ICON } from '../constants';
import type { Disk } from '../lib/disk';
import type { ProgramInput } from '../lib/get-input';
import type { Instance } from '../lib/get-input/get-instances';

export function listMismatches(input: ProgramInput, disk: Disk): void {
let isInvalid = false;
Expand All @@ -29,19 +30,44 @@ export function listMismatches(input: ProgramInput, disk: Disk): void {
}

groups.forEach(({ instances, isBanned, name }) => {
const expectedVersion = getExpectedVersion(name, versionGroup, input);
console.log(
isBanned
? chalk`{red ✕ ${name}} {dim.red remove this dependency}`
: chalk`{dim -} ${name} {green.dim ${expectedVersion}}`,
);
let workspaceMatch: Instance | null = null;
const expected = getExpectedVersion(name, versionGroup, input);

for (const instance of instances) {
const isMatch = instance.version === expected;
const isWorkspace = instance.dependencyType === 'workspace';
if (isMatch && isWorkspace) {
workspaceMatch = instance;
}
}

if (isBanned) {
console.log(
chalk`{red ${ICON.cross} ${name}} {dim.red is defined in this version group as banned from use}`,
);
} else if (workspaceMatch) {
const shortPath = relative(CWD, workspaceMatch.wrapper.filePath);
console.log(
chalk`{dim -} ${name} {green.dim ${expected} is developed in this repo at ${shortPath}}`,
);
} else {
console.log(
chalk`{dim -} ${name} {green.dim ${expected} is the highest valid semver version in use}`,
);
}

instances.forEach(({ dependencyType, version, wrapper }) => {
if (dependencyType === 'workspace') {
const shortPath = relative(CWD, wrapper.filePath);
console.log(chalk`{red ${version} {dim at ${shortPath}}}`);
const isMatch = version === expected;
const isLocal = dependencyType === 'workspace';
const shortPath = relative(CWD, wrapper.filePath);
const loc = isLocal ? 'version' : dependencyType;
if (isMatch) {
console.log(
chalk`{green ${version} {dim in ${loc} of ${shortPath}}}`,
);
} else {
console.log(
chalk`{red ${version} {dim in ${dependencyType} of ${wrapper.contents.name}}}`,
chalk`{red ${version} {dim in ${loc} of ${shortPath}}}`,
);
}
});
Expand Down
7 changes: 7 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,13 @@ export const SEMVER_ORDER: ValidRange[] = [
RANGE_ANY,
];

export const ICON = {
cross: '✘',
debug: '?',
skip: '-',
tick: '✓',
};

export const DEFAULT_CONFIG: SyncpackConfig = {
dependencyTypes: [],
dev: true,
Expand Down
5 changes: 3 additions & 2 deletions src/lib/log.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import chalk from 'chalk';
import { isString } from 'expect-more';
import { inspect } from 'util';
import { ICON } from '../constants';

export function verbose(...values: any[]): void {
export function verbose(...values: unknown[]): void {
if (process.env.SYNCPACK_VERBOSE) {
console.info(
chalk.yellow('?'),
chalk.yellow(ICON.debug),
...values.map((value) =>
isString(value)
? chalk.yellow(value)
Expand Down
6 changes: 3 additions & 3 deletions src/lib/write-if-changed.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import chalk from 'chalk';
import { EOL } from 'os';
import { relative } from 'path';
import { CWD } from '../constants';
import { CWD, ICON } from '../constants';
import type { Source } from '../lib/get-input/get-wrappers';
import type { Disk } from './disk';

Expand All @@ -18,8 +18,8 @@ export function writeIfChanged(disk: Disk, fileData: FileData): void {
const after = `${JSON.stringify(contents, null, indent)}${EOL}`;
if (json !== after) {
disk.writeFileSync(filePath, after);
console.log(chalk.green('✓'), shortPath);
console.log(chalk.green(ICON.tick), shortPath);
} else {
console.log(chalk.dim('-'), chalk.dim(shortPath));
console.log(chalk.dim(ICON.skip), chalk.dim(shortPath));
}
}

0 comments on commit 81160b5

Please sign in to comment.