diff --git a/packages/nx/src/project-graph/affected/locators/workspace-projects.spec.ts b/packages/nx/src/project-graph/affected/locators/workspace-projects.spec.ts index 359ae7cf0fe4f..72ad8346b9965 100644 --- a/packages/nx/src/project-graph/affected/locators/workspace-projects.spec.ts +++ b/packages/nx/src/project-graph/affected/locators/workspace-projects.spec.ts @@ -107,6 +107,44 @@ describe('getImplicitlyTouchedProjects', () => { ]); }); + it('should return projects which have touched files in their named inputs', () => { + const graph = buildProjectGraphNodes({ + a: { + root: 'a', + namedInputs: { + projectSpecificFiles: ['{workspaceRoot}/a.txt'], + }, + }, + b: { + root: 'b', + }, + }); + let fileChanges = getFileChanges(['a.txt']); + expect(getImplicitlyTouchedProjects(fileChanges, graph, nxJson)).toEqual([ + 'a', + ]); + }); + + it('should return projects which have touched files in their target inputs', () => { + const graph = buildProjectGraphNodes({ + a: { + root: 'a', + targets: { + build: { + inputs: ['{workspaceRoot}/a.txt'], + }, + }, + }, + b: { + root: 'b', + }, + }); + let fileChanges = getFileChanges(['a.txt']); + expect(getImplicitlyTouchedProjects(fileChanges, graph, nxJson)).toEqual([ + 'a', + ]); + }); + it('should return a list of unique projects', () => { const fileChanges = getFileChanges([ 'styles/file2.css', @@ -161,50 +199,20 @@ describe('getImplicitlyTouchedProjects', () => { describe('extractGlobalFilesFromInputs', () => { it('should return list of global files from nx.json', () => { - const globalFiles = extractGlobalFilesFromInputs( - { - namedInputs: { - one: [ - '{workspaceRoot}/global1.txt', - { fileset: '{workspaceRoot}/global2.txt' }, - '{projectRoot}/local.txt', - ], - }, - targetDefaults: { - build: { - inputs: ['{workspaceRoot}/global3.txt'], - }, + const globalFiles = extractGlobalFilesFromInputs({ + namedInputs: { + one: [ + '{workspaceRoot}/global1.txt', + { fileset: '{workspaceRoot}/global2.txt' }, + '{projectRoot}/local.txt', + ], + }, + targetDefaults: { + build: { + inputs: ['{workspaceRoot}/global3.txt'], }, }, - {} - ); - expect(globalFiles).toEqual(['global1.txt', 'global2.txt', 'global3.txt']); - }); - - it('should return list of global files from project configuration', () => { - const globalFiles = extractGlobalFilesFromInputs( - {}, - { - one: { - name: 'one', - type: 'lib', - data: { - namedInputs: { - one: [ - '{workspaceRoot}/global1.txt', - { fileset: '{workspaceRoot}/global2.txt' }, - '{projectRoot}/local.txt', - ], - }, - targets: { - build: { - inputs: ['{workspaceRoot}/global3.txt'], - }, - }, - }, - } as any, - } - ); + }); expect(globalFiles).toEqual(['global1.txt', 'global2.txt', 'global3.txt']); }); }); 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 5386e058e5293..89301bbab59f5 100644 --- a/packages/nx/src/project-graph/affected/locators/workspace-projects.ts +++ b/packages/nx/src/project-graph/affected/locators/workspace-projects.ts @@ -1,7 +1,6 @@ import * as minimatch from 'minimatch'; import { TouchedProjectLocator } from '../affected-project-graph-models'; import { NxJsonConfiguration } from '../../../config/nx-json'; -import { ProjectGraphProjectNode } from '../../../config/project-graph'; import { createProjectRootMappings, findProjectForPath, @@ -29,7 +28,7 @@ export const getImplicitlyTouchedProjects: TouchedProjectLocator = ( ): string[] => { const implicits = { ...nxJson.implicitDependencies }; const globalFiles = [ - ...extractGlobalFilesFromInputs(nxJson, projectGraphNodes), + ...extractGlobalFilesFromInputs(nxJson), 'nx.json', 'package-lock.json', 'yarn.lock', @@ -40,6 +39,19 @@ export const getImplicitlyTouchedProjects: TouchedProjectLocator = ( implicits[file] = '*' as any; }); + Object.values(projectGraphNodes || {}).forEach((node) => { + [ + ...extractFilesFromNamedInputs(node.data.namedInputs), + ...extractFilesFromTargetInputs(node.data.targets), + ].forEach((input) => { + implicits[input] ??= []; + + if (Array.isArray(implicits[input])) { + implicits[input].push(node.name); + } + }); + }); + const touched = new Set(); for (const [pattern, projects] of Object.entries(implicits)) { @@ -61,41 +73,32 @@ export const getImplicitlyTouchedProjects: TouchedProjectLocator = ( return Array.from(touched); }; -export function extractGlobalFilesFromInputs( - nxJson: NxJsonConfiguration, - projectGraphNodes: Record -) { +export function extractGlobalFilesFromInputs(nxJson: NxJsonConfiguration) { const globalFiles = []; - globalFiles.push(...extractGlobalFilesFromNamedInputs(nxJson.namedInputs)); - globalFiles.push(...extractGlobalFilesFromTargets(nxJson.targetDefaults)); - Object.values(projectGraphNodes || {}).forEach((node) => { - globalFiles.push( - ...extractGlobalFilesFromNamedInputs(node.data.namedInputs) - ); - globalFiles.push(...extractGlobalFilesFromTargets(node.data.targets)); - }); + globalFiles.push(...extractFilesFromNamedInputs(nxJson.namedInputs)); + globalFiles.push(...extractFilesFromTargetInputs(nxJson.targetDefaults)); return globalFiles; } -function extractGlobalFilesFromNamedInputs(namedInputs: any) { - const globalFiles = []; +function extractFilesFromNamedInputs(namedInputs: any) { + const files = []; for (const inputs of Object.values(namedInputs || {})) { - globalFiles.push(...extractGlobalFiles(inputs)); + files.push(...extractFilesFromInputs(inputs)); } - return globalFiles; + return files; } -function extractGlobalFilesFromTargets(targets: any) { +function extractFilesFromTargetInputs(targets: any) { const globalFiles = []; for (const target of Object.values(targets || {})) { if ((target as any).inputs) { - globalFiles.push(...extractGlobalFiles((target as any).inputs)); + globalFiles.push(...extractFilesFromInputs((target as any).inputs)); } } return globalFiles; } -function extractGlobalFiles(inputs: any) { +function extractFilesFromInputs(inputs: any) { const globalFiles = []; for (const input of inputs) { if (typeof input === 'string' && input.startsWith('{workspaceRoot}/')) {