-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7e55fd3
commit 7369585
Showing
6 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
packages/cli/src/lib/implementation/skip-plugins.middleware.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { filterItemRefsBy } from '@code-pushup/utils'; | ||
import { SkipPluginsOptions } from './skip-plugins.model'; | ||
import { validateSkipPluginsOption } from './skip-plugins.utils'; | ||
|
||
export function skipPluginsMiddleware<T extends SkipPluginsOptions>( | ||
originalProcessArgs: T, | ||
): T { | ||
const { categories = [], skipPlugins: originalSkipPlugins } = | ||
originalProcessArgs; | ||
|
||
if (originalSkipPlugins && originalSkipPlugins.length > 0) { | ||
const { verbose, plugins, skipPlugins = [] } = originalProcessArgs; | ||
|
||
validateSkipPluginsOption( | ||
{ plugins, categories }, | ||
{ skipPlugins, verbose }, | ||
); | ||
|
||
const validSkipPlugins = skipPlugins.filter(sP => | ||
plugins.find(p => p.slug === sP), | ||
); | ||
|
||
const skipPluginsSet = new Set(validSkipPlugins); | ||
|
||
return { | ||
...originalProcessArgs, | ||
plugins: | ||
skipPluginsSet.size > 0 | ||
? plugins.filter(({ slug }) => !skipPluginsSet.has(slug)) | ||
: plugins, | ||
categories: | ||
skipPluginsSet.size > 0 | ||
? filterItemRefsBy( | ||
categories, | ||
({ plugin }) => !skipPluginsSet.has(plugin), | ||
) | ||
: categories, | ||
}; | ||
} | ||
|
||
return { | ||
...originalProcessArgs, | ||
// if undefined fill categories with empty array | ||
categories, | ||
}; | ||
} |
98 changes: 98 additions & 0 deletions
98
packages/cli/src/lib/implementation/skip-plugins.middleware.unit.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { describe, expect, vi } from 'vitest'; | ||
import { CategoryConfig, PluginConfig } from '@code-pushup/models'; | ||
import { skipPluginsMiddleware } from './skip-plugins.middleware'; | ||
|
||
vi.mock('@code-pushup/core', async () => { | ||
const { CORE_CONFIG_MOCK }: typeof import('@code-pushup/test-utils') = | ||
await vi.importActual('@code-pushup/test-utils'); | ||
const core: object = await vi.importActual('@code-pushup/core'); | ||
return { | ||
...core, | ||
readRcByPath: vi.fn().mockResolvedValue(CORE_CONFIG_MOCK), | ||
autoloadRc: vi.fn().mockResolvedValue(CORE_CONFIG_MOCK), | ||
}; | ||
}); | ||
|
||
describe('skipPluginsMiddleware', () => { | ||
it('should fill undefined categories with empty array', () => { | ||
expect( | ||
skipPluginsMiddleware({ | ||
plugins: [{ slug: 'p1' } as PluginConfig], | ||
}), | ||
).toStrictEqual({ | ||
plugins: [{ slug: 'p1' }], | ||
categories: [], | ||
}); | ||
}); | ||
|
||
it('should forward equal values if not set', () => { | ||
expect( | ||
skipPluginsMiddleware({ | ||
plugins: [{ slug: 'p1' } as PluginConfig], | ||
categories: [ | ||
{ slug: 'c1', refs: [{ plugin: 'p1' }] } as CategoryConfig, | ||
], | ||
}), | ||
).toStrictEqual({ | ||
plugins: [{ slug: 'p1' }], | ||
categories: [{ slug: 'c1', refs: [{ plugin: 'p1' }] }], | ||
}); | ||
}); | ||
|
||
it('should filter plugins plugins for slug "p1"', () => { | ||
const { plugins } = skipPluginsMiddleware({ | ||
skipPlugins: ['p1'], | ||
plugins: [{ slug: 'p1' }, { slug: 'p2' }] as PluginConfig[], | ||
categories: [], | ||
}); | ||
expect(plugins).toStrictEqual([expect.objectContaining({ slug: 'p2' })]); | ||
}); | ||
|
||
it('should forward plugins and categories for a slug not present in plugins', () => { | ||
const originalCategories = [ | ||
{ | ||
slug: 'c1', | ||
refs: [ | ||
{ plugin: 'p1', slug: 'a1-p1' }, | ||
{ plugin: 'p2', slug: 'a2-p1' }, | ||
], | ||
}, | ||
{ slug: 'c2', refs: [{ plugin: 'p2', slug: 'a1-p2' }] }, | ||
] as CategoryConfig[]; | ||
const originalPlugins = [{ slug: 'p1' }, { slug: 'p2' }] as PluginConfig[]; | ||
const { categories, plugins } = skipPluginsMiddleware({ | ||
skipPlugins: ['wrong-slug'], | ||
plugins: originalPlugins, | ||
categories: originalCategories, | ||
}); | ||
expect(categories).toBe(originalCategories); | ||
expect(plugins).toBe(originalPlugins); | ||
}); | ||
|
||
it('should filter categories for slug "p1"', () => { | ||
const { categories } = skipPluginsMiddleware({ | ||
skipPlugins: ['p1'], | ||
plugins: [{ slug: 'p1' }, { slug: 'p2' }] as PluginConfig[], | ||
categories: [ | ||
{ | ||
slug: 'c1', | ||
refs: [ | ||
{ plugin: 'p1', slug: 'a1-p1' }, | ||
{ plugin: 'p2', slug: 'a2-p1' }, | ||
], | ||
}, | ||
{ slug: 'c2', refs: [{ plugin: 'p2', slug: 'a1-p2' }] }, | ||
] as CategoryConfig[], | ||
}); | ||
expect(categories).toStrictEqual([ | ||
expect.objectContaining({ | ||
slug: 'c1', | ||
refs: [{ plugin: 'p2', slug: 'a2-p1' }], | ||
}), | ||
expect.objectContaining({ | ||
slug: 'c2', | ||
refs: [{ plugin: 'p2', slug: 'a1-p2' }], | ||
}), | ||
]); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { GlobalOptions } from '@code-pushup/core'; | ||
import { CoreConfig } from '@code-pushup/models'; | ||
|
||
export type SkipPluginsCliOptions = { | ||
skipPlugins?: string[]; | ||
}; | ||
export type SkipPluginsOptions = Partial<GlobalOptions> & | ||
Pick<CoreConfig, 'categories' | 'plugins'> & | ||
SkipPluginsCliOptions; |
18 changes: 18 additions & 0 deletions
18
packages/cli/src/lib/implementation/skip-plugins.options.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Options } from 'yargs'; | ||
import { coerceArray } from './global.utils'; | ||
|
||
export const skipPluginsOption: Options = { | ||
describe: 'List of plugins to skip. If not set all plugins are run.', | ||
type: 'array', | ||
default: [], | ||
coerce: coerceArray, | ||
}; | ||
|
||
export function yargsSkipPluginsOptionsDefinition(): Record< | ||
'skipPlugins', | ||
Options | ||
> { | ||
return { | ||
skipPlugins: skipPluginsOption, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import chalk from 'chalk'; | ||
import type { CategoryConfig, PluginConfig } from '@code-pushup/models'; | ||
import { filterItemRefsBy, ui } from '@code-pushup/utils'; | ||
|
||
export function validateSkipPluginsOption( | ||
{ | ||
plugins, | ||
categories, | ||
}: { | ||
plugins: PluginConfig[]; | ||
categories: CategoryConfig[]; | ||
}, | ||
{ | ||
skipPlugins = [], | ||
verbose = false, | ||
}: { skipPlugins?: string[]; verbose?: boolean } = {}, | ||
): void { | ||
const skipPluginsSet = new Set(skipPlugins); | ||
const missingPlugins = skipPlugins.filter( | ||
plugin => !plugins.some(({ slug }) => slug === plugin), | ||
); | ||
|
||
if (missingPlugins.length > 0 && verbose) { | ||
ui().logger.info( | ||
`${chalk.yellow( | ||
'⚠', | ||
)} The --skipPlugin argument references plugins with "${missingPlugins.join( | ||
'", "', | ||
)}" slugs, but no such plugins are present in the configuration. Expected one of the following plugin slugs: "${plugins | ||
.map(({ slug }) => slug) | ||
.join('", "')}".`, | ||
); | ||
} | ||
|
||
if (categories.length > 0) { | ||
const removedCategorieSlugs = filterItemRefsBy(categories, ({ plugin }) => | ||
skipPluginsSet.has(plugin), | ||
).map(({ slug }) => slug); | ||
ui().logger.info( | ||
`The --skipPlugin argument removed categories with "${removedCategorieSlugs.join( | ||
'", "', | ||
)}" slugs. | ||
`, | ||
); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
packages/cli/src/lib/implementation/skip-plugins.utils.unit.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { describe, expect } from 'vitest'; | ||
import { CategoryConfig, PluginConfig } from '@code-pushup/models'; | ||
import { getLogMessages } from '@code-pushup/test-utils'; | ||
import { ui } from '@code-pushup/utils'; | ||
import { validateSkipPluginsOption } from './skip-plugins.utils'; | ||
|
||
describe('validateSkipPluginsOption', () => { | ||
it('should warn if skipPlugins option contains non-existing plugin', () => { | ||
validateSkipPluginsOption( | ||
{ | ||
plugins: [ | ||
{ slug: 'plugin1', audits: [{ slug: 'a1' }] }, | ||
] as PluginConfig[], | ||
categories: [], | ||
}, | ||
{ | ||
skipPlugins: ['plugin1', 'plugin3', 'plugin4'], | ||
verbose: true, | ||
}, | ||
); | ||
const logs = getLogMessages(ui().logger); | ||
expect(logs[0]).toContain( | ||
'The --skipPlugin argument references plugins with "plugin3", "plugin4" slugs', | ||
); | ||
}); | ||
|
||
it('should not log if skipPlugins option contains only existing plugins', () => { | ||
validateSkipPluginsOption( | ||
{ | ||
plugins: [ | ||
{ slug: 'plugin1', audits: [{ slug: 'a1-p1' }] }, | ||
{ slug: 'plugin2', audits: [{ slug: 'a1-p2' }] }, | ||
] as PluginConfig[], | ||
categories: [], | ||
}, | ||
{ | ||
skipPlugins: ['plugin1'], | ||
verbose: true, | ||
}, | ||
); | ||
expect(getLogMessages(ui().logger)).toHaveLength(0); | ||
}); | ||
|
||
it('should print ignored category and its first violating plugin', () => { | ||
validateSkipPluginsOption( | ||
{ | ||
plugins: [ | ||
{ slug: 'plugin1', audits: [{ slug: 'a1-p1' }] }, | ||
{ slug: 'plugin2', audits: [{ slug: 'a1-p2' }] }, | ||
] as PluginConfig[], | ||
categories: [ | ||
{ slug: 'c1', refs: [{ plugin: 'plugin2' }] } as CategoryConfig, | ||
{ slug: 'c2', refs: [{ plugin: 'plugin1' }] } as CategoryConfig, | ||
{ slug: 'c3', refs: [{ plugin: 'plugin2' }] } as CategoryConfig, | ||
], | ||
}, | ||
{ | ||
skipPlugins: ['plugin2'], | ||
verbose: true, | ||
}, | ||
); | ||
console.log(getLogMessages(ui().logger)); | ||
expect(getLogMessages(ui().logger)).toHaveLength(1); | ||
expect(getLogMessages(ui().logger)[0]).toContain( | ||
'The --skipPlugin argument removed categories with "c1", "c3" slugs', | ||
); | ||
}); | ||
}); |