From adbc64914511334bc6c0db352d38932cdff260cc Mon Sep 17 00:00:00 2001 From: Florian Guitton Date: Sun, 1 May 2022 13:48:55 +0100 Subject: [PATCH] feat(core): add support for tags selection in affected and run-many commands --- docs/generated/cli/affected-apps.md | 6 ++++ docs/generated/cli/affected-graph.md | 6 ++++ docs/generated/cli/affected-libs.md | 6 ++++ docs/generated/cli/affected.md | 6 ++++ docs/generated/cli/format-check.md | 6 ++++ docs/generated/cli/format-write.md | 6 ++++ docs/generated/cli/print-affected.md | 6 ++++ docs/generated/cli/run-many.md | 6 ++++ packages/nx/src/command-line/affected.ts | 38 +++++++++++++++++++- packages/nx/src/command-line/nx-commands.ts | 30 +++++++++++----- packages/nx/src/command-line/run-many.ts | 14 +++++--- packages/nx/src/utils/command-line-utils.ts | 18 ++++++---- packages/nx/src/utils/project-graph-utils.ts | 8 +++++ 13 files changed, 136 insertions(+), 20 deletions(-) diff --git a/docs/generated/cli/affected-apps.md b/docs/generated/cli/affected-apps.md index 74f2f90dfa5784..1859861fdfd3e3 100644 --- a/docs/generated/cli/affected-apps.md +++ b/docs/generated/cli/affected-apps.md @@ -109,6 +109,12 @@ Default: false Rerun the tasks even when the results are available in the cache +### tags + +Type: string + +Tags to run (comma delimited) + ### uncommitted Type: boolean diff --git a/docs/generated/cli/affected-graph.md b/docs/generated/cli/affected-graph.md index 9db3ed6a475c49..5ad4c7da113823 100644 --- a/docs/generated/cli/affected-graph.md +++ b/docs/generated/cli/affected-graph.md @@ -161,6 +161,12 @@ Default: false Rerun the tasks even when the results are available in the cache +### tags + +Type: string + +Tags to run (comma delimited) + ### uncommitted Type: boolean diff --git a/docs/generated/cli/affected-libs.md b/docs/generated/cli/affected-libs.md index ccf029174bb88b..ee4d4b6b05ba09 100644 --- a/docs/generated/cli/affected-libs.md +++ b/docs/generated/cli/affected-libs.md @@ -109,6 +109,12 @@ Default: false Rerun the tasks even when the results are available in the cache +### tags + +Type: string + +Tags to run (comma delimited) + ### uncommitted Type: boolean diff --git a/docs/generated/cli/affected.md b/docs/generated/cli/affected.md index 9aa0acdd9e09cd..7087abd2143ab7 100644 --- a/docs/generated/cli/affected.md +++ b/docs/generated/cli/affected.md @@ -129,6 +129,12 @@ Default: false Rerun the tasks even when the results are available in the cache +### tags + +Type: string + +Tags to run (comma delimited) + ### target Type: string diff --git a/docs/generated/cli/format-check.md b/docs/generated/cli/format-check.md index ffff3813379349..f0a41d126cce4b 100644 --- a/docs/generated/cli/format-check.md +++ b/docs/generated/cli/format-check.md @@ -97,6 +97,12 @@ Default: false Rerun the tasks even when the results are available in the cache +### tags + +Type: string + +Tags to run (comma delimited) + ### uncommitted Type: boolean diff --git a/docs/generated/cli/format-write.md b/docs/generated/cli/format-write.md index a9e280aa32f3e4..8a5cb9e1d879a4 100644 --- a/docs/generated/cli/format-write.md +++ b/docs/generated/cli/format-write.md @@ -97,6 +97,12 @@ Default: false Rerun the tasks even when the results are available in the cache +### tags + +Type: string + +Tags to run (comma delimited) + ### uncommitted Type: boolean diff --git a/docs/generated/cli/print-affected.md b/docs/generated/cli/print-affected.md index bc176dec03bdd3..88e87631cefc15 100644 --- a/docs/generated/cli/print-affected.md +++ b/docs/generated/cli/print-affected.md @@ -123,6 +123,12 @@ Default: false Rerun the tasks even when the results are available in the cache +### tags + +Type: string + +Tags to run (comma delimited) + ### uncommitted Type: boolean diff --git a/docs/generated/cli/run-many.md b/docs/generated/cli/run-many.md index b3264ae2623ecf..6c025f38afd59b 100644 --- a/docs/generated/cli/run-many.md +++ b/docs/generated/cli/run-many.md @@ -99,6 +99,12 @@ Default: false Rerun the tasks even when the results are available in the cache +### tags + +Type: string + +Tags to run (comma delimited) + ### target Type: string diff --git a/packages/nx/src/command-line/affected.ts b/packages/nx/src/command-line/affected.ts index 2c03482a2584fd..3b110f37747035 100644 --- a/packages/nx/src/command-line/affected.ts +++ b/packages/nx/src/command-line/affected.ts @@ -14,7 +14,7 @@ import { performance } from 'perf_hooks'; import { createProjectGraphAsync } from '../project-graph/project-graph'; import { withDeps } from '../project-graph/operators'; import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph'; -import { projectHasTarget } from '../utils/project-graph-utils'; +import { projectHasTarget, projectHasTag } from '../utils/project-graph-utils'; import { filterAffected } from '../project-graph/affected/affected-project-graph'; import { readEnvironment } from './read-environment'; @@ -133,6 +133,9 @@ function projectsToRun( nxArgs ) ); + if (!nxArgs.all && nxArgs.tags) { + affectedGraph = filterByTag(affectedGraph, nxArgs); + } if (!nxArgs.all && nxArgs.withDeps) { affectedGraph = withDeps( projectGraph, @@ -150,6 +153,39 @@ function projectsToRun( return Object.values(affectedGraph.nodes) as ProjectGraphProjectNode[]; } +function filterByTag( + affectedGraph: ProjectGraph, + nxArgs: NxArgs +): ProjectGraph { + const filteredProjects = allProjectsWithTag( + Object.values(affectedGraph.nodes), + nxArgs + ); + const res = { + nodes: filteredProjects.reduce( + (nodes, project) => ({ + ...nodes, + [project.name]: project, + }), + {} + ), + dependencies: affectedGraph.dependencies, + } as ProjectGraph; + return res; +} + +function allProjectsWithTag( + projects: ProjectGraphProjectNode[], + nxArgs: NxArgs +) { + return projects.filter((p) => + nxArgs.tags.reduce( + (matched, tag) => matched || projectHasTag(p, tag), + false + ) + ); +} + function allProjectsWithTarget( projects: ProjectGraphProjectNode[], nxArgs: NxArgs diff --git a/packages/nx/src/command-line/nx-commands.ts b/packages/nx/src/command-line/nx-commands.ts index 65c2495b1084fb..1ef440742dcc8a 100644 --- a/packages/nx/src/command-line/nx-commands.ts +++ b/packages/nx/src/command-line/nx-commands.ts @@ -359,6 +359,11 @@ function withAffectedOptions(yargs: yargs.Argv): yargs.Argv { type: 'boolean', default: undefined, }) + .option('tags', { + describe: 'Tags to run (comma delimited)', + type: 'string', + default: undefined, + }) .option('all', { describe: 'All projects', type: 'boolean', @@ -416,10 +421,11 @@ function withAffectedOptions(yargs: yargs.Argv): yargs.Argv { describe: 'Print additional error stack trace on failure', }) .conflicts({ - files: ['uncommitted', 'untracked', 'base', 'head', 'all'], - untracked: ['uncommitted', 'files', 'base', 'head', 'all'], - uncommitted: ['files', 'untracked', 'base', 'head', 'all'], - all: ['files', 'untracked', 'uncommitted', 'base', 'head'], + files: ['uncommitted', 'untracked', 'base', 'head', 'all', 'tags'], + untracked: ['uncommitted', 'files', 'base', 'head', 'all', 'tags'], + uncommitted: ['files', 'untracked', 'base', 'head', 'all', 'tags'], + all: ['files', 'untracked', 'uncommitted', 'base', 'head', 'tags'], + tags: ['files', 'untracked', 'uncommitted', 'base', 'head', 'all'], }); } @@ -428,15 +434,21 @@ function withRunManyOptions(yargs: yargs.Argv): yargs.Argv { .option('projects', { describe: 'Projects to run (comma delimited)', type: 'string', + default: undefined, + }) + .option('tags', { + describe: 'Tags to run (comma delimited)', + type: 'string', + default: undefined, }) .option('all', { describe: 'Run the target on all projects in the workspace', type: 'boolean', default: undefined, }) - .check(({ all, projects }) => { - if ((all && projects) || (!all && !projects)) - throw new Error('You must provide either --all or --projects'); + .check(({ all, projects, tags }) => { + if (!all && !projects && !tags) + throw new Error('You must provide either --all, --projects or --tags'); return true; }) .options('runner', { @@ -471,7 +483,9 @@ function withRunManyOptions(yargs: yargs.Argv): yargs.Argv { describe: 'Print additional error stack trace on failure', }) .conflicts({ - all: 'projects', + all: ['projects', 'tags'], + projects: ['all', 'tags'], + tags: ['all', 'projects'], }); } diff --git a/packages/nx/src/command-line/run-many.ts b/packages/nx/src/command-line/run-many.ts index 1d3b39528026f4..5c902adc6ea195 100644 --- a/packages/nx/src/command-line/run-many.ts +++ b/packages/nx/src/command-line/run-many.ts @@ -2,7 +2,7 @@ import * as yargs from 'yargs'; import { runCommand } from '../tasks-runner/run-command'; import type { NxArgs, RawNxArgs } from '../utils/command-line-utils'; import { splitArgsIntoNxArgsAndOverrides } from '../utils/command-line-utils'; -import { projectHasTarget } from '../utils/project-graph-utils'; +import { projectHasTarget, projectHasTag } from '../utils/project-graph-utils'; import { output } from '../utils/output'; import { connectToNxCloudUsingScan } from './connect-to-nx-cloud'; import { performance } from 'perf_hooks'; @@ -46,9 +46,13 @@ function projectsToRun( ); } checkForInvalidProjects(nxArgs, allProjects); - let selectedProjects = nxArgs.projects.map((name) => - allProjects.find((project) => project.name === name) - ); + let selectedProjects = nxArgs.tags + ? nxArgs.tags.map((tag) => + allProjects.find((project) => project.data.tags.includes(tag)) + ) + : (nxArgs.projects ?? []).map((name) => + allProjects.find((project) => project.name === name) + ); return runnableForTarget(selectedProjects, nxArgs.target, true).filter( (proj) => !excludedProjects.has(proj.name) ); @@ -58,7 +62,7 @@ function checkForInvalidProjects( nxArgs: NxArgs, allProjects: ProjectGraphProjectNode[] ) { - const invalid = nxArgs.projects.filter( + const invalid = (nxArgs.projects ?? []).filter( (name) => !allProjects.find((p) => p.name === name) ); if (invalid.length !== 0) { diff --git a/packages/nx/src/utils/command-line-utils.ts b/packages/nx/src/utils/command-line-utils.ts index 8a46cf32061b29..9dfb76e8d10ba4 100644 --- a/packages/nx/src/utils/command-line-utils.ts +++ b/packages/nx/src/utils/command-line-utils.ts @@ -84,7 +84,7 @@ const runOne: string[] = [ 'hide-cached-output', ]; -const runMany: string[] = [...runOne, 'projects', 'all']; +const runMany: string[] = [...runOne, 'projects', 'tags', 'all']; const runAffected: string[] = [ ...runOne, @@ -96,6 +96,7 @@ const runAffected: string[] = [ 'files', 'plain', 'select', + 'tags', ]; export interface RawNxArgs extends NxArgs { @@ -129,6 +130,7 @@ export interface NxArgs { 'hide-cached-output'?: boolean; hideCachedOutput?: boolean; scan?: boolean; + tags?: string[]; } const ignoreArgs = ['$0', '_']; @@ -163,9 +165,7 @@ export function splitArgsIntoNxArgsAndOverrides( }); if (mode === 'run-many') { - if (!nxArgs.projects) { - nxArgs.projects = []; - } else { + if (nxArgs.projects) { nxArgs.projects = (args.projects as string) .split(',') .map((p: string) => p.trim()); @@ -206,7 +206,7 @@ export function splitArgsIntoNxArgsAndOverrides( !nxArgs.untracked && !nxArgs.base && !nxArgs.head && - !nxArgs.all && + (!nxArgs.all || !nxArgs.tags) && args._.length >= 3 ) { nxArgs.base = args._[1] as string; @@ -246,7 +246,7 @@ export function splitArgsIntoNxArgsAndOverrides( !nxArgs.files && !nxArgs.uncommitted && !nxArgs.untracked && - !nxArgs.all + (!nxArgs.all || !nxArgs.tags) ) { output.note({ title: `Affected criteria defaulted to --base=${output.bold( @@ -255,6 +255,12 @@ export function splitArgsIntoNxArgsAndOverrides( }); } } + + if (nxArgs.tags) { + nxArgs.tags = (args.tags as string) + .split(',') + .map((p: string) => p.trim()); + } } if (!nxArgs.skipNxCache) { diff --git a/packages/nx/src/utils/project-graph-utils.ts b/packages/nx/src/utils/project-graph-utils.ts index ab83ec404ef38c..2b1aa3f87c8725 100644 --- a/packages/nx/src/utils/project-graph-utils.ts +++ b/packages/nx/src/utils/project-graph-utils.ts @@ -29,6 +29,14 @@ export function projectHasTargetAndConfiguration( ); } +export function projectHasTag(project: ProjectGraphProjectNode, tag: string) { + return !!( + project.data && + project.data.tags && + project.data.tags.includes(tag) + ); +} + export function mergeNpmScriptsWithTargets( projectRoot: string, targets