From 840f448545d20b49a21db63b0df4264fe489e33c Mon Sep 17 00:00:00 2001 From: Craigory Coppola Date: Tue, 9 Jul 2024 10:04:38 -0400 Subject: [PATCH] feat(core): pattern matching for target defaults --- .../utils/project-configuration-utils.spec.ts | 18 ++++++++++++++++++ .../utils/project-configuration-utils.ts | 11 ++++++++++- packages/nx/src/tasks-runner/utils.ts | 8 +++----- .../nx/src/utils/find-matching-projects.ts | 10 +++------- packages/nx/src/utils/globs.ts | 11 +++++++++++ 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts b/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts index c24db50ef41893..a34af30cdee473 100644 --- a/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts +++ b/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts @@ -32,6 +32,16 @@ describe('project-configuration-utils', () => { key: 'default-value-for-targetname', }, }, + 'e2e-ci--*': { + options: { + key: 'default-value-for-e2e-ci', + }, + }, + 'e2e-ci--file-*': { + options: { + key: 'default-value-for-e2e-ci-file', + }, + }, }; it('should prefer executor key', () => { @@ -61,6 +71,14 @@ describe('project-configuration-utils', () => { ).toBeNull(); }); + it('should return first matching target', () => { + expect( + // This matches both 'e2e-ci--*' and 'e2e-ci--file-*', we expect the first match to be returned. + readTargetDefaultsForTarget('e2e-ci--file-foo', targetDefaults, null) + .options['key'] + ).toEqual('default-value-for-e2e-ci'); + }); + it('should not merge top level properties for incompatible targets', () => { expect( mergeTargetConfigurations( diff --git a/packages/nx/src/project-graph/utils/project-configuration-utils.ts b/packages/nx/src/project-graph/utils/project-configuration-utils.ts index e1a38c2c12eaf7..8870a42e8826a0 100644 --- a/packages/nx/src/project-graph/utils/project-configuration-utils.ts +++ b/packages/nx/src/project-graph/utils/project-configuration-utils.ts @@ -29,6 +29,7 @@ import { AggregateCreateNodesError, } from '../error-types'; import { CreateNodesResult } from '../plugins'; +import { isGlobPattern } from '../../utils/globs'; export type SourceInformation = [file: string | null, plugin: string]; export type ConfigurationSourceMaps = Record< @@ -1036,10 +1037,18 @@ export function readTargetDefaultsForTarget( // If not, use build if it is present. const key = [executor, targetName].find((x) => targetDefaults?.[x]); return key ? targetDefaults?.[key] : null; - } else { + } else if (targetDefaults?.[targetName]) { // If the executor is not defined, the only key we have is the target name. return targetDefaults?.[targetName]; } + + for (const key in targetDefaults ?? {}) { + if (isGlobPattern(key) && minimatch(targetName, key)) { + return targetDefaults[key]; + } + } + + return {}; } function createRootMap(projectRootMap: Record) { diff --git a/packages/nx/src/tasks-runner/utils.ts b/packages/nx/src/tasks-runner/utils.ts index 2d7534cdc11917..517737d26a5751 100644 --- a/packages/nx/src/tasks-runner/utils.ts +++ b/packages/nx/src/tasks-runner/utils.ts @@ -15,11 +15,9 @@ import { splitByColons } from '../utils/split-target'; import { getExecutorInformation } from '../command-line/run/executor-utils'; import { CustomHasher, ExecutorConfig } from '../config/misc-interfaces'; import { readProjectsConfigurationFromProjectGraph } from '../project-graph/project-graph'; -import { - GLOB_CHARACTERS, - findMatchingProjects, -} from '../utils/find-matching-projects'; +import { findMatchingProjects } from '../utils/find-matching-projects'; import { minimatch } from 'minimatch'; +import { isGlobPattern } from '../utils/globs'; export type NormalizedTargetDependencyConfig = TargetDependencyConfig & { projects: string[]; @@ -122,7 +120,7 @@ export function expandWildcardTargetConfiguration( dependencyConfig: NormalizedTargetDependencyConfig, allTargetNames: string[] ): NormalizedTargetDependencyConfig[] { - if (!GLOB_CHARACTERS.some((char) => dependencyConfig.target.includes(char))) { + if (!isGlobPattern(dependencyConfig.target)) { return [dependencyConfig]; } let cache = patternResultCache.get(allTargetNames); diff --git a/packages/nx/src/utils/find-matching-projects.ts b/packages/nx/src/utils/find-matching-projects.ts index de76ec1e39294f..b78e7197a8abc0 100644 --- a/packages/nx/src/utils/find-matching-projects.ts +++ b/packages/nx/src/utils/find-matching-projects.ts @@ -1,5 +1,6 @@ import { minimatch } from 'minimatch'; import type { ProjectGraphProjectNode } from '../config/project-graph'; +import { isGlobPattern } from './globs'; const validPatternTypes = [ 'name', // Pattern is based on the project's name @@ -18,11 +19,6 @@ interface ProjectPattern { value: string; } -/** - * The presence of these characters in a string indicates that it might be a glob pattern. - */ -export const GLOB_CHARACTERS = ['*', '|', '{', '}', '(', ')']; - /** * Find matching project names given a list of potential project names or globs. * @@ -169,7 +165,7 @@ function addMatchingProjectsByName( return; } - if (!GLOB_CHARACTERS.some((c) => pattern.value.includes(c))) { + if (!isGlobPattern(pattern.value)) { return; } @@ -204,7 +200,7 @@ function addMatchingProjectsByTag( continue; } - if (!GLOB_CHARACTERS.some((c) => pattern.value.includes(c))) { + if (!isGlobPattern(pattern.value)) { continue; } diff --git a/packages/nx/src/utils/globs.ts b/packages/nx/src/utils/globs.ts index 969f6a8a69c1d0..335f92f2bed34d 100644 --- a/packages/nx/src/utils/globs.ts +++ b/packages/nx/src/utils/globs.ts @@ -2,3 +2,14 @@ export function combineGlobPatterns(...patterns: (string | string[])[]) { const p = patterns.flat(); return p.length > 1 ? '{' + p.join(',') + '}' : p.length === 1 ? p[0] : ''; } + +export const GLOB_CHARACTERS = new Set(['*', '|', '{', '}', '(', ')', '[']); + +export function isGlobPattern(pattern: string) { + for (const c of pattern) { + if (GLOB_CHARACTERS.has(c)) { + return true; + } + } + return false; +}