diff --git a/docs/generated/cli/affected.md b/docs/generated/cli/affected.md index b7896570a2..bf0bb37696 100644 --- a/docs/generated/cli/affected.md +++ b/docs/generated/cli/affected.md @@ -149,11 +149,11 @@ Default: `false` Rerun the tasks even when the results are available in the cache -### target +### targets -Type: `string` +Type: `array` -Task to run for affected projects +Tasks to run for affected projects ### uncommitted diff --git a/docs/generated/cli/exec.md b/docs/generated/cli/exec.md index fe4658f799..d73b6ef78e 100644 --- a/docs/generated/cli/exec.md +++ b/docs/generated/cli/exec.md @@ -81,11 +81,11 @@ Default: `false` Rerun the tasks even when the results are available in the cache -### target +### targets -Type: `string` +Type: `array` -Task to run for affected projects +Tasks to run for affected projects ### verbose diff --git a/docs/generated/cli/print-affected.md b/docs/generated/cli/print-affected.md index 27a0e86547..c0badf29ad 100644 --- a/docs/generated/cli/print-affected.md +++ b/docs/generated/cli/print-affected.md @@ -99,11 +99,11 @@ Type: `string` Select the subset of the returned json document (e.g., --select=projects) -### target +### targets -Type: `string` +Type: `array` -Task to run for affected projects +Tasks to run for affected projects ### type diff --git a/docs/generated/cli/run-many.md b/docs/generated/cli/run-many.md index 8db25d371f..853ec97898 100644 --- a/docs/generated/cli/run-many.md +++ b/docs/generated/cli/run-many.md @@ -121,11 +121,11 @@ Default: `false` Rerun the tasks even when the results are available in the cache -### target +### targets -Type: `string` +Type: `array` -Task to run for affected projects +Tasks to run for affected projects ### verbose diff --git a/docs/generated/packages/nx/documents/affected.md b/docs/generated/packages/nx/documents/affected.md index b7896570a2..bf0bb37696 100644 --- a/docs/generated/packages/nx/documents/affected.md +++ b/docs/generated/packages/nx/documents/affected.md @@ -149,11 +149,11 @@ Default: `false` Rerun the tasks even when the results are available in the cache -### target +### targets -Type: `string` +Type: `array` -Task to run for affected projects +Tasks to run for affected projects ### uncommitted diff --git a/docs/generated/packages/nx/documents/exec.md b/docs/generated/packages/nx/documents/exec.md index fe4658f799..d73b6ef78e 100644 --- a/docs/generated/packages/nx/documents/exec.md +++ b/docs/generated/packages/nx/documents/exec.md @@ -81,11 +81,11 @@ Default: `false` Rerun the tasks even when the results are available in the cache -### target +### targets -Type: `string` +Type: `array` -Task to run for affected projects +Tasks to run for affected projects ### verbose diff --git a/docs/generated/packages/nx/documents/print-affected.md b/docs/generated/packages/nx/documents/print-affected.md index 27a0e86547..c0badf29ad 100644 --- a/docs/generated/packages/nx/documents/print-affected.md +++ b/docs/generated/packages/nx/documents/print-affected.md @@ -99,11 +99,11 @@ Type: `string` Select the subset of the returned json document (e.g., --select=projects) -### target +### targets -Type: `string` +Type: `array` -Task to run for affected projects +Tasks to run for affected projects ### type diff --git a/docs/generated/packages/nx/documents/run-many.md b/docs/generated/packages/nx/documents/run-many.md index 8db25d371f..853ec97898 100644 --- a/docs/generated/packages/nx/documents/run-many.md +++ b/docs/generated/packages/nx/documents/run-many.md @@ -121,11 +121,11 @@ Default: `false` Rerun the tasks even when the results are available in the cache -### target +### targets -Type: `string` +Type: `array` -Task to run for affected projects +Tasks to run for affected projects ### verbose diff --git a/docs/shared/angular-standalone-tutorial/4-task-pipelines.md b/docs/shared/angular-standalone-tutorial/4-task-pipelines.md index a353636f00..ba2dca6a7d 100644 --- a/docs/shared/angular-standalone-tutorial/4-task-pipelines.md +++ b/docs/shared/angular-standalone-tutorial/4-task-pipelines.md @@ -34,7 +34,7 @@ Build at: 2022-11-30T16:44:43.171Z - Hash: 9850ece7cc7c6b7c - Time: 6527ms ————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - > NX Successfully ran target build for project store and 1 task(s) it depends on (9s) + > NX Successfully ran target build for project store and 1 task(s) they depend on (9s) ``` @@ -100,7 +100,7 @@ Build at: 2022-11-30T16:44:43.171Z - Hash: 9850ece7cc7c6b7c - Time: 6527ms ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - > NX Successfully ran target build for project store and 1 task(s) it depends on (13ms) + > NX Successfully ran target build for project store and 1 task(s) they depend on (13ms) Nx read the output from the cache instead of running the command for 2 out of 2 tasks. ``` diff --git a/docs/shared/angular-tutorial/4-workspace-optimization.md b/docs/shared/angular-tutorial/4-workspace-optimization.md index 34ce0f38b6..fce0ed9457 100644 --- a/docs/shared/angular-tutorial/4-workspace-optimization.md +++ b/docs/shared/angular-tutorial/4-workspace-optimization.md @@ -198,7 +198,7 @@ Build at: 2022-11-23T22:53:29.097Z - Hash: 3cd478c78ebeead2 - Time: 5154ms ———————————————————————————————————————————————————————————————————————————————————————————————— - > NX Successfully ran target build for project store and 1 task(s) it depends on (8s) + > NX Successfully ran target build for project store and 1 task(s) they depend on (8s) ``` Notice the line here: diff --git a/docs/shared/node-tutorial/4-workspace-optimization.md b/docs/shared/node-tutorial/4-workspace-optimization.md index 94878c7536..09672d0f10 100644 --- a/docs/shared/node-tutorial/4-workspace-optimization.md +++ b/docs/shared/node-tutorial/4-workspace-optimization.md @@ -191,7 +191,7 @@ webpack compiled successfully (bafa37be9890ecb2) ——————————————————————————————————————————————————————————————————————————————————————————————— - > NX Successfully ran target build for project products-cli and 1 task(s) it depends on (2s) + > NX Successfully ran target build for project products-cli and 1 task(s) they depend on (2s) Nx read the output from the cache instead of running the command for 1 out of 2 tasks. ``` diff --git a/docs/shared/react-standalone-tutorial/4-task-pipelines.md b/docs/shared/react-standalone-tutorial/4-task-pipelines.md index a72a13930f..b311ffb7ae 100644 --- a/docs/shared/react-standalone-tutorial/4-task-pipelines.md +++ b/docs/shared/react-standalone-tutorial/4-task-pipelines.md @@ -25,7 +25,7 @@ dist/store/assets/index.f18c2b19.js.map 565.79 KiB ———————————————————————————————————————————————————————————————————————————————————————————————————————— - > NX Successfully ran target build for project store and 2 task(s) it depends on (6s) + > NX Successfully ran target build for project store and 2 task(s) they depend on (6s) ``` @@ -86,7 +86,7 @@ dist/store/assets/index.f18c2b19.js.map 565.79 KiB ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - > NX Successfully ran target build for project store and 2 task(s) it depends on (42ms) + > NX Successfully ran target build for project store and 2 task(s) they depend on (42ms) Nx read the output from the cache instead of running the command for 3 out of 3 tasks. ``` diff --git a/docs/shared/react-tutorial/4-workspace-optimization.md b/docs/shared/react-tutorial/4-workspace-optimization.md index 80a6956568..ac37ef7e8e 100644 --- a/docs/shared/react-tutorial/4-workspace-optimization.md +++ b/docs/shared/react-tutorial/4-workspace-optimization.md @@ -181,7 +181,7 @@ webpack compiled successfully (06e95dfdacea84c7) ——————————————————————————————————————————————————————————————————————————————————————————————————— - > NX Successfully ran target build for project store and 1 task(s) it depends on (5s) + > NX Successfully ran target build for project store and 1 task(s) they depend on (5s) ``` Notice the line here: diff --git a/e2e/js/src/js.test.ts b/e2e/js/src/js.test.ts index 0964f946c3..e69a64ace2 100644 --- a/e2e/js/src/js.test.ts +++ b/e2e/js/src/js.test.ts @@ -140,7 +140,7 @@ describe('js e2e', () => { }); const output = runCLI(`build ${parentLib}`); - expect(output).toContain('1 task(s) it depends on'); + expect(output).toContain('1 task it depends on'); expect(output).toContain('Done compiling TypeScript files'); updateJson(`libs/${lib}/tsconfig.json`, (json) => { @@ -226,7 +226,7 @@ describe('js e2e', () => { }); const output = runCLI(`build ${parentLib}`); - expect(output).toContain('1 task(s) it depends on'); + expect(output).toContain('1 task it depends on'); expect(output).toContain('Successfully compiled: 2 files with swc'); updateJson(`libs/${lib}/.lib.swcrc`, (json) => { diff --git a/e2e/linter/src/linter.test.ts b/e2e/linter/src/linter.test.ts index 441d702c14..ae1559b767 100644 --- a/e2e/linter/src/linter.test.ts +++ b/e2e/linter/src/linter.test.ts @@ -398,7 +398,9 @@ export function tslibC(): string { const fixedStout = runCLI(`lint ${libC} --fix`, { silenceError: true, }); - expect(fixedStout).toContain('Successfully ran target lint for project'); + expect(fixedStout).toContain( + `Successfully ran target lint for project ${libC}` + ); const fileContent = readFile(`libs/${libC}/src/lib/tslib-c-another.ts`); expect(fileContent).toContain(`import { tslibC } from './tslib-c';`); @@ -424,7 +426,9 @@ export function tslibC(): string { const fixedStout = runCLI(`lint ${libB} --fix`, { silenceError: true, }); - expect(fixedStout).toContain('Successfully ran target lint for project'); + expect(fixedStout).toContain( + `Successfully ran target lint for project ${libB}` + ); const fileContent = readFile(`libs/${libB}/src/lib/tslib-b.ts`); expect(fileContent).toContain( diff --git a/e2e/nx-run/src/affected-graph.test.ts b/e2e/nx-run/src/affected-graph.test.ts index 12d850f331..a75c5dea5d 100644 --- a/e2e/nx-run/src/affected-graph.test.ts +++ b/e2e/nx-run/src/affected-graph.test.ts @@ -129,7 +129,7 @@ describe('Nx Affected and Graph Tests', () => { const build = runCLI( `affected:build --files="libs/${mylib}/src/index.ts" --parallel` ); - expect(build).toContain(`Running target build for 3 project(s):`); + expect(build).toContain(`Running target build for 3 projects:`); expect(build).toContain(`- ${myapp}`); expect(build).toContain(`- ${mypublishablelib}`); expect(build).not.toContain('is not registered with the build command'); @@ -138,7 +138,7 @@ describe('Nx Affected and Graph Tests', () => { const buildExcluded = runCLI( `affected:build --files="libs/${mylib}/src/index.ts" --exclude ${myapp}` ); - expect(buildExcluded).toContain(`Running target build for 2 project(s):`); + expect(buildExcluded).toContain(`Running target build for 2 projects:`); expect(buildExcluded).toContain(`- ${mypublishablelib}`); // test diff --git a/e2e/nx-run/src/run.test.ts b/e2e/nx-run/src/run.test.ts index 986b948f11..f8410d7db4 100644 --- a/e2e/nx-run/src/run.test.ts +++ b/e2e/nx-run/src/run.test.ts @@ -290,7 +290,7 @@ describe('Nx Running Tests', () => { const output = runCLI(`build ${myapp}`); expect(output).toContain( - `NX Running target build for project ${myapp} and 3 task(s) it depends on` + `NX Running target build for project ${myapp} and 3 tasks it depends on` ); expect(output).toContain(myapp); expect(output).toContain(mylib1); @@ -310,7 +310,7 @@ describe('Nx Running Tests', () => { const output = runCLI(`build ${myapp}`); expect(output).toContain( - `NX Running target build for project ${myapp} and 2 task(s) it depends on` + `NX Running target build for project ${myapp} and 2 tasks it depends on` ); expect(output).toContain(myapp); expect(output).toContain(mylib1); @@ -347,7 +347,7 @@ describe('Nx Running Tests', () => { const output = runCLI(`outside ${myapp}`); expect(output).toContain( - `NX Running target outside for project ${myapp} and 1 task(s) it depends on` + `NX Running target outside for project ${myapp} and 1 task it depends on` ); removeFile(`one.txt`); @@ -391,7 +391,7 @@ describe('Nx Running Tests', () => { const buildParallel = runCLI( `run-many --target=build --projects="${libC},${libB}"` ); - expect(buildParallel).toContain(`Running target build for 2 project(s):`); + expect(buildParallel).toContain(`Running target build for 2 projects:`); expect(buildParallel).not.toContain(`- ${libA}`); expect(buildParallel).toContain(`- ${libB}`); expect(buildParallel).toContain(`- ${libC}`); @@ -401,7 +401,7 @@ describe('Nx Running Tests', () => { // testing run many --all starting const buildAllParallel = runCLI(`run-many --target=build`); expect(buildAllParallel).toContain( - `Running target build for 4 project(s):` + `Running target build for 4 projects:` ); expect(buildAllParallel).toContain(`- ${appA}`); expect(buildAllParallel).toContain(`- ${libA}`); @@ -415,7 +415,7 @@ describe('Nx Running Tests', () => { `run-many --target=build --projects="${libA}"` ); expect(buildWithDeps).toContain( - `Running target build for 1 project(s) and 1 task(s) they depend on:` + `Running target build for project ${libA} and 1 task it depends on:` ); expect(buildWithDeps).toContain(`- ${libA}`); expect(buildWithDeps).toContain(`${libC}`); // build should include libC as dependency @@ -428,7 +428,7 @@ describe('Nx Running Tests', () => { `run-many --target=build --projects="${appA},${libA}" --prod` ); expect(buildConfig).toContain( - `Running target build for 2 project(s) and 1 task(s) they depend on:` + `Running target build for 2 projects and 1 task they depend on:` ); expect(buildConfig).toContain(`run ${appA}:build:production`); expect(buildConfig).toContain(`run ${libA}:build`); @@ -441,6 +441,19 @@ describe('Nx Running Tests', () => { }); expect(buildWithDaemon).toContain(`Successfully ran target build`); }, 1000000); + + it('should run multiple targets', () => { + const myapp1 = uniq('myapp'); + const myapp2 = uniq('myapp'); + runCLI(`generate @nrwl/web:app ${myapp1}`); + runCLI(`generate @nrwl/web:app ${myapp2}`); + + let outputs = runCLI(`run-many -t build test -p ${myapp1} ${myapp2}`); + expect(outputs).toContain('Running targets build, test for 2 projects:'); + + outputs = runCLI(`run-many -t build test -p=${myapp1},${myapp2}`); + expect(outputs).toContain('Running targets build, test for 2 projects:'); + }); }); describe('exec', () => { diff --git a/packages/nx/src/command-line/affected.ts b/packages/nx/src/command-line/affected.ts index 632c5ae983..6f39b71745 100644 --- a/packages/nx/src/command-line/affected.ts +++ b/packages/nx/src/command-line/affected.ts @@ -93,7 +93,7 @@ export async function affected( break; case 'print-affected': - if (nxArgs.target) { + if (nxArgs.targets && nxArgs.targets.length > 0) { await printAffected( allProjectsWithTarget(projects, nxArgs), projectGraph, @@ -163,7 +163,9 @@ function allProjectsWithTarget( projects: ProjectGraphProjectNode[], nxArgs: NxArgs ) { - return projects.filter((p) => projectHasTarget(p, nxArgs.target)); + return projects.filter((p) => + nxArgs.targets.find((target) => projectHasTarget(p, target)) + ); } function printError(e: any, verbose?: boolean) { diff --git a/packages/nx/src/command-line/nx-commands.ts b/packages/nx/src/command-line/nx-commands.ts index 84d67d2591..39fd437ef6 100644 --- a/packages/nx/src/command-line/nx-commands.ts +++ b/packages/nx/src/command-line/nx-commands.ts @@ -571,9 +571,12 @@ function withRunManyOptions(yargs: yargs.Argv): yargs.Argv { 'populate--': true, }) .option('projects', { + type: 'array', + string: true, + alias: 'p', + coerce: parseCSV, describe: 'Projects to run. (comma delimited project names and/or patterns)', - type: 'string', }) .option('all', { describe: '[deprecated] Run the target on all projects in the workspace', @@ -649,10 +652,12 @@ function withTargetAndConfigurationOption( yargs: yargs.Argv, demandOption = true ): yargs.Argv { - return withConfiguration(yargs).option('target', { - describe: 'Task to run for affected projects', - type: 'string', + return withConfiguration(yargs).option('targets', { + describe: 'Tasks to run for affected projects', + type: 'array', + alias: ['target', 't'], requiresArg: true, + coerce: parseCSV, demandOption, global: false, }); @@ -946,6 +951,7 @@ function withWatchOptions(yargs: yargs.Argv) { .option('projects', { type: 'array', string: true, + alias: 'p', coerce: parseCSV, description: 'Projects to watch (comma delimited).', }) diff --git a/packages/nx/src/command-line/print-affected.ts b/packages/nx/src/command-line/print-affected.ts index 9243a08fa3..7429cdb36c 100644 --- a/packages/nx/src/command-line/print-affected.ts +++ b/packages/nx/src/command-line/print-affected.ts @@ -22,15 +22,16 @@ export async function printAffected( nxArgs.type ? p.type === nxArgs.type : true ); const projectNames = projectsForType.map((p) => p.name); - const tasksJson = nxArgs.target - ? await createTasks( - projectsForType, - projectGraph, - nxArgs, - nxJson, - overrides - ) - : []; + const tasksJson = + nxArgs.targets && nxArgs.targets.length > 0 + ? await createTasks( + projectsForType, + projectGraph, + nxArgs, + nxJson, + overrides + ) + : []; const result = { tasks: tasksJson, projects: projectNames, @@ -53,24 +54,28 @@ async function createTasks( const workspaces = new Workspaces(workspaceRoot); const hasher = new Hasher(projectGraph, nxJson, {}); const execCommand = getPackageManagerCommand().exec; - - const tasks: Task[] = affectedProjectsWithTargetAndConfig.map( - (affectedProject) => { - const p = new ProcessTasks({}, projectGraph); + const p = new ProcessTasks({}, projectGraph); + const tasks = []; + for (let target of nxArgs.targets) { + for (const affectedProject of affectedProjectsWithTargetAndConfig) { const resolvedConfiguration = p.resolveConfiguration( affectedProject, - nxArgs.target, + target, nxArgs.configuration ); - return p.createTask( - p.getId(affectedProject.name, nxArgs.target, resolvedConfiguration), - affectedProject, - nxArgs.target, - resolvedConfiguration, - overrides - ); + try { + tasks.push( + p.createTask( + p.getId(affectedProject.name, target, resolvedConfiguration), + affectedProject, + target, + resolvedConfiguration, + overrides + ) + ); + } catch (e) {} } - ); + } await Promise.all( tasks.map((t) => hashTask(workspaces, hasher, projectGraph, {} as any, t)) diff --git a/packages/nx/src/command-line/run-many.spec.ts b/packages/nx/src/command-line/run-many.spec.ts index 84ef3acaa7..9902055ac9 100644 --- a/packages/nx/src/command-line/run-many.spec.ts +++ b/packages/nx/src/command-line/run-many.spec.ts @@ -38,7 +38,7 @@ describe('run-many', () => { const projects = projectsToRun( { all: true, - target: 'test', + targets: ['test'], projects: [], }, projectGraph @@ -50,7 +50,7 @@ describe('run-many', () => { it('should select a project with a target', () => { const projects = projectsToRun( { - target: 'test', + targets: ['test'], projects: ['proj1'], }, projectGraph @@ -62,7 +62,7 @@ describe('run-many', () => { it('should filter projects with a pattern', () => { const projects = projectsToRun( { - target: 'test', + targets: ['test'], projects: ['proj*'], }, projectGraph @@ -75,7 +75,7 @@ describe('run-many', () => { expect(() => { projectsToRun( { - target: 'test', + targets: ['test'], projects: ['nomatch*'], }, projectGraph @@ -87,7 +87,7 @@ describe('run-many', () => { const projects = projectsToRun( { all: true, - target: 'test', + targets: ['test'], projects: [], exclude: ['proj1'], }, @@ -101,7 +101,7 @@ describe('run-many', () => { const projects = projectsToRun( { all: true, - target: 'test', + targets: ['test'], projects: [], exclude: ['proj*'], }, @@ -131,7 +131,7 @@ describe('run-many', () => { performance.mark('start'); projectsToRun( { - target: 'test', + targets: ['test'], projects: ['proj1*'], exclude: ['proj12*'], }, diff --git a/packages/nx/src/command-line/run-many.ts b/packages/nx/src/command-line/run-many.ts index a153ef444f..720eba3faa 100644 --- a/packages/nx/src/command-line/run-many.ts +++ b/packages/nx/src/command-line/run-many.ts @@ -56,7 +56,7 @@ export function projectsToRun( projectGraph: ProjectGraph ): ProjectGraphProjectNode[] { const selectedProjects = new Map(); - const validProjects = runnableForTarget(projectGraph.nodes, nxArgs.target); + const validProjects = runnableForTarget(projectGraph.nodes, nxArgs.targets); const validProjectNames = Array.from(validProjects.keys()); const invalidProjects: string[] = []; @@ -122,12 +122,12 @@ export function projectsToRun( function runnableForTarget( projects: Record, - target: string + targets: string[] ): Set { const runnable = new Set(); for (let projectName in projects) { const project = projects[projectName]; - if (projectHasTarget(project, target)) { + if (targets.find((target) => projectHasTarget(project, target))) { runnable.add(projectName); } } diff --git a/packages/nx/src/command-line/run-one.ts b/packages/nx/src/command-line/run-one.ts index 84413d941a..fa68042c98 100644 --- a/packages/nx/src/command-line/run-one.ts +++ b/packages/nx/src/command-line/run-one.ts @@ -44,7 +44,7 @@ export async function runOne( { ...opts.parsedArgs, configuration: opts.configuration, - target: opts.target, + targets: [opts.target], }, 'run-one', { printWarnings: true }, diff --git a/packages/nx/src/project-graph/affected/locators/workspace-projects.ts b/packages/nx/src/project-graph/affected/locators/workspace-projects.ts index 44aa9ee504..5386e058e5 100644 --- a/packages/nx/src/project-graph/affected/locators/workspace-projects.ts +++ b/packages/nx/src/project-graph/affected/locators/workspace-projects.ts @@ -31,6 +31,10 @@ export const getImplicitlyTouchedProjects: TouchedProjectLocator = ( const globalFiles = [ ...extractGlobalFilesFromInputs(nxJson, projectGraphNodes), 'nx.json', + 'package-lock.json', + 'yarn.lock', + 'pnpm-lock.yaml', + 'pnpm-lock.yml', ]; globalFiles.forEach((file) => { implicits[file] = '*' as any; diff --git a/packages/nx/src/tasks-runner/create-task-graph.spec.ts b/packages/nx/src/tasks-runner/create-task-graph.spec.ts index 3ce87a79c0..e3b9aabe31 100644 --- a/packages/nx/src/tasks-runner/create-task-graph.spec.ts +++ b/packages/nx/src/tasks-runner/create-task-graph.spec.ts @@ -412,6 +412,63 @@ describe('createTaskGraph', () => { }); }); + it('should correctly set dependencies when they are all given as inputs', () => { + const taskGraph = createTaskGraph( + projectGraph, + {}, + ['app1', 'lib1'], + ['build', 'prebuild'], + 'development', + { + __overrides_unparsed__: [], + } + ); + // prebuild should also be in here + expect(taskGraph).toEqual({ + roots: ['app1:prebuild', 'lib1:build'], + tasks: { + 'app1:build': { + id: 'app1:build', + target: { + project: 'app1', + target: 'build', + }, + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'app1-root', + }, + 'app1:prebuild': { + id: 'app1:prebuild', + target: { + project: 'app1', + target: 'prebuild', + }, + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'app1-root', + }, + 'lib1:build': { + id: 'lib1:build', + target: { + project: 'lib1', + target: 'build', + }, + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib1-root', + }, + }, + dependencies: { + 'app1:build': ['lib1:build', 'app1:prebuild'], + 'app1:prebuild': [], + 'lib1:build': [], + }, + }); + }); + it('should handle diamond shape dependencies', () => { projectGraph = { nodes: { diff --git a/packages/nx/src/tasks-runner/create-task-graph.ts b/packages/nx/src/tasks-runner/create-task-graph.ts index 8a14a6ae40..8baf21d507 100644 --- a/packages/nx/src/tasks-runner/create-task-graph.ts +++ b/packages/nx/src/tasks-runner/create-task-graph.ts @@ -26,21 +26,24 @@ export class ProcessTasks { ) { for (const projectName of projectNames) { for (const target of targets) { - const resolvedConfiguration = this.resolveConfiguration( - this.projectGraph.nodes[projectName], - target, - configuration - ); - const id = this.getId(projectName, target, resolvedConfiguration); - const task = this.createTask( - id, - this.projectGraph.nodes[projectName], - target, - resolvedConfiguration, - overrides - ); - this.tasks[task.id] = task; - this.dependencies[task.id] = []; + const project = this.projectGraph.nodes[projectName]; + if (targets.length === 1 || project.data.targets[target]) { + const resolvedConfiguration = this.resolveConfiguration( + project, + target, + configuration + ); + const id = this.getId(projectName, target, resolvedConfiguration); + const task = this.createTask( + id, + project, + target, + resolvedConfiguration, + overrides + ); + this.tasks[task.id] = task; + this.dependencies[task.id] = []; + } } } diff --git a/packages/nx/src/tasks-runner/life-cycles/dynamic-run-many-terminal-output-life-cycle.ts b/packages/nx/src/tasks-runner/life-cycles/dynamic-run-many-terminal-output-life-cycle.ts index c3c9c10ab8..07ff82da50 100644 --- a/packages/nx/src/tasks-runner/life-cycles/dynamic-run-many-terminal-output-life-cycle.ts +++ b/packages/nx/src/tasks-runner/life-cycles/dynamic-run-many-terminal-output-life-cycle.ts @@ -7,7 +7,7 @@ import type { LifeCycle } from '../life-cycle'; import type { TaskStatus } from '../tasks-runner'; import { Task } from '../../config/task-graph'; import { prettyTime } from './pretty-time'; -import { formatFlags } from './formatting-utils'; +import { formatFlags, formatTargetsAndProjects } from './formatting-utils'; import { viewLogsFooterRows } from './view-logs-utils'; /** @@ -28,7 +28,7 @@ export async function createRunManyDynamicOutputRenderer({ }: { projectNames: string[]; tasks: Task[]; - args: { target?: string; configuration?: string; parallel?: number }; + args: { targets?: string[]; configuration?: string; parallel?: number }; overrides: Record; }): Promise<{ lifeCycle: LifeCycle; renderIsDone: Promise }> { cliCursor.hide(); @@ -41,8 +41,8 @@ export async function createRunManyDynamicOutputRenderer({ }); function clearRenderInterval() { - if (renderProjectRowsIntervalId) { - clearInterval(renderProjectRowsIntervalId); + if (renderIntervalId) { + clearInterval(renderIntervalId); } } @@ -57,14 +57,11 @@ export async function createRunManyDynamicOutputRenderer({ const start = process.hrtime(); const figures = await import('figures'); + const targets = args.targets; const totalTasks = tasks.length; - const totalProjects = projectNames.length; - const totalDependentTasks = totalTasks - totalProjects; - const targetName = args.target; - const configuration = args.configuration; - const projectRows = projectNames.map((projectName) => { + const taskRows = tasks.map((task) => { return { - projectName, + task, status: 'pending', }; }); @@ -83,8 +80,8 @@ export async function createRunManyDynamicOutputRenderer({ let totalCachedTasks = 0; // Used to control the rendering of the spinner on each project row - let projectRowsCurrentFrame = 0; - let renderProjectRowsIntervalId: NodeJS.Timeout | undefined; + let currentFrame = 0; + let renderIntervalId: NodeJS.Timeout | undefined; const clearPinnedFooter = () => { for (let i = 0; i < pinnedFooterNumLines; i++) { @@ -180,16 +177,16 @@ export async function createRunManyDynamicOutputRenderer({ delete tasksToTerminalOutputs[task.id]; renderPinnedFooter([]); - renderProjectRows(); + renderRows(); }; - const renderProjectRows = () => { + const renderRows = () => { const max = dots.frames.length - 1; - const curr = projectRowsCurrentFrame; - projectRowsCurrentFrame = curr >= max ? 0 : curr + 1; + const curr = currentFrame; + currentFrame = curr >= max ? 0 : curr + 1; const additionalFooterRows: string[] = ['']; - const runningTasks = projectRows.filter((row) => row.status === 'running'); + const runningTasks = taskRows.filter((row) => row.status === 'running'); const remainingTasks = totalTasks - totalCompletedTasks; if (runningTasks.length > 0) { @@ -203,16 +200,11 @@ export async function createRunManyDynamicOutputRenderer({ ) ); additionalFooterRows.push(''); - for (const projectRow of runningTasks) { + for (const runningTask of runningTasks) { additionalFooterRows.push( ` ${output.dim.cyan( - dots.frames[projectRowsCurrentFrame] - )} ${output.formatCommand( - projectRow.projectName + - ':' + - targetName + - (configuration ? ':' + configuration : '') - )}` + dots.frames[currentFrame] + )} ${output.formatCommand(runningTask.task.id)}` ); } /** @@ -261,15 +253,11 @@ export async function createRunManyDynamicOutputRenderer({ clearPinnedFooter(); if (additionalFooterRows.length > 1) { - let text = `Running target ${output.bold.cyan( - targetName - )} for ${output.bold.cyan(totalProjects)} projects`; - if (totalDependentTasks > 0) { - text += ` and ${output.bold( - totalDependentTasks - )} task(s) they depend on`; - } - + const text = `Running target ${formatTargetsAndProjects( + projectNames, + targets, + tasks + )}`; const taskOverridesRows = []; if (Object.keys(overrides).length > 0) { const leftPadding = `${output.X_PADDING} `; @@ -302,14 +290,17 @@ export async function createRunManyDynamicOutputRenderer({ }; lifeCycle.startCommand = () => { - if (totalProjects <= 0) { - let description = `with target ${output.colors.white.bold(targetName)}`; - if (args.configuration) { - description += ` that are configured for "${args.configuration}"`; - } + if (projectNames.length <= 0) { renderPinnedFooter([ '', - output.applyNxPrefix('gray', `No projects ${description} were run`), + output.applyNxPrefix( + 'gray', + `No projects with ${formatTargetsAndProjects( + projectNames, + targets, + tasks + )} were run` + ), ]); resolveRenderIsDonePromise(); return; @@ -323,15 +314,11 @@ export async function createRunManyDynamicOutputRenderer({ clearPinnedFooter(); if (totalSuccessfulTasks === totalTasks) { - let text = `Successfully ran target ${output.bold( - targetName - )} for ${output.bold(totalProjects)} projects`; - if (totalDependentTasks > 0) { - text += ` and ${output.bold( - totalDependentTasks - )} task(s) they depend on`; - } - + const text = `Successfully ran ${formatTargetsAndProjects( + projectNames, + targets, + tasks + )}`; const taskOverridesRows = []; if (Object.keys(overrides).length > 0) { const leftPadding = `${output.X_PADDING} `; @@ -362,15 +349,11 @@ export async function createRunManyDynamicOutputRenderer({ } renderPinnedFooter(pinnedFooterLines, 'green'); } else { - let text = `Ran target ${output.bold(targetName)} for ${output.bold( - totalProjects - )} projects`; - if (totalDependentTasks > 0) { - text += ` and ${output.bold( - totalDependentTasks - )} task(s) they depend on`; - } - + const text = `Ran ${formatTargetsAndProjects( + projectNames, + targets, + tasks + )}`; const taskOverridesRows = []; if (Object.keys(overrides).length > 0) { const leftPadding = `${output.X_PADDING} `; @@ -437,17 +420,13 @@ export async function createRunManyDynamicOutputRenderer({ for (const task of tasks) { tasksToProcessStartTimes[task.id] = process.hrtime(); } - for (const projectRow of projectRows) { - const matchedTask = tasks.find( - (t) => t.target.project === projectRow.projectName - ); - if (!matchedTask) { - continue; + for (const taskRow of taskRows) { + if (tasks.indexOf(taskRow.task) > -1) { + taskRow.status = 'running'; } - projectRow.status = 'running'; } - if (!renderProjectRowsIntervalId) { - renderProjectRowsIntervalId = setInterval(renderProjectRows, 100); + if (!renderIntervalId) { + renderIntervalId = setInterval(renderRows, 100); } }; @@ -458,11 +437,9 @@ export async function createRunManyDynamicOutputRenderer({ lifeCycle.endTasks = (taskResults) => { for (let t of taskResults) { totalCompletedTasks++; - const matchingProjectRow = projectRows.find( - (pr) => pr.projectName === t.task.target.project - ); - if (matchingProjectRow) { - matchingProjectRow.status = t.status; + const matchingTaskRow = taskRows.find((r) => r.task === t.task); + if (matchingTaskRow) { + matchingTaskRow.status = t.status; } switch (t.status) { diff --git a/packages/nx/src/tasks-runner/life-cycles/dynamic-run-one-terminal-output-life-cycle.ts b/packages/nx/src/tasks-runner/life-cycles/dynamic-run-one-terminal-output-life-cycle.ts index 58a2b1b739..4cd3a207e2 100644 --- a/packages/nx/src/tasks-runner/life-cycles/dynamic-run-one-terminal-output-life-cycle.ts +++ b/packages/nx/src/tasks-runner/life-cycles/dynamic-run-one-terminal-output-life-cycle.ts @@ -6,7 +6,7 @@ import { output } from '../../utils/output'; import type { LifeCycle } from '../life-cycle'; import { prettyTime } from './pretty-time'; import { Task } from '../../config/task-graph'; -import { formatFlags } from './formatting-utils'; +import { formatFlags, formatTargetsAndProjects } from './formatting-utils'; import { viewLogsFooterRows } from './view-logs-utils'; /** @@ -272,14 +272,11 @@ export async function createRunOneDynamicOutputRenderer({ if (totalSuccessfulTasks === totalTasks) { state = 'COMPLETED_SUCCESSFULLY'; - let text = `Successfully ran target ${output.bold( - targetName - )} for project ${output.bold(initiatingProject)}`; - if (totalDependentTasks > 0) { - text += ` and ${output.bold( - totalDependentTasks - )} task(s) it depends on`; - } + const text = `Successfully ran ${formatTargetsAndProjects( + [initiatingProject], + [tasks[0].target.target], + tasks + )}`; const taskOverridesLines = []; if (Object.keys(overrides).length > 0) { @@ -319,7 +316,7 @@ export async function createRunOneDynamicOutputRenderer({ if (totalDependentTasks > 0) { text += ` and ${output.bold( totalDependentTasks - )} task(s) it depends on`; + )} task(s) they depend on`; } const taskOverridesLines = []; diff --git a/packages/nx/src/tasks-runner/life-cycles/formatting-utils.ts b/packages/nx/src/tasks-runner/life-cycles/formatting-utils.ts index 187ec7b3f9..9a0465fadc 100644 --- a/packages/nx/src/tasks-runner/life-cycles/formatting-utils.ts +++ b/packages/nx/src/tasks-runner/life-cycles/formatting-utils.ts @@ -1,3 +1,6 @@ +import { Task } from '../../config/task-graph'; +import { output } from '../../utils/output'; + export function formatFlags( leftPadding: string, flag: string, @@ -17,3 +20,38 @@ function formatValue(value: any) { return value; } } + +export function formatTargetsAndProjects( + projectNames: string[], + targets: string[], + tasks: Task[] +) { + if (tasks.length === 1) + return `target ${targets[0]} for project ${projectNames[0]}`; + + let text; + const project = + projectNames.length === 1 + ? `project ${projectNames[0]}` + : `${projectNames.length} projects`; + if (targets.length === 1) { + text = `target ${output.bold(targets[0])} for ${project}`; + } else { + text = `targets ${targets + .map((t) => output.bold(t)) + .join(', ')} for ${project}`; + } + + const dependentTasks = tasks.filter( + (t) => + projectNames.indexOf(t.target.project) === -1 || + targets.indexOf(t.target.target) === -1 + ).length; + + if (dependentTasks > 0) { + text += ` and ${output.bold(dependentTasks)} ${ + dependentTasks === 1 ? 'task' : 'tasks' + } ${projectNames.length === 1 ? 'it depends on' : 'they depend on'}`; + } + return text; +} diff --git a/packages/nx/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.ts b/packages/nx/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.ts index 4b261ae27a..d4f5e37ee9 100644 --- a/packages/nx/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.ts +++ b/packages/nx/src/tasks-runner/life-cycles/static-run-many-terminal-output-life-cycle.ts @@ -3,7 +3,7 @@ import { TaskStatus } from '../tasks-runner'; import { getPrintableCommandArgsForTask } from '../utils'; import type { LifeCycle } from '../life-cycle'; import { Task } from '../../config/task-graph'; -import { formatFlags } from './formatting-utils'; +import { formatFlags, formatTargetsAndProjects } from './formatting-utils'; /** * The following life cycle's outputs are static, meaning no previous content @@ -22,7 +22,7 @@ export class StaticRunManyTerminalOutputLifeCycle implements LifeCycle { private readonly projectNames: string[], private readonly tasks: Task[], private readonly args: { - target?: string; + targets?: string[]; configuration?: string; }, private readonly taskOverrides: any @@ -30,11 +30,13 @@ export class StaticRunManyTerminalOutputLifeCycle implements LifeCycle { startCommand(): void { if (this.projectNames.length <= 0) { - let description = `with "${this.args.target}"`; - if (this.args.configuration) { - description += ` that are configured for "${this.args.configuration}"`; - } - output.logSingleLine(`No projects ${description} were run`); + output.logSingleLine( + `No projects with ${formatTargetsAndProjects( + this.projectNames, + this.args.targets, + this.tasks + )} were run` + ); return; } @@ -49,16 +51,11 @@ export class StaticRunManyTerminalOutputLifeCycle implements LifeCycle { .forEach((arg) => bodyLines.push(arg)); } - let title = `Running target ${output.bold( - this.args.target - )} for ${output.bold(this.projectNames.length)} project(s)`; - const dependentTasksCount = this.tasks.length - this.projectNames.length; - if (dependentTasksCount > 0) { - title += ` and ${output.bold( - dependentTasksCount - )} task(s) they depend on`; - } - title += ':'; + const title = `Running ${formatTargetsAndProjects( + this.projectNames, + this.args.targets, + this.tasks + )}:`; output.log({ color: 'cyan', @@ -85,9 +82,11 @@ export class StaticRunManyTerminalOutputLifeCycle implements LifeCycle { : []; output.success({ - title: `Successfully ran target ${output.bold( - this.args.target - )} for ${output.bold(this.projectNames.length)} projects`, + title: `Successfully ran ${formatTargetsAndProjects( + this.projectNames, + this.args.targets, + this.tasks + )}`, bodyLines, }); } else { @@ -113,7 +112,11 @@ export class StaticRunManyTerminalOutputLifeCycle implements LifeCycle { ) ); output.error({ - title: `Running target "${this.args.target}" failed`, + title: `Running ${formatTargetsAndProjects( + this.projectNames, + this.args.targets, + this.tasks + )} failed`, bodyLines, }); } diff --git a/packages/nx/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.ts b/packages/nx/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.ts index ee5ab25e63..7f13f14e6e 100644 --- a/packages/nx/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.ts +++ b/packages/nx/src/tasks-runner/life-cycles/static-run-one-terminal-output-life-cycle.ts @@ -3,6 +3,7 @@ import { TaskStatus } from '../tasks-runner'; import { getPrintableCommandArgsForTask } from '../utils'; import type { LifeCycle } from '../life-cycle'; import { Task } from '../../config/task-graph'; +import { formatTargetsAndProjects } from './formatting-utils'; /** * The following life cycle's outputs are static, meaning no previous content @@ -21,22 +22,22 @@ export class StaticRunOneTerminalOutputLifeCycle implements LifeCycle { private readonly projectNames: string[], private readonly tasks: Task[], private readonly args: { - target?: string; + targets?: string[]; configuration?: string; } ) {} startCommand(): void { const numberOfDeps = this.tasks.length - 1; - + const title = `Running ${formatTargetsAndProjects( + this.projectNames, + this.args.targets, + this.tasks + )}:`; if (numberOfDeps > 0) { output.log({ color: 'cyan', - title: `Running target ${output.bold( - this.args.target - )} for project ${output.bold(this.initiatingProject)} and ${output.bold( - numberOfDeps - )} task(s) it depends on`, + title, }); output.addVerticalSeparatorWithoutNewLines('cyan'); } @@ -58,9 +59,11 @@ export class StaticRunOneTerminalOutputLifeCycle implements LifeCycle { : []; output.success({ - title: `Successfully ran target ${output.bold( - this.args.target - )} for project ${output.bold(this.initiatingProject)}`, + title: `Successfully ran ${formatTargetsAndProjects( + this.projectNames, + this.args.targets, + this.tasks + )}`, bodyLines, }); } else { @@ -76,7 +79,11 @@ export class StaticRunOneTerminalOutputLifeCycle implements LifeCycle { )}`, ]; output.error({ - title: `Running target "${this.initiatingProject}:${this.args.target}" failed`, + title: `Running ${formatTargetsAndProjects( + this.projectNames, + this.args.targets, + this.tasks + )} failed`, bodyLines, }); } diff --git a/packages/nx/src/tasks-runner/run-command.ts b/packages/nx/src/tasks-runner/run-command.ts index c2b95ee3d3..2793151514 100644 --- a/packages/nx/src/tasks-runner/run-command.ts +++ b/packages/nx/src/tasks-runner/run-command.ts @@ -129,7 +129,7 @@ export async function runCommand( projectGraph, defaultDependencyConfigs, projectNames, - [nxArgs.target], + nxArgs.targets, nxArgs.configuration, overrides, extraOptions.excludeTaskDependencies @@ -199,7 +199,6 @@ export async function runCommand( { initiatingProject: nxArgs.outputStyle === 'compact' ? null : initiatingProject, - target: nxArgs.target, projectGraph, nxJson, nxArgs, diff --git a/packages/nx/src/utils/command-line-utils.ts b/packages/nx/src/utils/command-line-utils.ts index 0794e5bd9e..d806ca7e4c 100644 --- a/packages/nx/src/utils/command-line-utils.ts +++ b/packages/nx/src/utils/command-line-utils.ts @@ -12,6 +12,7 @@ export interface RawNxArgs extends NxArgs { export interface NxArgs { target?: string; + targets?: string[]; configuration?: string; runner?: string; parallel?: number; @@ -44,6 +45,13 @@ export function splitArgsIntoNxArgsAndOverrides( nxArgs: NxArgs; overrides: Arguments & { __overrides_unparsed__: string[] }; } { + // this is to lerna case when this function is invoked imperatively + if (args['target'] && !args['targets']) { + args['targets'] = [args['target']]; + } + delete args['target']; + delete args['t']; + if (!args.__overrides_unparsed__ && args._) { // required for backwards compatibility args.__overrides_unparsed__ = args._; @@ -75,10 +83,6 @@ export function splitArgsIntoNxArgsAndOverrides( if (mode === 'run-many') { if (!nxArgs.projects) { nxArgs.projects = []; - } else { - nxArgs.projects = (args.projects as string) - .split(',') - .map((p: string) => p.trim()); } }