diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 94755e2f1..4865fae94 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -13,15 +13,13 @@ jobs: fail-fast: false matrix: lib: - [ - cli, - core, - models, - utils, - plugin-eslint, - plugin-coverage, - plugin-js-packages, - ] + - cli + - core + - models + - utils + - plugin-eslint + - plugin-coverage + - plugin-js-packages scope: [unit, integration] name: Update code coverage runs-on: ubuntu-latest diff --git a/packages/plugin-js-packages/README.md b/packages/plugin-js-packages/README.md index 4ab3dae01..8eb9ca87e 100644 --- a/packages/plugin-js-packages/README.md +++ b/packages/plugin-js-packages/README.md @@ -7,13 +7,17 @@ 📦 **Code PushUp plugin for JavaScript packages.** 🛡️ This plugin allows you to list outdated dependencies and run audit for known vulnerabilities. -It supports the following package managers: npm, yarn, yarn berry, pnpm. +It supports the following package managers: + +- [NPM](https://docs.npmjs.com/) +- [Yarn v1](https://classic.yarnpkg.com/docs/) & [Yarn v2+](https://yarnpkg.com/getting-started) +- [PNPM](https://pnpm.io/pnpm-cli) ## Getting started 1. If you haven't already, install [@code-pushup/cli](../cli/README.md) and create a configuration file. -2. Insert plugin configuration. By default, npm audit and npm outdated commands will be run. +2. Insert plugin configuration. By default, `audit` and `outdated` commands will be run. Default configuration will look as follows: @@ -40,7 +44,7 @@ It supports the following package managers: npm, yarn, yarn berry, pnpm. // ... plugins: [ // ... - await jsPackagesPlugin({ packageManager: ['yarn'], features: ['audit'] }), + await jsPackagesPlugin({ packageManager: ['yarn'], checks: ['audit'] }), ], }; ``` @@ -78,8 +82,8 @@ It supports the following package managers: npm, yarn, yarn berry, pnpm. The plugin accepts the following parameters: -- (optional) `packageManager`: The package manager you are using. Supported values: `npm`, `yarn` (v1), `yarn-berry` (v2+), `pnpm`. Default is `npm`. -- (optional) `features`: Array of commands to be run. Supported commands: `audit`, `outdated`. Both are configured by default. +- (optional) `packageManager`: The package manager you are using. Supported values: `npm`, `yarn-classic` (v1), `yarn-modern` (v2+), `pnpm`. Default is `npm`. +- (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] diff --git a/packages/plugin-js-packages/src/lib/config.ts b/packages/plugin-js-packages/src/lib/config.ts index 7cfd4a868..41fbcd8b3 100644 --- a/packages/plugin-js-packages/src/lib/config.ts +++ b/packages/plugin-js-packages/src/lib/config.ts @@ -4,7 +4,12 @@ import { IssueSeverity, issueSeveritySchema } from '@code-pushup/models'; const packageCommandSchema = z.enum(['audit', 'outdated']); export type PackageCommand = z.infer; -const packageManagerSchema = z.enum(['npm', 'yarn', 'yarn-berry', 'pnpm']); +const packageManagerSchema = z.enum([ + 'npm', + 'yarn-classic', + 'yarn-modern', + 'pnpm', +]); export type PackageManager = z.infer; const packageAuditLevelSchema = z.enum([ @@ -36,26 +41,8 @@ export function fillAuditLevelMapping( }; } -// TODO how? -// export function objectKeys(obj: T): (keyof T)[] { -// return Object.keys(obj) as (keyof T)[]; -// } - -// function newFillAuditLevelMapping( -// mapping: Partial>, -// ): Record { -// return Object.fromEntries( -// objectKeys(defaultAuditLevelMapping).map< -// [PackageAuditLevel, IssueSeverity] -// >(auditLevel => [ -// auditLevel, -// mapping[auditLevel] ?? defaultAuditLevelMapping[auditLevel], -// ]), -// ); -// } - export const jsPackagesPluginConfigSchema = z.object({ - features: z + checks: z .array(packageCommandSchema, { description: 'Package manager commands to be run. Defaults to both audit and outdated.', diff --git a/packages/plugin-js-packages/src/lib/config.unit.test.ts b/packages/plugin-js-packages/src/lib/config.unit.test.ts index 25f233bae..36f82cb57 100644 --- a/packages/plugin-js-packages/src/lib/config.unit.test.ts +++ b/packages/plugin-js-packages/src/lib/config.unit.test.ts @@ -13,8 +13,8 @@ describe('jsPackagesPluginConfigSchema', () => { expect(() => jsPackagesPluginConfigSchema.parse({ auditLevelMapping: { moderate: 'error' }, - features: ['audit'], - packageManager: 'yarn', + checks: ['audit'], + packageManager: 'yarn-classic', } satisfies JSPackagesPluginConfig), ).not.toThrow(); }); @@ -26,7 +26,7 @@ describe('jsPackagesPluginConfigSchema', () => { it('should fill in default values', () => { const config = jsPackagesPluginConfigSchema.parse({}); expect(config).toEqual({ - features: ['audit', 'outdated'], + checks: ['audit', 'outdated'], packageManager: 'npm', auditLevelMapping: { critical: 'error', @@ -38,8 +38,8 @@ describe('jsPackagesPluginConfigSchema', () => { }); }); - it('should throw for no features', () => { - expect(() => jsPackagesPluginConfigSchema.parse({ features: [] })).toThrow( + it('should throw for no passed commands', () => { + expect(() => jsPackagesPluginConfigSchema.parse({ checks: [] })).toThrow( 'too_small', ); }); diff --git a/packages/plugin-js-packages/src/lib/js-packages-plugin.ts b/packages/plugin-js-packages/src/lib/js-packages-plugin.ts index bfd0dc59c..056945ea4 100644 --- a/packages/plugin-js-packages/src/lib/js-packages-plugin.ts +++ b/packages/plugin-js-packages/src/lib/js-packages-plugin.ts @@ -8,7 +8,13 @@ import { jsPackagesPluginConfigSchema, } from './config'; import { createRunnerConfig } from './runner'; -import { auditDocs, outdatedDocs, pkgManagerDocs } from './utils'; +import { + auditDocs, + outdatedDocs, + pkgManagerDocs, + pkgManagerIcons, + pkgManagerNames, +} from './utils'; /** * Instantiates Code PushUp JS packages plugin for core config. @@ -31,7 +37,7 @@ export async function jsPackagesPlugin( ): Promise { const jsPackagesPluginConfig = jsPackagesPluginConfigSchema.parse(config); const pkgManager = jsPackagesPluginConfig.packageManager; - const features = [...new Set(jsPackagesPluginConfig.features)]; + const checks = [...new Set(jsPackagesPluginConfig.checks)]; const runnerScriptPath = join( fileURLToPath(dirname(import.meta.url)), @@ -41,25 +47,25 @@ export async function jsPackagesPlugin( const audits: Record = { audit: { slug: `${pkgManager}-audit`, - title: `${pkgManager} audit`, - description: `Lists ${pkgManager} audit vulnerabilities.`, + title: `${pkgManagerNames[pkgManager]} audit`, + description: `Lists ${pkgManagerNames[pkgManager]} audit vulnerabilities.`, docsUrl: auditDocs[pkgManager], }, outdated: { slug: `${pkgManager}-outdated`, - title: `${pkgManager} outdated dependencies`, - description: `Lists ${pkgManager} outdated dependencies.`, + title: `${pkgManagerNames[pkgManager]} outdated dependencies`, + description: `Lists ${pkgManagerNames[pkgManager]} outdated dependencies.`, docsUrl: outdatedDocs[pkgManager], }, }; const group: Group = { slug: `${pkgManager}-package-manager`, - title: `${pkgManager} package manager`, - description: `Group containing both audit and dependencies command audits for the ${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: features.map(feature => ({ - slug: `${pkgManager}-${feature}`, + refs: checks.map(check => ({ + slug: `${pkgManager}-${check}`, weight: 1, })), }; @@ -67,14 +73,13 @@ export async function jsPackagesPlugin( return { slug: 'js-packages', title: 'Plugin for JS packages', - icon: - pkgManager === 'npm' ? 'npm' : pkgManager === 'pnpm' ? 'pnpm' : 'yarn', + 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: features.map(feature => audits[feature]), + audits: checks.map(check => audits[check]), groups: [group], runner: await createRunnerConfig(runnerScriptPath, jsPackagesPluginConfig), }; diff --git a/packages/plugin-js-packages/src/lib/js-packages-plugin.unit.test.ts b/packages/plugin-js-packages/src/lib/js-packages-plugin.unit.test.ts index 0d8877c4b..973f4aafb 100644 --- a/packages/plugin-js-packages/src/lib/js-packages-plugin.unit.test.ts +++ b/packages/plugin-js-packages/src/lib/js-packages-plugin.unit.test.ts @@ -12,7 +12,7 @@ vi.mock('./runner/index.ts', () => ({ describe('jsPackagesPlugin', () => { it('should initialise a JS packages plugin', async () => { await expect( - jsPackagesPlugin({ packageManager: 'npm', features: ['outdated'] }), + jsPackagesPlugin({ packageManager: 'npm', checks: ['outdated'] }), ).resolves.toStrictEqual( expect.objectContaining({ slug: 'js-packages', @@ -26,14 +26,14 @@ describe('jsPackagesPlugin', () => { it('should set package manager and commands based on configuration', async () => { await expect( - jsPackagesPlugin({ packageManager: 'yarn', features: ['audit'] }), + jsPackagesPlugin({ packageManager: 'yarn-classic', checks: ['audit'] }), ).resolves.toStrictEqual( expect.objectContaining({ - audits: [expect.objectContaining({ slug: 'yarn-audit' })], + audits: [expect.objectContaining({ slug: 'yarn-classic-audit' })], groups: [ expect.objectContaining>({ - slug: 'yarn-package-manager', - refs: [{ slug: 'yarn-audit', weight: 1 }], + slug: 'yarn-classic-package-manager', + refs: [{ slug: 'yarn-classic-audit', weight: 1 }], }), ], }), diff --git a/packages/plugin-js-packages/src/lib/utils.ts b/packages/plugin-js-packages/src/lib/utils.ts index d1c94866a..b219e3992 100644 --- a/packages/plugin-js-packages/src/lib/utils.ts +++ b/packages/plugin-js-packages/src/lib/utils.ts @@ -1,21 +1,36 @@ +import { MaterialIcon } from '@code-pushup/models'; import { PackageManager } from './config'; +export const pkgManagerNames: Record = { + npm: 'NPM', + 'yarn-classic': 'Yarn v1', + 'yarn-modern': 'Yarn v2+', + pnpm: 'PNPM', +}; + +export const pkgManagerIcons: Record = { + npm: 'npm', + 'yarn-classic': 'yarn', + 'yarn-modern': 'yarn', + pnpm: 'pnpm', +}; + export const pkgManagerDocs: Record = { npm: 'https://docs.npmjs.com/', - yarn: 'https://classic.yarnpkg.com/lang/en/docs/', - 'yarn-berry': 'https://yarnpkg.com/getting-started', + 'yarn-classic': 'https://classic.yarnpkg.com/docs/', + 'yarn-modern': 'https://yarnpkg.com/getting-started', pnpm: 'https://pnpm.io/pnpm-cli', }; export const auditDocs: Record = { - npm: 'https://docs.npmjs.com/cli/v10/commands/npm-audit', - yarn: 'https://classic.yarnpkg.com/en/docs/cli/audit', - 'yarn-berry': 'https://yarnpkg.com/cli/npm/audit', + 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/', }; export const outdatedDocs: Record = { - npm: 'https://docs.npmjs.com/cli/v10/commands/npm-outdated', - yarn: 'https://classic.yarnpkg.com/lang/en/docs/cli/outdated/', - 'yarn-berry': 'https://github.com/mskelton/yarn-plugin-outdated', + npm: 'https://docs.npmjs.com/cli/commands/npm-outdated', + 'yarn-classic': 'https://classic.yarnpkg.com/docs/cli/outdated/', + 'yarn-modern': 'https://github.com/mskelton/yarn-plugin-outdated', pnpm: 'https://pnpm.io/cli/outdated', };