Skip to content

Commit

Permalink
fix: fail early for top level deps out of sync pnpm and updated tests
Browse files Browse the repository at this point in the history
  • Loading branch information
gemaxim committed Aug 13, 2024
1 parent 01b8757 commit f3f5193
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 126 deletions.
16 changes: 16 additions & 0 deletions lib/dep-graph-builders/pnpm/build-dep-graph-pnpm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ import { getPnpmChildNode } from './utils';
import { eventLoopSpinner } from 'event-loop-spinner';
import { PnpmLockfileParser } from './lockfile-parser/lockfile-parser';
import { NormalisedPnpmPkgs, PnpmNode } from './types';
import { OpenSourceEcosystems } from '@snyk/error-catalog-nodejs-public';
import {
INSTALL_COMMAND,
LOCK_FILE_NAME,
} from '../../errors/out-of-sync-error';
import { LockfileType } from '../..';

export const buildDepGraphPnpm = async (
lockFileParser: PnpmLockfileParser,
Expand Down Expand Up @@ -41,6 +47,16 @@ export const buildDepGraphPnpm = async (
) || {};

for (const name of Object.keys(topLevelDeps)) {
if (!extractedTopLevelDeps[name]) {
throw new OpenSourceEcosystems.PnpmOutOfSyncError(
`Dependency ${name} was not found in ` +
`${LOCK_FILE_NAME[LockfileType.pnpm]}. Your package.json and ` +
`${
LOCK_FILE_NAME[LockfileType.pnpm]
} are probably out of sync. Please run ` +
`"${INSTALL_COMMAND[LockfileType.pnpm]}" and try again.`,
);
}
topLevelDeps[name].version = extractedTopLevelDeps[name].version;
}

Expand Down
9 changes: 0 additions & 9 deletions lib/dep-graph-builders/pnpm/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,6 @@ export const getPnpmChildNode = (
resolvedVersion = pkgData.version;
}
if (!pkgs[childNodeKey]) {
if (lockfileParser.isWorkspaceLockfile()) {
return {
id: childNodeKey,
name: name,
version: resolvedVersion,
dependencies: {},
isDev: depInfo.isDev,
};
}
if (strictOutOfSync && !/^file:/.test(depInfo.version)) {
const errMessage =
`Dependency ${childNodeKey} was not found in ` +
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 21 additions & 27 deletions test/jest/dep-graph-builders/npm-lock-v2.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { join } from 'path';
import { readFileSync } from 'fs';
import { parseNpmLockV2Project } from '../../../lib/';
import {
InvalidUserInputError,
LockfileType,
OutOfSyncError,
parseNpmLockV2Project,
} from '../../../lib/';

describe('dep-graph-builder npm-lock-v2', () => {
describe('Happy path tests', () => {
Expand Down Expand Up @@ -397,19 +402,18 @@ describe('dep-graph-builder npm-lock-v2', () => {
'utf8',
);
const npmLockContent = '';
try {
await parseNpmLockV2Project(pkgJsonContent, npmLockContent, {
await expect(
parseNpmLockV2Project(pkgJsonContent, npmLockContent, {
includeDevDeps: false,
includeOptionalDeps: true,
pruneCycles: true,
strictOutOfSync: false,
});
} catch (err) {
expect((err as Error).message).toBe(
}),
).rejects.toThrow(
new InvalidUserInputError(
'package.json parsing failed with error Unexpected token } in JSON at position 100',
);
expect((err as Error).name).toBe('InvalidUserInputError');
}
),
);
});

it('project: simple-non-top-level-out-of-sync -> throws OutOfSyncError', async () => {
Expand All @@ -425,19 +429,14 @@ describe('dep-graph-builder npm-lock-v2', () => {
),
'utf8',
);
try {
await parseNpmLockV2Project(pkgJsonContent, npmLockContent, {
await expect(
parseNpmLockV2Project(pkgJsonContent, npmLockContent, {
includeDevDeps: false,
includeOptionalDeps: true,
pruneCycles: true,
strictOutOfSync: true,
});
} catch (err) {
expect((err as Error).message).toBe(
'Dependency ms@0.6.2 was not found in package-lock.json. Your package.json and package-lock.json are probably out of sync. Please run "npm install" and try again.',
);
expect((err as Error).name).toBe('OutOfSyncError');
}
}),
).rejects.toThrow(new OutOfSyncError('ms@0.6.2', LockfileType.npm));
});

it('project: simple-top-level-out-of-sync -> throws OutOfSyncError', async () => {
Expand All @@ -453,19 +452,14 @@ describe('dep-graph-builder npm-lock-v2', () => {
),
'utf8',
);
try {
await parseNpmLockV2Project(pkgJsonContent, npmLockContent, {
await expect(
parseNpmLockV2Project(pkgJsonContent, npmLockContent, {
includeDevDeps: false,
includeOptionalDeps: true,
pruneCycles: true,
strictOutOfSync: true,
});
} catch (err) {
expect((err as Error).message).toBe(
'Dependency lodash@4.17.11 was not found in package-lock.json. Your package.json and package-lock.json are probably out of sync. Please run "npm install" and try again.',
);
expect((err as Error).name).toBe('OutOfSyncError');
}
}),
).rejects.toThrow(new OutOfSyncError('lodash@4.17.11', LockfileType.npm));
});
});
});
Expand Down
49 changes: 24 additions & 25 deletions test/jest/dep-graph-builders/pnpm-lock.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { join } from 'path';
import { readFileSync } from 'fs';
import { parsePnpmProject } from '../../../lib/dep-graph-builders';
import { OpenSourceEcosystems } from '@snyk/error-catalog-nodejs-public';
import { InvalidUserInputError } from '../../../lib';

describe.each(['pnpm-lock-v5', 'pnpm-lock-v6', 'pnpm-lock-v9'])(
'pnpm dep-graph-builder %s',
Expand Down Expand Up @@ -130,19 +132,18 @@ describe.each(['pnpm-lock-v5', 'pnpm-lock-v6', 'pnpm-lock-v9'])(
'utf8',
);
const pnpmLockContent = '';
try {
await parsePnpmProject(pkgJsonContent, pnpmLockContent, {
await expect(
parsePnpmProject(pkgJsonContent, pnpmLockContent, {
includeDevDeps: false,
includeOptionalDeps: true,
pruneWithinTopLevelDeps: true,
strictOutOfSync: false,
});
} catch (err) {
expect((err as Error).message).toBe(
}),
).rejects.toThrow(
new InvalidUserInputError(
'package.json parsing failed with error Unexpected token } in JSON at position 100',
);
expect((err as Error).name).toBe('InvalidUserInputError');
}
),
);
});
it('project: simple-non-top-level-out-of-sync -> throws OutOfSyncError', async () => {
const fixtureName = 'missing-non-top-level-deps';
Expand All @@ -160,19 +161,18 @@ describe.each(['pnpm-lock-v5', 'pnpm-lock-v6', 'pnpm-lock-v9'])(
),
'utf8',
);
try {
await parsePnpmProject(pkgJsonContent, pnpmLockContent, {
await expect(
parsePnpmProject(pkgJsonContent, pnpmLockContent, {
includeDevDeps: false,
includeOptionalDeps: true,
pruneWithinTopLevelDeps: true,
strictOutOfSync: true,
});
} catch (err) {
expect((err as Error).message).toBe(
}),
).rejects.toThrow(
new OpenSourceEcosystems.PnpmOutOfSyncError(
'Dependency ms@0.6.2 was not found in pnpm-lock.yaml. Your package.json and pnpm-lock.yaml are probably out of sync. Please run "pnpm install" and try again.',
);
expect((err as Error).name).toBe('OutOfSyncError');
}
),
);
});
it('project: simple-top-level-out-of-sync -> throws OutOfSyncError', async () => {
const fixtureName = 'missing-top-level-deps';
Expand All @@ -190,19 +190,18 @@ describe.each(['pnpm-lock-v5', 'pnpm-lock-v6', 'pnpm-lock-v9'])(
),
'utf8',
);
try {
await parsePnpmProject(pkgJsonContent, pnpmLockContent, {
await expect(
parsePnpmProject(pkgJsonContent, pnpmLockContent, {
includeDevDeps: false,
includeOptionalDeps: true,
pruneWithinTopLevelDeps: true,
strictOutOfSync: true,
});
} catch (err) {
expect((err as Error).message).toBe(
'Dependency lodash@4.17.11 was not found in pnpm-lock.yaml. Your package.json and pnpm-lock.yaml are probably out of sync. Please run "pnpm install" and try again.',
);
expect((err as Error).name).toBe('OutOfSyncError');
}
}),
).rejects.toThrow(
new OpenSourceEcosystems.PnpmOutOfSyncError(
'Dependency lodash was not found in pnpm-lock.yaml. Your package.json and pnpm-lock.yaml are probably out of sync. Please run "pnpm install" and try again.',
),
);
});
});
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { join } from 'path';
import { readFileSync } from 'fs';
import { createFromJSON } from '@snyk/dep-graph';
import { parseYarnLockV1Project } from '../../../lib';
import {
InvalidUserInputError,
LockfileType,
OutOfSyncError,
parseYarnLockV1Project,
} from '../../../lib';

describe('yarn.lock v1 "real projects"', () => {
describe('Expected Result tests', () => {
Expand Down Expand Up @@ -306,20 +311,19 @@ describe('Unhappy path tests', () => {
'utf8',
);
const yarnLockContent = '';
try {
await parseYarnLockV1Project(pkgJsonContent, yarnLockContent, {
await expect(
parseYarnLockV1Project(pkgJsonContent, yarnLockContent, {
includeDevDeps: false,
includeOptionalDeps: true,
includePeerDeps: false,
pruneLevel: 'cycles',
strictOutOfSync: false,
});
} catch (err) {
expect((err as Error).message).toBe(
}),
).rejects.toThrow(
new InvalidUserInputError(
'package.json parsing failed with error Unexpected token } in JSON at position 100',
);
expect((err as Error).name).toBe('InvalidUserInputError');
}
),
);
});

it('project: simple-top-level-out-of-sync -> throws OutOfSyncError', async () => {
Expand All @@ -338,20 +342,15 @@ describe('Unhappy path tests', () => {
),
'utf8',
);
try {
await parseYarnLockV1Project(pkgJsonContent, yarnLockContent, {
await expect(
parseYarnLockV1Project(pkgJsonContent, yarnLockContent, {
includeDevDeps: false,
includeOptionalDeps: true,
includePeerDeps: false,
pruneLevel: 'cycles',
strictOutOfSync: true,
});
} catch (err) {
expect((err as Error).message).toBe(
'Dependency lodash@4.17.11 was not found in yarn.lock. Your package.json and yarn.lock are probably out of sync. Please run "yarn install" and try again.',
);
expect((err as Error).name).toBe('OutOfSyncError');
}
}),
).rejects.toThrow(new OutOfSyncError('lodash@4.17.11', LockfileType.yarn));
});

it('project: simple-non-top-level-out-of-sync -> throws OutOfSyncError', async () => {
Expand All @@ -370,19 +369,14 @@ describe('Unhappy path tests', () => {
),
'utf8',
);
try {
await parseYarnLockV1Project(pkgJsonContent, yarnLockContent, {
await expect(
parseYarnLockV1Project(pkgJsonContent, yarnLockContent, {
includeDevDeps: false,
includeOptionalDeps: true,
includePeerDeps: false,
pruneLevel: 'cycles',
strictOutOfSync: true,
});
} catch (err) {
expect((err as Error).message).toBe(
'Dependency ms@0.6.2 was not found in yarn.lock. Your package.json and yarn.lock are probably out of sync. Please run "yarn install" and try again.',
);
expect((err as Error).name).toBe('OutOfSyncError');
}
}),
).rejects.toThrow(new OutOfSyncError('ms@0.6.2', LockfileType.yarn));
});
});
Loading

0 comments on commit f3f5193

Please sign in to comment.