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 ba392bc commit 1405e7d
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 76 deletions.
62 changes: 40 additions & 22 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 All @@ -17,9 +17,7 @@ It supports the following package managers:

1. If you haven't already, install [@code-pushup/cli](../cli/README.md) and create a configuration file.

2. Insert plugin configuration. By default, `audit` and `outdated` commands will be run.

Default configuration will look as follows:
2. Insert plugin configuration with your package manager. By default, both `audit` and `outdated` checks will be run. The result should look as follows:

```js
import jsPackagesPlugin from '@code-pushup/js-packages-plugin';
Expand All @@ -28,14 +26,12 @@ It supports the following package managers:
// ...
plugins: [
// ...
await jsPackagesPlugin(),
await jsPackagesPlugin({ packageManager: 'npm' }), // replace with your package manager
],
};
```

You may run this plugin with a custom configuration for any supported package manager or command.

A custom configuration will look similarly to the following:
You may run this plugin with a custom configuration for any supported package manager or command. A custom configuration will look similarly to the following:

```js
import jsPackagesPlugin from '@code-pushup/js-packages-plugin';
Expand All @@ -49,7 +45,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 @@ -58,17 +54,30 @@ It supports the following package managers:
// ...
categories: [
{
slug: 'dependencies',
title: 'Package dependencies',
slug: 'security',
title: 'Security',
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,
},
],
},
{
slug: 'up-to-date',
title: 'Up-to-date tools',
refs: [
{
type: 'group',
plugin: 'npm-outdated', // replace prefix with your package manager
slug: 'js-packages',
weight: 1,
},
// ...
],
},
// ...
],
};
Expand All @@ -82,16 +91,13 @@ It supports the following package managers:

The plugin accepts the following parameters:

- (optional) `packageManager`: The package manager you are using. Supported values: `npm`, `yarn-classic` (v1), `yarn-modern` (v2+), `pnpm`. Default is `npm`.
- `packageManager`: The package manager you are using. Supported values: `npm`, `yarn-classic` (v1), `yarn-modern` (v2+), `pnpm`.
- (optional) `checks`: Array of checks to be run. Supported commands: `audit`, `outdated`. Both are configured by default.
- (optional) `auditLevelMapping`: If you wish to set a custom level of issue severity based on audit vulnerability level, you may do so here. Any omitted values will be filled in by defaults. Audit levels are: `critical`, `high`, `moderate`, `low` and `info`. Issue severities are: `error`, `warn` and `info`. By default the mapping is as follows: `critical` and `high``error`; `moderate` and `low``warning`; `info``info`.

> [!NOTE]
> All parameters are optional so the plugin can be called with no arguments in the default setting.
### 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
6 changes: 3 additions & 3 deletions packages/plugin-js-packages/src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ export const jsPackagesPluginConfigSchema = z.object({
})
.min(1)
.default(['audit', 'outdated']),
packageManager: packageManagerSchema
.describe('Package manager to be used. Defaults to npm')
.default('npm'),
packageManager: packageManagerSchema.describe('Package manager to be used.'),
auditLevelMapping: z
.record(packageAuditLevelSchema, issueSeveritySchema, {
description:
Expand All @@ -68,3 +66,5 @@ export type JSPackagesPluginConfig = z.input<
export type FinalJSPackagesPluginConfig = z.infer<
typeof jsPackagesPluginConfigSchema
>;

export type PackageDependencyType = 'prod' | 'dev' | 'optional';
19 changes: 14 additions & 5 deletions packages/plugin-js-packages/src/lib/config.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ describe('jsPackagesPluginConfigSchema', () => {
});

it('should accept a minimal JS package configuration', () => {
expect(() => jsPackagesPluginConfigSchema.parse({})).not.toThrow();
expect(() =>
jsPackagesPluginConfigSchema.parse({
packageManager: 'pnpm',
} satisfies JSPackagesPluginConfig),
).not.toThrow();
});

it('should fill in default values', () => {
const config = jsPackagesPluginConfigSchema.parse({});
const config = jsPackagesPluginConfigSchema.parse({
packageManager: 'npm',
});
expect(config).toEqual<FinalJSPackagesPluginConfig>({
checks: ['audit', 'outdated'],
packageManager: 'npm',
Expand All @@ -39,9 +45,12 @@ describe('jsPackagesPluginConfigSchema', () => {
});

it('should throw for no passed commands', () => {
expect(() => jsPackagesPluginConfigSchema.parse({ checks: [] })).toThrow(
'too_small',
);
expect(() =>
jsPackagesPluginConfigSchema.parse({
packageManager: 'yarn-classic',
checks: [],
}),
).toThrow('too_small');
});
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MaterialIcon } from '@code-pushup/models';
import { PackageManager } from './config';
import { PackageDependencyType, PackageManager } from './config';

export const pkgManagerNames: Record<PackageManager, string> = {
npm: 'NPM',
Expand All @@ -25,7 +25,7 @@ export const auditDocs: Record<PackageManager, string> = {
npm: 'https://docs.npmjs.com/cli/commands/npm-audit',
'yarn-classic': 'https://classic.yarnpkg.com/docs/cli/audit',
'yarn-modern': 'https://yarnpkg.com/cli/npm/audit',
pnpm: 'https://pnpm.io/',
pnpm: 'https://pnpm.io/cli/audit/',
};

export const outdatedDocs: Record<PackageManager, string> = {
Expand All @@ -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 dependencyDocs: Record<PackageDependencyType, string> = {
prod: 'https://classic.yarnpkg.com/docs/dependency-types#toc-dependencies',
dev: 'https://classic.yarnpkg.com/docs/dependency-types#toc-devdependencies',
optional:
'https://classic.yarnpkg.com/docs/dependency-types#toc-optionaldependencies',
};
119 changes: 88 additions & 31 deletions packages/plugin-js-packages/src/lib/js-packages-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,39 @@ import { name, version } from '../../package.json';
import {
JSPackagesPluginConfig,
PackageCommand,
PackageDependencyType,
PackageManager,
jsPackagesPluginConfigSchema,
} from './config';
import { createRunnerConfig } from './runner';
import {
auditDocs,
dependencyDocs,
outdatedDocs,
pkgManagerDocs,
pkgManagerIcons,
pkgManagerNames,
} from './utils';
} from './constants';
import { createRunnerConfig } from './runner';

/**
* Instantiates Code PushUp JS packages plugin for core config.
*
* @example
* import coveragePlugin from '@code-pushup/js-packages-plugin'
* import jsPackagesPlugin from '@code-pushup/js-packages-plugin'
*
* export default {
* // ... core config ...
* plugins: [
* // ... other plugins ...
* await jsPackagesPlugin()
* await jsPackagesPlugin({ packageManager: 'npm' })
* ]
* }
*
* @returns Plugin configuration.
*/

export async function jsPackagesPlugin(
config: JSPackagesPluginConfig = {},
config: JSPackagesPluginConfig,
): Promise<PluginConfig> {
const jsPackagesPluginConfig = jsPackagesPluginConfigSchema.parse(config);
const pkgManager = jsPackagesPluginConfig.packageManager;
Expand All @@ -44,43 +48,96 @@ export async function jsPackagesPlugin(
'bin.js',
);

const audits: Record<PackageCommand, Audit> = {
return {
slug: 'js-packages',
title: 'Plugin for JS packages',
icon: pkgManagerIcons[pkgManager],
description:
'This plugin runs audit to uncover vulnerabilities and lists outdated dependencies. It supports npm, yarn classic and berry, pnpm package managers.',
docsUrl: pkgManagerDocs[pkgManager],
packageName: name,
version,
audits: createAudits(pkgManager, checks),
groups: createGroups(pkgManager, checks),
runner: await createRunnerConfig(runnerScriptPath, jsPackagesPluginConfig),
};
}

function createGroups(
pkgManager: PackageManager,
checks: PackageCommand[],
): Group[] {
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 checks.map(check => groups[check]);
}

return {
slug: 'js-packages',
title: 'Plugin for JS packages',
icon: pkgManagerIcons[pkgManager],
description:
'This plugin runs audit to uncover vulnerabilities and lists outdated dependencies. It supports npm, yarn classic and berry, pnpm package managers.',
docsUrl: pkgManagerDocs[pkgManager],
packageName: name,
version,
audits: checks.map(check => audits[check]),
groups: [group],
runner: await createRunnerConfig(runnerScriptPath, jsPackagesPluginConfig),
};
function createAudits(
pkgManager: PackageManager,
checks: PackageCommand[],
): Audit[] {
return checks.flatMap(check => [
{
slug: `${pkgManager}-${check}-prod`,
title: getAuditTitle(pkgManager, check, 'prod'),
description: getAuditDescription(check, 'prod'),
docsUrl: dependencyDocs.prod,
},
{
slug: `${pkgManager}-${check}-dev`,
title: getAuditTitle(pkgManager, check, 'dev'),
description: getAuditDescription(check, 'dev'),
docsUrl: dependencyDocs.dev,
},
{
slug: `${pkgManager}-${check}-optional`,
title: getAuditTitle(pkgManager, check, 'optional'),
description: getAuditDescription(check, 'optional'),
docsUrl: dependencyDocs.optional,
},
]);
}

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

function getAuditDescription(
check: PackageCommand,
dependencyType: PackageDependencyType,
) {
return check === 'audit'
? `Runs security audit on ${dependencyType} dependencies.`
: `Checks for outdated ${dependencyType} dependencies`;
}
Loading

0 comments on commit 1405e7d

Please sign in to comment.