Skip to content

Commit

Permalink
feat(plugin-js-packages): use group per check, audit per dependency g…
Browse files Browse the repository at this point in the history
…roup
  • Loading branch information
Tlacenka committed Mar 11, 2024
1 parent 31a0c4f commit a23c158
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 38 deletions.
36 changes: 27 additions & 9 deletions packages/plugin-js-packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

📦 **Code PushUp plugin for JavaScript packages.** 🛡️

This plugin allows you to list outdated dependencies and run audit for known vulnerabilities.
This plugin checks for known vulnerabilities and outdated dependencies.
It supports the following package managers:

- [NPM](https://docs.npmjs.com/)
Expand Down Expand Up @@ -49,7 +49,7 @@ It supports the following package managers:
};
```

3. (Optional) Reference individual audits or the provided plugin group which you wish to include in custom categories (use `npx code-pushup print-config` to list audits and groups).
3. (Optional) Reference individual audits or the provided plugin groups which you wish to include in custom categories (use `npx code-pushup print-config` to list audits and groups).

💡 Assign weights based on what influence each command should have on the overall category score (assign weight 0 to only include as extra info, without influencing category score).

Expand All @@ -63,7 +63,13 @@ It supports the following package managers:
refs: [
{
type: 'group',
plugin: 'npm-package-manager', // replace prefix with your package manager
plugin: 'npm-audit', // replace prefix with your package manager
slug: 'js-packages',
weight: 1,
},
{
type: 'group',
plugin: 'npm-outdated', // replace prefix with your package manager
slug: 'js-packages',
weight: 1,
},
Expand Down Expand Up @@ -91,7 +97,7 @@ The plugin accepts the following parameters:

### Audits and group

This plugin provides a group for convenient declaration in your config. When defined this way, all measured coverage type audits have the same weight.
This plugin provides a group per check for a convenient declaration in your config.

```ts
// ...
Expand All @@ -103,7 +109,13 @@ This plugin provides a group for convenient declaration in your config. When def
{
type: 'group',
plugin: 'js-packages',
slug: 'npm-package-manager', // replace prefix with your package manager
slug: 'npm-audit', // replace prefix with your package manager
weight: 1,
},
{
type: 'group',
plugin: 'js-packages',
slug: 'npm-outdated', // replace prefix with your package manager
weight: 1,
},
// ...
Expand All @@ -113,7 +125,7 @@ This plugin provides a group for convenient declaration in your config. When def
],
```

Each package manager command still has its own audit. So when you want to include a subset of commands or assign different weights to them, you can do so in the following way:
Each dependency group has its own audit. If you want to check only a subset of dependencies (e.g. run audit and outdated for production dependencies) or assign different weights to them, you can do so in the following way:

```ts
// ...
Expand All @@ -125,15 +137,21 @@ Each package manager command still has its own audit. So when you want to includ
{
type: 'audit',
plugin: 'js-packages',
slug: 'npm-audit', // replace prefix with your package manager
slug: 'npm-audit-prod', // replace prefix with your package manager
weight: 2,
},
{
{
type: 'audit',
plugin: 'js-packages',
slug: 'npm-outdated', // replace prefix with your package manager
slug: 'npm-audit-dev', // replace prefix with your package manager
weight: 1,
},
{
type: 'audit',
plugin: 'js-packages',
slug: 'npm-outdated-prod', // replace prefix with your package manager
weight: 2,
},
// ...
],
},
Expand Down
76 changes: 60 additions & 16 deletions packages/plugin-js-packages/src/lib/js-packages-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { name, version } from '../../package.json';
import {
JSPackagesPluginConfig,
PackageCommand,
PackageManager,
jsPackagesPluginConfigSchema,
} from './config';
import { createRunnerConfig } from './runner';
import {
auditDocs,
groupDepDocs,
outdatedDocs,
pkgManagerDocs,
pkgManagerIcons,
Expand All @@ -32,6 +34,7 @@ import {
*
* @returns Plugin configuration.
*/
// eslint-disable-next-line max-lines-per-function
export async function jsPackagesPlugin(
config: JSPackagesPluginConfig = {},
): Promise<PluginConfig> {
Expand All @@ -44,32 +47,54 @@ export async function jsPackagesPlugin(
'bin.js',
);

const audits: Record<PackageCommand, Audit> = {
const audits: Audit[] = checks.flatMap(check => [
{
slug: `${pkgManager}-${check}-prod`,
title: getAuditTitle(pkgManager, check, 'prod'),
description: getAuditDescription(check, 'prod'),
docsUrl: groupDepDocs[pkgManager],
},
{
slug: `${pkgManager}-${check}-dev`,
title: getAuditTitle(pkgManager, check, 'dev'),
description: getAuditDescription(check, 'dev'),
docsUrl: groupDepDocs[pkgManager],
},
{
slug: `${pkgManager}-${check}-optional`,
title: getAuditTitle(pkgManager, check, 'optional'),
description: getAuditDescription(check, 'optional'),
docsUrl: groupDepDocs[pkgManager],
},
]);

const groups: Record<PackageCommand, Group> = {
audit: {
slug: `${pkgManager}-audit`,
title: `${pkgManagerNames[pkgManager]} audit`,
description: `Lists ${pkgManagerNames[pkgManager]} audit vulnerabilities.`,
description: `Group containing ${pkgManagerNames[pkgManager]} vulnerabilities.`,
docsUrl: auditDocs[pkgManager],
refs: [
// eslint-disable-next-line no-magic-numbers
{ slug: `${pkgManager}-audit-prod`, weight: 8 },
{ slug: `${pkgManager}-audit-dev`, weight: 1 },
{ slug: `${pkgManager}-audit-optional`, weight: 1 },
],
},
outdated: {
slug: `${pkgManager}-outdated`,
title: `${pkgManagerNames[pkgManager]} outdated dependencies`,
description: `Lists ${pkgManagerNames[pkgManager]} outdated dependencies.`,
description: `Group containing outdated ${pkgManagerNames[pkgManager]} dependencies.`,
docsUrl: outdatedDocs[pkgManager],
refs: [
// eslint-disable-next-line no-magic-numbers
{ slug: `${pkgManager}-outdated-prod`, weight: 8 },
{ slug: `${pkgManager}-outdated-dev`, weight: 1 },
{ slug: `${pkgManager}-outdated-optional`, weight: 1 },
],
},
};

const group: Group = {
slug: `${pkgManager}-package-manager`,
title: `${pkgManagerNames[pkgManager]} package manager`,
description: `Group containing both audit and dependencies command audits for the ${pkgManagerNames[pkgManager]} package manager.`,
docsUrl: pkgManagerDocs[pkgManager],
refs: checks.map(check => ({
slug: `${pkgManager}-${check}`,
weight: 1,
})),
};

return {
slug: 'js-packages',
title: 'Plugin for JS packages',
Expand All @@ -79,8 +104,27 @@ export async function jsPackagesPlugin(
docsUrl: pkgManagerDocs[pkgManager],
packageName: name,
version,
audits: checks.map(check => audits[check]),
groups: [group],
audits,
groups: checks.map(check => groups[check]),
runner: await createRunnerConfig(runnerScriptPath, jsPackagesPluginConfig),
};
}

function getAuditTitle(
pkgManager: PackageManager,
check: PackageCommand,
depGroup: 'prod' | 'dev' | 'optional',
) {
return check === 'audit'
? `Vulnerabilities for ${pkgManagerNames[pkgManager]} ${depGroup} dependencies.`
: `Outdated ${pkgManagerNames[pkgManager]} ${depGroup} dependencies.`;
}

function getAuditDescription(
check: PackageCommand,
depGroup: 'prod' | 'dev' | 'optional',
) {
return check === 'audit'
? `Runs security audit on ${depGroup} dependencies.`
: `Checks for outdated ${depGroup} dependencies`;
}
43 changes: 30 additions & 13 deletions packages/plugin-js-packages/src/lib/js-packages-plugin.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,35 +24,52 @@ describe('jsPackagesPlugin', () => {
);
});

it('should set package manager and commands based on configuration', async () => {
it('should create a group for both npm audit and outdated when no configuration is provided', async () => {
await expect(jsPackagesPlugin()).resolves.toStrictEqual(
expect.objectContaining<Partial<PluginConfig>>({
groups: [
expect.objectContaining<Partial<Group>>({
slug: 'npm-audit',
}),
expect.objectContaining<Partial<Group>>({
slug: 'npm-outdated',
}),
],
}),
);
});

it('should configure a group based on package manager and chosen check', async () => {
await expect(
jsPackagesPlugin({ packageManager: 'yarn-classic', checks: ['audit'] }),
jsPackagesPlugin({ packageManager: 'yarn-modern', checks: ['outdated'] }),
).resolves.toStrictEqual(
expect.objectContaining({
audits: [expect.objectContaining({ slug: 'yarn-classic-audit' })],
groups: [
expect.objectContaining<Partial<Group>>({
slug: 'yarn-classic-package-manager',
refs: [{ slug: 'yarn-classic-audit', weight: 1 }],
slug: 'yarn-modern-outdated',
}),
],
}),
);
});

it('should use npm with both audit and outdated commands when no configuration is provided', async () => {
await expect(jsPackagesPlugin()).resolves.toStrictEqual(
expect.objectContaining<Partial<PluginConfig>>({
it('should create an audit for each dependency group', async () => {
await expect(
jsPackagesPlugin({ packageManager: 'yarn-classic', checks: ['audit'] }),
).resolves.toStrictEqual(
expect.objectContaining({
audits: [
expect.objectContaining({ slug: 'npm-audit' }),
expect.objectContaining({ slug: 'npm-outdated' }),
expect.objectContaining({ slug: 'yarn-classic-audit-prod' }),
expect.objectContaining({ slug: 'yarn-classic-audit-dev' }),
expect.objectContaining({ slug: 'yarn-classic-audit-optional' }),
],
groups: [
expect.objectContaining<Partial<Group>>({
slug: 'npm-package-manager',
slug: 'yarn-classic-audit',
refs: [
{ slug: 'npm-audit', weight: 1 },
{ slug: 'npm-outdated', weight: 1 },
{ slug: 'yarn-classic-audit-prod', weight: 8 },
{ slug: 'yarn-classic-audit-dev', weight: 1 },
{ slug: 'yarn-classic-audit-optional', weight: 1 },
],
}),
],
Expand Down
7 changes: 7 additions & 0 deletions packages/plugin-js-packages/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,10 @@ export const outdatedDocs: Record<PackageManager, string> = {
'yarn-modern': 'https://github.com/mskelton/yarn-plugin-outdated',
pnpm: 'https://pnpm.io/cli/outdated',
};

export const groupDepDocs: Record<PackageManager, string> = {
npm: 'https://docs.npmjs.com/cli/using-npm/config#include',
'yarn-classic': 'https://classic.yarnpkg.com/docs/usage',
'yarn-modern': 'https://yarnpkg.com/cli/npm/audit#options',
pnpm: 'https://pnpm.io/cli/audit#options',
};

0 comments on commit a23c158

Please sign in to comment.