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 cf8df73f8a5c7..7177042f612a2 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 @@ -7,7 +7,6 @@ import { WholeFileChange } from '../../file-utils'; import { getTouchedProjects, getImplicitlyTouchedProjects, - extractGlobalFilesFromInputs, } from './workspace-projects'; function getFileChanges(files: string[]) { @@ -84,6 +83,9 @@ describe('getImplicitlyTouchedProjects', () => { beforeEach(() => { nxJson = { npmScope: 'nrwl', + namedInputs: { + files: ['{workspaceRoot}/a.txt'], + }, projects: {}, }; }); @@ -95,6 +97,11 @@ describe('getImplicitlyTouchedProjects', () => { namedInputs: { projectSpecificFiles: ['{workspaceRoot}/a.txt'], }, + targets: { + build: { + inputs: ['projectSpecificFiles'], + }, + }, }, b: { root: 'b', @@ -125,25 +132,44 @@ describe('getImplicitlyTouchedProjects', () => { 'a', ]); }); -}); -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', - ], + it('should return projects which have touched files in their target inputs which are named inputs defined in nx.json', () => { + const graph = buildProjectGraphNodes({ + a: { + root: 'a', + targets: { + build: { + inputs: ['files'], + }, + }, }, - targetDefaults: { - build: { - inputs: ['{workspaceRoot}/global3.txt'], + b: { + root: 'b', + }, + }); + let fileChanges = getFileChanges(['a.txt']); + expect(getImplicitlyTouchedProjects(fileChanges, graph, nxJson)).toEqual([ + 'a', + ]); + }); + + it('should not return projects which have touched files inputs which are not used by its targets', () => { + const graph = buildProjectGraphNodes({ + a: { + root: 'a', + namedInputs: { + files: ['{workspaceRoot}/a.txt'], }, + targets: {}, + }, + b: { + root: 'b', }, }); - expect(globalFiles).toEqual(['global1.txt', 'global2.txt', 'global3.txt']); + let fileChanges = getFileChanges(['a.txt']); + expect(getImplicitlyTouchedProjects(fileChanges, graph, nxJson)).toEqual( + [] + ); }); }); 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 58169c74757e4..d7a1a777f6b4c 100644 --- a/packages/nx/src/project-graph/affected/locators/workspace-projects.ts +++ b/packages/nx/src/project-graph/affected/locators/workspace-projects.ts @@ -1,10 +1,10 @@ import { minimatch } from 'minimatch'; import { TouchedProjectLocator } from '../affected-project-graph-models'; -import { NxJsonConfiguration } from '../../../config/nx-json'; import { createProjectRootMappings, findProjectForPath, } from '../../utils/find-project-for-path'; +import { InputDefinition } from '../../../config/workspace-json-project-json'; export const getTouchedProjects: TouchedProjectLocator = ( touchedFiles, @@ -27,22 +27,21 @@ export const getImplicitlyTouchedProjects: TouchedProjectLocator = ( nxJson ): string[] => { const implicits = {}; - const globalFiles = [...extractGlobalFilesFromInputs(nxJson), 'nx.json']; - globalFiles.forEach((file) => { - implicits[file] = '*' as any; - }); Object.values(projectGraphNodes || {}).forEach((node) => { - [ - ...extractFilesFromNamedInputs(node.data.namedInputs), - ...extractFilesFromTargetInputs(node.data.targets), - ].forEach((input) => { - implicits[input] ??= []; + const namedInputs = { + ...nxJson.namedInputs, + ...node.data.namedInputs, + }; + extractFilesFromTargetInputs(node.data.targets, namedInputs).forEach( + (input) => { + implicits[input] ??= []; - if (Array.isArray(implicits[input])) { - implicits[input].push(node.name); + if (Array.isArray(implicits[input])) { + implicits[input].push(node.name); + } } - }); + ); }); const touched = new Set(); @@ -66,35 +65,33 @@ export const getImplicitlyTouchedProjects: TouchedProjectLocator = ( return Array.from(touched); }; -export function extractGlobalFilesFromInputs(nxJson: NxJsonConfiguration) { - const globalFiles = []; - globalFiles.push(...extractFilesFromNamedInputs(nxJson.namedInputs)); - globalFiles.push(...extractFilesFromTargetInputs(nxJson.targetDefaults)); - return globalFiles; -} - -function extractFilesFromNamedInputs(namedInputs: any) { - const files = []; - for (const inputs of Object.values(namedInputs || {})) { - files.push(...extractFilesFromInputs(inputs)); - } - return files; -} - -function extractFilesFromTargetInputs(targets: any) { +function extractFilesFromTargetInputs( + targets: any, + namedInputs: Record> +) { const globalFiles = []; for (const target of Object.values(targets || {})) { if ((target as any).inputs) { - globalFiles.push(...extractFilesFromInputs((target as any).inputs)); + globalFiles.push( + ...extractFilesFromInputs((target as any).inputs, namedInputs) + ); } } return globalFiles; } -function extractFilesFromInputs(inputs: any) { +function extractFilesFromInputs( + inputs: any, + namedInputs: Record> +) { const globalFiles = []; for (const input of inputs) { - if (typeof input === 'string' && input.startsWith('{workspaceRoot}/')) { + if (typeof input === 'string' && input in namedInputs) { + return extractFilesFromInputs(namedInputs[input], namedInputs); + } else if ( + typeof input === 'string' && + input.startsWith('{workspaceRoot}/') + ) { globalFiles.push(input.substring('{workspaceRoot}/'.length)); } else if (input.fileset && input.fileset.startsWith('{workspaceRoot}/')) { globalFiles.push(input.fileset.substring('{workspaceRoot}/'.length));