From ebfe942caa6608b28e4c9cb175f0a3dd197aeb38 Mon Sep 17 00:00:00 2001 From: Andrew Haines Date: Tue, 19 Nov 2024 09:51:12 +0000 Subject: [PATCH] feat(cli): support excluding projects with `--project=!pattern` (#6924) --- docs/guide/cli-generated.md | 2 +- packages/vitest/src/node/cli/cli-config.ts | 2 +- packages/vitest/src/utils/base.ts | 17 +++++++++++++---- test/config/test/project.test.ts | 20 +++++++++++++++++--- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/docs/guide/cli-generated.md b/docs/guide/cli-generated.md index 80e1343818e3..27d7d0160e3b 100644 --- a/docs/guide/cli-generated.md +++ b/docs/guide/cli-generated.md @@ -752,7 +752,7 @@ Path to a custom tsconfig file - **CLI:** `--project ` - **Config:** [project](/config/#project) -The name of the project to run if you are using Vitest workspace feature. This can be repeated for multiple projects: `--project=1 --project=2`. You can also filter projects using wildcards like `--project=packages*` +The name of the project to run if you are using Vitest workspace feature. This can be repeated for multiple projects: `--project=1 --project=2`. You can also filter projects using wildcards like `--project=packages*`, and exclude projects with `--project=!pattern`. ### slowTestThreshold diff --git a/packages/vitest/src/node/cli/cli-config.ts b/packages/vitest/src/node/cli/cli-config.ts index 3d4f9e31961f..ac67b8ba7bf4 100644 --- a/packages/vitest/src/node/cli/cli-config.ts +++ b/packages/vitest/src/node/cli/cli-config.ts @@ -700,7 +700,7 @@ export const cliOptionsConfig: VitestCLIOptions = { }, project: { description: - 'The name of the project to run if you are using Vitest workspace feature. This can be repeated for multiple projects: `--project=1 --project=2`. You can also filter projects using wildcards like `--project=packages*`', + 'The name of the project to run if you are using Vitest workspace feature. This can be repeated for multiple projects: `--project=1 --project=2`. You can also filter projects using wildcards like `--project=packages*`, and exclude projects with `--project=!pattern`.', argument: '', array: true, }, diff --git a/packages/vitest/src/utils/base.ts b/packages/vitest/src/utils/base.ts index 25a9fa7a445d..7e02e0a20597 100644 --- a/packages/vitest/src/utils/base.ts +++ b/packages/vitest/src/utils/base.ts @@ -24,8 +24,17 @@ export function escapeRegExp(s: string) { } export function wildcardPatternToRegExp(pattern: string): RegExp { - return new RegExp( - `^${pattern.split('*').map(escapeRegExp).join('.*')}$`, - 'i', - ) + const negated = pattern.startsWith('!') + + if (negated) { + pattern = pattern.slice(1) + } + + let regexp = `${pattern.split('*').map(escapeRegExp).join('.*')}$` + + if (negated) { + regexp = `(?!${regexp})` + } + + return new RegExp(`^${regexp}`, 'i') } diff --git a/test/config/test/project.test.ts b/test/config/test/project.test.ts index 9506ec7c2ce1..fd66166016d3 100644 --- a/test/config/test/project.test.ts +++ b/test/config/test/project.test.ts @@ -1,14 +1,19 @@ import { expect, test } from 'vitest' import { runVitest } from '../../test-utils' +const allProjects = ['project_1', 'project_2', 'space_1'] + test.each([ { pattern: 'project_1', expected: ['project_1'] }, - { pattern: '*', expected: ['project_1', 'project_2', 'space_1'] }, + { pattern: '*', expected: allProjects }, { pattern: '*j*', expected: ['project_1', 'project_2'] }, { pattern: 'project*', expected: ['project_1', 'project_2'] }, { pattern: 'space*', expected: ['space_1'] }, + { pattern: '!project_1', expected: ['project_2', 'space_1'] }, + { pattern: '!project*', expected: ['space_1'] }, + { pattern: '!project', expected: allProjects }, ])('should match projects correctly: $pattern', async ({ pattern, expected }) => { - const { stdout, stderr } = await runVitest({ + const { ctx, stderr, stdout } = await runVitest({ root: 'fixtures/project', reporters: ['basic'], project: pattern, @@ -17,5 +22,14 @@ test.each([ expect(stderr).toBeFalsy() expect(stdout).toBeTruthy() - expected.forEach(name => expect(stdout).toContain(name)) + for (const project of allProjects) { + if (expected.includes(project)) { + expect(stdout).toContain(project) + } + else { + expect(stdout).not.toContain(project) + } + } + + expect(ctx?.projects.map(p => p.name).sort()).toEqual(expected) })