fix(core): include dependencies of projects which do not have a target (#6309)
This commit is contained in:
parent
d35d03e55e
commit
033579712f
@ -1,5 +1,113 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`TaskGraphCreator (tasks with dependency configurations) should create a task graph (builds depend on builds of dependencies even with intermediate projects) 1`] = `
|
||||||
|
Object {
|
||||||
|
"dependencies": Object {
|
||||||
|
"app1:build": Array [
|
||||||
|
"common2:build",
|
||||||
|
],
|
||||||
|
"common2:build": Array [],
|
||||||
|
},
|
||||||
|
"roots": Array [
|
||||||
|
"common2:build",
|
||||||
|
],
|
||||||
|
"tasks": Object {
|
||||||
|
"app1:build": Object {
|
||||||
|
"id": "app1:build",
|
||||||
|
"overrides": Object {},
|
||||||
|
"projectRoot": "app1-root",
|
||||||
|
"target": Object {
|
||||||
|
"configuration": undefined,
|
||||||
|
"project": "app1",
|
||||||
|
"target": "build",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"common2:build": Object {
|
||||||
|
"id": "common2:build",
|
||||||
|
"overrides": Object {},
|
||||||
|
"projectRoot": "common2-root",
|
||||||
|
"target": Object {
|
||||||
|
"configuration": undefined,
|
||||||
|
"project": "common2",
|
||||||
|
"target": "build",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`TaskGraphCreator (tasks with dependency configurations) should create a task graph (builds depend on builds of dependencies with intermediate projects and circular dependencies between projects) 1`] = `
|
||||||
|
Object {
|
||||||
|
"dependencies": Object {
|
||||||
|
"app1:build": Array [
|
||||||
|
"common2:build",
|
||||||
|
],
|
||||||
|
"common2:build": Array [],
|
||||||
|
},
|
||||||
|
"roots": Array [
|
||||||
|
"common2:build",
|
||||||
|
],
|
||||||
|
"tasks": Object {
|
||||||
|
"app1:build": Object {
|
||||||
|
"id": "app1:build",
|
||||||
|
"overrides": Object {},
|
||||||
|
"projectRoot": "app1-root",
|
||||||
|
"target": Object {
|
||||||
|
"configuration": undefined,
|
||||||
|
"project": "app1",
|
||||||
|
"target": "build",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"common2:build": Object {
|
||||||
|
"id": "common2:build",
|
||||||
|
"overrides": Object {},
|
||||||
|
"projectRoot": "common2-root",
|
||||||
|
"target": Object {
|
||||||
|
"configuration": undefined,
|
||||||
|
"project": "common2",
|
||||||
|
"target": "build",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`TaskGraphCreator (tasks with dependency configurations) should create a task graph (builds depend on builds of dependencies with intermediate projects and circular dependencies between projects) 2 1`] = `
|
||||||
|
Object {
|
||||||
|
"dependencies": Object {
|
||||||
|
"app1:build": Array [
|
||||||
|
"common3:build",
|
||||||
|
],
|
||||||
|
"common3:build": Array [],
|
||||||
|
},
|
||||||
|
"roots": Array [
|
||||||
|
"common3:build",
|
||||||
|
],
|
||||||
|
"tasks": Object {
|
||||||
|
"app1:build": Object {
|
||||||
|
"id": "app1:build",
|
||||||
|
"overrides": Object {},
|
||||||
|
"projectRoot": "app1-root",
|
||||||
|
"target": Object {
|
||||||
|
"configuration": undefined,
|
||||||
|
"project": "app1",
|
||||||
|
"target": "build",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"common3:build": Object {
|
||||||
|
"id": "common3:build",
|
||||||
|
"overrides": Object {},
|
||||||
|
"projectRoot": "common3",
|
||||||
|
"target": Object {
|
||||||
|
"configuration": undefined,
|
||||||
|
"project": "common3",
|
||||||
|
"target": "build",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`TaskGraphCreator (tasks with dependency configurations) should create task graph (builds depend on build of dependencies and prebuild of self) 1`] = `
|
exports[`TaskGraphCreator (tasks with dependency configurations) should create task graph (builds depend on build of dependencies and prebuild of self) 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"dependencies": Object {
|
"dependencies": Object {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { TasksRunner } from './tasks-runner';
|
import { TasksRunner } from './tasks-runner';
|
||||||
import defaultTaskRunner from './default-tasks-runner';
|
import defaultTaskRunner from './default-tasks-runner';
|
||||||
import { createTasksForProjectToRun, getRunner } from './run-command';
|
import { createTasksForProjectToRun, getRunner } from './run-command';
|
||||||
|
import type { NxJsonConfiguration, ProjectGraph } from '@nrwl/devkit';
|
||||||
import { DependencyType } from '@nrwl/devkit';
|
import { DependencyType } from '@nrwl/devkit';
|
||||||
import type { ProjectGraph, NxJsonConfiguration } from '@nrwl/devkit';
|
|
||||||
|
|
||||||
describe('createTasksForProjectToRun', () => {
|
describe('createTasksForProjectToRun', () => {
|
||||||
let projectGraph: ProjectGraph;
|
let projectGraph: ProjectGraph;
|
||||||
@ -331,6 +331,279 @@ describe('createTasksForProjectToRun', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create tasks for multiple sets of dependencies for multiple targets', () => {
|
||||||
|
projectGraph.nodes.app1.data.targets.build.dependsOn = [
|
||||||
|
{
|
||||||
|
target: 'prebuild',
|
||||||
|
projects: 'dependencies',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
projects: 'dependencies',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
projectGraph.dependencies.app1.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'app1',
|
||||||
|
target: 'lib1',
|
||||||
|
});
|
||||||
|
|
||||||
|
projectGraph.nodes.lib1.data.targets.prebuild = {};
|
||||||
|
|
||||||
|
const tasks = createTasksForProjectToRun(
|
||||||
|
[projectGraph.nodes.app1],
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
configuration: undefined,
|
||||||
|
overrides: {},
|
||||||
|
},
|
||||||
|
projectGraph,
|
||||||
|
projectGraph.nodes.app1.name
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(tasks).toEqual([
|
||||||
|
{
|
||||||
|
id: 'lib1:prebuild',
|
||||||
|
overrides: {},
|
||||||
|
projectRoot: 'lib1-root',
|
||||||
|
target: {
|
||||||
|
configuration: undefined,
|
||||||
|
project: 'lib1',
|
||||||
|
target: 'prebuild',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'lib1:build',
|
||||||
|
overrides: {},
|
||||||
|
projectRoot: 'lib1-root',
|
||||||
|
target: {
|
||||||
|
configuration: undefined,
|
||||||
|
project: 'lib1',
|
||||||
|
target: 'build',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'app1:build',
|
||||||
|
overrides: {},
|
||||||
|
projectRoot: 'app1-root',
|
||||||
|
target: {
|
||||||
|
configuration: undefined,
|
||||||
|
project: 'app1',
|
||||||
|
target: 'build',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should include dependencies of projects without the same target', () => {
|
||||||
|
// App 1 depends on builds of its dependencies
|
||||||
|
projectGraph.nodes.app1.data.targets.build.dependsOn = [
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
projects: 'dependencies',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// App 1 depends on Lib 1
|
||||||
|
projectGraph.dependencies.app1.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'app1',
|
||||||
|
target: 'lib1',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Lib 1 does not have build but depends on Lib 2
|
||||||
|
delete projectGraph.nodes.lib1.data.targets.build;
|
||||||
|
projectGraph.dependencies.lib1.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'lib1',
|
||||||
|
target: 'lib2',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Lib 2 has a build
|
||||||
|
projectGraph.nodes.lib2 = {
|
||||||
|
name: 'lib2',
|
||||||
|
type: 'lib',
|
||||||
|
data: {
|
||||||
|
root: 'lib2-root',
|
||||||
|
files: [],
|
||||||
|
targets: {
|
||||||
|
build: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
projectGraph.dependencies.lib2 = [];
|
||||||
|
|
||||||
|
const tasks = createTasksForProjectToRun(
|
||||||
|
[projectGraph.nodes.app1],
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
configuration: undefined,
|
||||||
|
overrides: {},
|
||||||
|
},
|
||||||
|
projectGraph,
|
||||||
|
projectGraph.nodes.app1.name
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(tasks).toContainEqual({
|
||||||
|
id: 'app1:build',
|
||||||
|
target: { project: 'app1', target: 'build' },
|
||||||
|
projectRoot: 'app1-root',
|
||||||
|
overrides: {},
|
||||||
|
});
|
||||||
|
expect(tasks).toContainEqual({
|
||||||
|
id: 'lib2:build',
|
||||||
|
target: { project: 'lib2', target: 'build' },
|
||||||
|
projectRoot: 'lib2-root',
|
||||||
|
overrides: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle circular dependencies between projects', () => {
|
||||||
|
// App 1 depends on builds of its dependencies
|
||||||
|
projectGraph.nodes.app1.data.targets.build.dependsOn = [
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
projects: 'dependencies',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// App 1 depends on Lib 1
|
||||||
|
projectGraph.dependencies.app1.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'app1',
|
||||||
|
target: 'lib1',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Lib 1 does not have build but depends on Lib 2
|
||||||
|
delete projectGraph.nodes.lib1.data.targets.build;
|
||||||
|
projectGraph.dependencies.lib1.push(
|
||||||
|
{
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'lib1',
|
||||||
|
target: 'app1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'lib1',
|
||||||
|
target: 'lib2',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Lib 2 has a build
|
||||||
|
projectGraph.nodes.lib2 = {
|
||||||
|
name: 'lib2',
|
||||||
|
type: 'lib',
|
||||||
|
data: {
|
||||||
|
root: 'lib2-root',
|
||||||
|
files: [],
|
||||||
|
targets: {
|
||||||
|
build: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
projectGraph.dependencies.lib2 = [
|
||||||
|
{
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'lib2',
|
||||||
|
target: 'lib1',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const tasks = createTasksForProjectToRun(
|
||||||
|
[projectGraph.nodes.app1],
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
configuration: undefined,
|
||||||
|
overrides: {},
|
||||||
|
},
|
||||||
|
projectGraph,
|
||||||
|
projectGraph.nodes.app1.name
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(tasks).toContainEqual({
|
||||||
|
id: 'app1:build',
|
||||||
|
target: { project: 'app1', target: 'build' },
|
||||||
|
projectRoot: 'app1-root',
|
||||||
|
overrides: {},
|
||||||
|
});
|
||||||
|
expect(tasks).toContainEqual({
|
||||||
|
id: 'lib2:build',
|
||||||
|
target: { project: 'lib2', target: 'build' },
|
||||||
|
projectRoot: 'lib2-root',
|
||||||
|
overrides: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle circular dependencies between projects with no tasks', () => {
|
||||||
|
// App 1 depends on builds of its dependencies
|
||||||
|
projectGraph.nodes.app1.data.targets.build.dependsOn = [
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
projects: 'dependencies',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// App 1 depends on Lib 1
|
||||||
|
projectGraph.dependencies.app1.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'app1',
|
||||||
|
target: 'lib1',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Lib 1 does not have build but depends on Lib 2
|
||||||
|
delete projectGraph.nodes.lib1.data.targets.build;
|
||||||
|
projectGraph.dependencies.lib1.push(
|
||||||
|
{
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'lib1',
|
||||||
|
target: 'app1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'lib1',
|
||||||
|
target: 'lib2',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Lib 2 has a build
|
||||||
|
projectGraph.nodes.lib2 = {
|
||||||
|
name: 'lib2',
|
||||||
|
type: 'lib',
|
||||||
|
data: {
|
||||||
|
root: 'lib2-root',
|
||||||
|
files: [],
|
||||||
|
targets: {
|
||||||
|
build: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
projectGraph.dependencies.lib2 = [];
|
||||||
|
|
||||||
|
const tasks = createTasksForProjectToRun(
|
||||||
|
[projectGraph.nodes.app1],
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
configuration: undefined,
|
||||||
|
overrides: {},
|
||||||
|
},
|
||||||
|
projectGraph,
|
||||||
|
projectGraph.nodes.app1.name
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(tasks).toContainEqual({
|
||||||
|
id: 'app1:build',
|
||||||
|
target: { project: 'app1', target: 'build' },
|
||||||
|
projectRoot: 'app1-root',
|
||||||
|
overrides: {},
|
||||||
|
});
|
||||||
|
expect(tasks).toContainEqual({
|
||||||
|
id: 'lib2:build',
|
||||||
|
target: { project: 'lib2', target: 'build' },
|
||||||
|
projectRoot: 'lib2-root',
|
||||||
|
overrides: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw an error for an invalid target', () => {
|
it('should throw an error for an invalid target', () => {
|
||||||
jest.spyOn(process, 'exit').mockImplementation(() => {
|
jest.spyOn(process, 'exit').mockImplementation(() => {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
|
|||||||
@ -155,6 +155,7 @@ export function createTasksForProjectToRun(
|
|||||||
defaultDependencyConfigs: Record<string, TargetDependencyConfig[]> = {}
|
defaultDependencyConfigs: Record<string, TargetDependencyConfig[]> = {}
|
||||||
) {
|
) {
|
||||||
const tasksMap: Map<string, Task> = new Map<string, Task>();
|
const tasksMap: Map<string, Task> = new Map<string, Task>();
|
||||||
|
const seenSet = new Set<string>();
|
||||||
|
|
||||||
for (const project of projectsToRun) {
|
for (const project of projectsToRun) {
|
||||||
addTasksForProjectTarget(
|
addTasksForProjectTarget(
|
||||||
@ -166,7 +167,8 @@ export function createTasksForProjectToRun(
|
|||||||
defaultDependencyConfigs,
|
defaultDependencyConfigs,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
tasksMap,
|
tasksMap,
|
||||||
[]
|
[],
|
||||||
|
seenSet
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Array.from(tasksMap.values());
|
return Array.from(tasksMap.values());
|
||||||
@ -183,7 +185,8 @@ function addTasksForProjectTarget(
|
|||||||
defaultDependencyConfigs: Record<string, TargetDependencyConfig[]> = {},
|
defaultDependencyConfigs: Record<string, TargetDependencyConfig[]> = {},
|
||||||
projectGraph: ProjectGraph,
|
projectGraph: ProjectGraph,
|
||||||
tasksMap: Map<string, Task>,
|
tasksMap: Map<string, Task>,
|
||||||
path: string[]
|
path: string[],
|
||||||
|
seenSet: Set<string>
|
||||||
) {
|
) {
|
||||||
const task = createTask({
|
const task = createTask({
|
||||||
project,
|
project,
|
||||||
@ -211,7 +214,8 @@ function addTasksForProjectTarget(
|
|||||||
defaultDependencyConfigs,
|
defaultDependencyConfigs,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
tasksMap,
|
tasksMap,
|
||||||
path
|
path,
|
||||||
|
seenSet
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,13 +271,15 @@ function addTasksForProjectDependencyConfig(
|
|||||||
defaultDependencyConfigs: Record<string, TargetDependencyConfig[]>,
|
defaultDependencyConfigs: Record<string, TargetDependencyConfig[]>,
|
||||||
projectGraph: ProjectGraph,
|
projectGraph: ProjectGraph,
|
||||||
tasksMap: Map<string, Task>,
|
tasksMap: Map<string, Task>,
|
||||||
path: string[]
|
path: string[],
|
||||||
|
seenSet: Set<string>
|
||||||
) {
|
) {
|
||||||
const targetIdentifier = getId({
|
const targetIdentifier = getId({
|
||||||
project: project.name,
|
project: project.name,
|
||||||
target,
|
target,
|
||||||
configuration,
|
configuration,
|
||||||
});
|
});
|
||||||
|
seenSet.add(project.name);
|
||||||
|
|
||||||
if (path.includes(targetIdentifier)) {
|
if (path.includes(targetIdentifier)) {
|
||||||
output.error({
|
output.error({
|
||||||
@ -303,7 +309,23 @@ function addTasksForProjectDependencyConfig(
|
|||||||
defaultDependencyConfigs,
|
defaultDependencyConfigs,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
tasksMap,
|
tasksMap,
|
||||||
[...path, targetIdentifier]
|
[...path, targetIdentifier],
|
||||||
|
seenSet
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (seenSet.has(dep.target)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
addTasksForProjectDependencyConfig(
|
||||||
|
projectGraph.nodes[dep.target],
|
||||||
|
{ target, configuration },
|
||||||
|
dependencyConfig,
|
||||||
|
defaultDependencyConfigs,
|
||||||
|
projectGraph,
|
||||||
|
tasksMap,
|
||||||
|
path,
|
||||||
|
seenSet
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -319,7 +341,8 @@ function addTasksForProjectDependencyConfig(
|
|||||||
defaultDependencyConfigs,
|
defaultDependencyConfigs,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
tasksMap,
|
tasksMap,
|
||||||
[...path, targetIdentifier]
|
[...path, targetIdentifier],
|
||||||
|
seenSet
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -294,6 +294,109 @@ describe('TaskGraphCreator', () => {
|
|||||||
expect(taskGraph).toMatchSnapshot();
|
expect(taskGraph).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a task graph (builds depend on builds of dependencies even with intermediate projects)', () => {
|
||||||
|
delete projectGraph.nodes.common1.data.targets.build;
|
||||||
|
projectGraph.dependencies.common1.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'common1',
|
||||||
|
target: 'common2',
|
||||||
|
});
|
||||||
|
|
||||||
|
const tasks = createTasksForProjectToRun(
|
||||||
|
[projectGraph.nodes.app1],
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
configuration: undefined,
|
||||||
|
overrides: {},
|
||||||
|
},
|
||||||
|
projectGraph,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
const taskGraph = new TaskGraphCreator(projectGraph, {}).createTaskGraph(
|
||||||
|
tasks
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(taskGraph).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a task graph (builds depend on builds of dependencies with intermediate projects and circular dependencies between projects)', () => {
|
||||||
|
delete projectGraph.nodes.common1.data.targets.build;
|
||||||
|
projectGraph.dependencies.common1.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'common1',
|
||||||
|
target: 'common2',
|
||||||
|
});
|
||||||
|
|
||||||
|
projectGraph.dependencies.common2.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'common2',
|
||||||
|
target: 'common1',
|
||||||
|
});
|
||||||
|
|
||||||
|
const tasks = createTasksForProjectToRun(
|
||||||
|
[projectGraph.nodes.app1],
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
configuration: undefined,
|
||||||
|
overrides: {},
|
||||||
|
},
|
||||||
|
projectGraph,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
const taskGraph = new TaskGraphCreator(projectGraph, {}).createTaskGraph(
|
||||||
|
tasks
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(taskGraph).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a task graph (builds depend on builds of dependencies with intermediate projects and circular dependencies between projects) 2', () => {
|
||||||
|
delete projectGraph.nodes.common1.data.targets.build;
|
||||||
|
projectGraph.dependencies.common1.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'common1',
|
||||||
|
target: 'common2',
|
||||||
|
});
|
||||||
|
|
||||||
|
delete projectGraph.nodes.common2.data.targets.build;
|
||||||
|
projectGraph.dependencies.common2.push({
|
||||||
|
type: DependencyType.static,
|
||||||
|
source: 'common2',
|
||||||
|
target: 'common3',
|
||||||
|
});
|
||||||
|
|
||||||
|
projectGraph.nodes.common3 = {
|
||||||
|
name: 'common3',
|
||||||
|
type: 'lib',
|
||||||
|
data: {
|
||||||
|
root: 'common3',
|
||||||
|
targets: {
|
||||||
|
build: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
projectGraph.dependencies.common3 = [];
|
||||||
|
|
||||||
|
const tasks = createTasksForProjectToRun(
|
||||||
|
[projectGraph.nodes.app1],
|
||||||
|
{
|
||||||
|
target: 'build',
|
||||||
|
configuration: undefined,
|
||||||
|
overrides: {},
|
||||||
|
},
|
||||||
|
projectGraph,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
const taskGraph = new TaskGraphCreator(projectGraph, {}).createTaskGraph(
|
||||||
|
tasks
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(taskGraph).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
it('should create task graph (builds depend on build of dependencies and prebuild of self)', () => {
|
it('should create task graph (builds depend on build of dependencies and prebuild of self)', () => {
|
||||||
projectGraph.nodes.app1.data.targets.prebuild = {};
|
projectGraph.nodes.app1.data.targets.prebuild = {};
|
||||||
projectGraph.nodes.app2.data.targets.prebuild = {};
|
projectGraph.nodes.app2.data.targets.prebuild = {};
|
||||||
|
|||||||
@ -22,8 +22,8 @@ export class TaskGraphCreator {
|
|||||||
dependencies: {},
|
dependencies: {},
|
||||||
};
|
};
|
||||||
for (const task of tasks) {
|
for (const task of tasks) {
|
||||||
graph.tasks[task.id] = task;
|
this.addTaskToGraph(task, graph);
|
||||||
graph.dependencies[task.id] = [];
|
|
||||||
const dependencyConfigs = getDependencyConfigs(
|
const dependencyConfigs = getDependencyConfigs(
|
||||||
task.target,
|
task.target,
|
||||||
this.defaultTargetDependencies,
|
this.defaultTargetDependencies,
|
||||||
@ -34,12 +34,22 @@ export class TaskGraphCreator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectDependencies = new Set(
|
this.addTaskDependencies(task, dependencyConfigs, tasks, graph);
|
||||||
this.projectGraph.dependencies[task.target.project].map(
|
}
|
||||||
(dependency) => dependency.target
|
|
||||||
)
|
graph.roots = Object.keys(graph.dependencies).filter(
|
||||||
|
(k) => graph.dependencies[k].length === 0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return graph;
|
||||||
|
}
|
||||||
|
|
||||||
|
private addTaskDependencies(
|
||||||
|
task: Task,
|
||||||
|
dependencyConfigs: TargetDependencyConfig[],
|
||||||
|
tasks: Task[],
|
||||||
|
graph: TaskGraph
|
||||||
|
) {
|
||||||
for (const dependencyConfig of dependencyConfigs) {
|
for (const dependencyConfig of dependencyConfigs) {
|
||||||
if (dependencyConfig.projects === 'self') {
|
if (dependencyConfig.projects === 'self') {
|
||||||
for (const t of tasks) {
|
for (const t of tasks) {
|
||||||
@ -51,22 +61,66 @@ export class TaskGraphCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (dependencyConfig.projects === 'dependencies') {
|
} else if (dependencyConfig.projects === 'dependencies') {
|
||||||
for (const t of tasks) {
|
const seen = new Set<string>();
|
||||||
if (
|
|
||||||
projectDependencies.has(t.target.project) &&
|
|
||||||
t.target.target === dependencyConfig.target
|
|
||||||
) {
|
|
||||||
graph.dependencies[task.id].push(t.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
graph.roots = Object.keys(graph.dependencies).filter(
|
this.addDependencies(
|
||||||
(k) => graph.dependencies[k].length === 0
|
task.target.project,
|
||||||
|
dependencyConfig.target,
|
||||||
|
tasks,
|
||||||
|
graph,
|
||||||
|
task.id,
|
||||||
|
seen
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return graph;
|
private addDependencies(
|
||||||
|
project: string,
|
||||||
|
target: string,
|
||||||
|
tasks: Task[],
|
||||||
|
graph: TaskGraph,
|
||||||
|
taskId: string,
|
||||||
|
seen: Set<string>
|
||||||
|
) {
|
||||||
|
seen.add(project);
|
||||||
|
const projectDependencies = this.projectGraph.dependencies[project].map(
|
||||||
|
(dependency) => dependency.target
|
||||||
|
);
|
||||||
|
for (const projectDependency of projectDependencies) {
|
||||||
|
if (seen.has(projectDependency)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const dependency = this.findTask(
|
||||||
|
{ project: projectDependency, target },
|
||||||
|
tasks
|
||||||
|
);
|
||||||
|
if (dependency) {
|
||||||
|
graph.dependencies[taskId].push(dependency.id);
|
||||||
|
} else {
|
||||||
|
this.addDependencies(
|
||||||
|
projectDependency,
|
||||||
|
target,
|
||||||
|
tasks,
|
||||||
|
graph,
|
||||||
|
taskId,
|
||||||
|
seen
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private findTask(
|
||||||
|
{ project, target }: { project: string; target: string },
|
||||||
|
tasks: Task[]
|
||||||
|
): Task {
|
||||||
|
return tasks.find(
|
||||||
|
(t) => t.target.project === project && t.target.target === target
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private addTaskToGraph(task: Task, graph: TaskGraph) {
|
||||||
|
graph.tasks[task.id] = task;
|
||||||
|
graph.dependencies[task.id] = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user