diff --git a/e2e/workspace/src/workspace.test.ts b/e2e/workspace/src/workspace.test.ts index bb1ee2da45..6a27eea2b2 100644 --- a/e2e/workspace/src/workspace.test.ts +++ b/e2e/workspace/src/workspace.test.ts @@ -499,16 +499,6 @@ forEachCli((cliName) => { ) ); expect(resWithDeps.tasks).toEqual([ - { - id: `${mypublishablelib}:build`, - overrides: {}, - target: { - project: mypublishablelib, - target: 'build', - }, - command: `npm run ${cliCommand} -- build ${mypublishablelib}`, - outputs: [`dist/libs/${mypublishablelib}`], - }, { id: `${myapp}:build`, overrides: {}, @@ -519,6 +509,16 @@ forEachCli((cliName) => { command: `npm run ${cliCommand} -- build ${myapp}`, outputs: [`dist/apps/${myapp}`], }, + { + id: `${mypublishablelib}:build`, + overrides: {}, + target: { + project: mypublishablelib, + target: 'build', + }, + command: `npm run ${cliCommand} -- build ${mypublishablelib}`, + outputs: [`dist/libs/${mypublishablelib}`], + }, ]); compareTwoArrays(resWithDeps.projects, [ mylib, diff --git a/packages/workspace/src/core/project-graph/operators.spec.ts b/packages/workspace/src/core/project-graph/operators.spec.ts index aa253e07a9..7007aadcf2 100644 --- a/packages/workspace/src/core/project-graph/operators.spec.ts +++ b/packages/workspace/src/core/project-graph/operators.spec.ts @@ -173,6 +173,65 @@ describe('withDeps', () => { }, }); }); + + it('should handle circular deps', () => { + const graph: ProjectGraph = { + nodes: { + lib1: { name: 'lib1', type: 'lib', data: null }, + lib2: { name: 'lib2', type: 'lib', data: null }, + }, + dependencies: { + lib1: [ + { + type: DependencyType.static, + source: 'lib1', + target: 'lib2', + }, + ], + lib2: [ + { + type: DependencyType.static, + source: 'lib2', + target: 'lib1', + }, + ], + }, + }; + + const affectedNodes = [{ name: 'lib1', type: 'lib', data: null }]; + + const result = withDeps(graph, affectedNodes); + expect(result).toEqual({ + nodes: { + lib1: { + name: 'lib1', + type: 'lib', + data: null, + }, + lib2: { + name: 'lib2', + type: 'lib', + data: null, + }, + }, + dependencies: { + lib2: [ + { + type: 'static', + source: 'lib2', + target: 'lib1', + }, + ], + lib1: [ + { + type: 'static', + source: 'lib1', + target: 'lib2', + }, + ], + }, + }); + }); }); describe('filterNodes', () => { diff --git a/packages/workspace/src/core/project-graph/operators.ts b/packages/workspace/src/core/project-graph/operators.ts index b6bfae788f..2568213d37 100644 --- a/packages/workspace/src/core/project-graph/operators.ts +++ b/packages/workspace/src/core/project-graph/operators.ts @@ -80,22 +80,35 @@ export function withDeps( subsetNodes: ProjectGraphNode[] ): ProjectGraph { const builder = new ProjectGraphBuilder(); - Object.values(subsetNodes).forEach(recur); + const visitedNodes = []; + const visitedEdges = []; + Object.values(subsetNodes).forEach(recurNodes); + Object.values(subsetNodes).forEach(recurEdges); return builder.build(); // --------------------------------------------------------------------------- - function recur(node) { - const ds = original.dependencies[node.name]; - // 1. Recursively add all source nodes - ds.forEach((n) => { - recur(original.nodes[n.target]); - }); - // 2. Add current node + function recurNodes(node) { + if (visitedNodes.indexOf(node.name) > -1) return; builder.addNode(node); - // 3. Add all source dependencies + visitedNodes.push(node.name); + + original.dependencies[node.name].forEach((n) => { + recurNodes(original.nodes[n.target]); + }); + } + + function recurEdges(node) { + if (visitedEdges.indexOf(node.name) > -1) return; + visitedEdges.push(node.name); + + const ds = original.dependencies[node.name]; ds.forEach((n) => { builder.addDependency(n.type, n.source, n.target); }); + + ds.forEach((n) => { + recurEdges(original.nodes[n.target]); + }); } }