Skip to content

Commit

Permalink
feat(core): expose the task graph in the executor context (#17111)
Browse files Browse the repository at this point in the history
  • Loading branch information
leosvelperez committed May 24, 2023
1 parent 5ef9ea6 commit 8f6fcf2
Show file tree
Hide file tree
Showing 12 changed files with 178 additions and 120 deletions.
13 changes: 5 additions & 8 deletions docs/generated/devkit/nx_devkit.md
Expand Up @@ -2064,14 +2064,11 @@ Note that the return value is a promise of an iterator, so you need to await bef

#### Parameters

| Name | Type |
| :--------------------------------- | :-------------------------------------------------------------------- |
| `targetDescription` | `Object` |
| `targetDescription.configuration?` | `string` |
| `targetDescription.project` | `string` |
| `targetDescription.target` | `string` |
| `overrides` | `Object` |
| `context` | [`ExecutorContext`](../../devkit/documents/nx_devkit#executorcontext) |
| Name | Type |
| :------------------ | :-------------------------------------------------------------------- |
| `targetDescription` | [`Target`](../../devkit/documents/nx_devkit#target) |
| `overrides` | `Object` |
| `context` | [`ExecutorContext`](../../devkit/documents/nx_devkit#executorcontext) |

#### Returns

Expand Down
13 changes: 5 additions & 8 deletions docs/generated/packages/devkit/documents/nx_devkit.md
Expand Up @@ -2064,14 +2064,11 @@ Note that the return value is a promise of an iterator, so you need to await bef

#### Parameters

| Name | Type |
| :--------------------------------- | :-------------------------------------------------------------------- |
| `targetDescription` | `Object` |
| `targetDescription.configuration?` | `string` |
| `targetDescription.project` | `string` |
| `targetDescription.target` | `string` |
| `overrides` | `Object` |
| `context` | [`ExecutorContext`](../../devkit/documents/nx_devkit#executorcontext) |
| Name | Type |
| :------------------ | :-------------------------------------------------------------------- |
| `targetDescription` | [`Target`](../../devkit/documents/nx_devkit#target) |
| `overrides` | `Object` |
| `context` | [`ExecutorContext`](../../devkit/documents/nx_devkit#executorcontext) |

#### Returns

Expand Down
13 changes: 3 additions & 10 deletions packages/devkit/src/utils/convert-nx-executor.ts
@@ -1,10 +1,8 @@
import type { Observable } from 'rxjs';
import type { Executor, ExecutorContext } from 'nx/src/config/misc-interfaces';
import type { ProjectGraph } from 'nx/src/config/project-graph';
import { requireNx } from '../../nx';

const { createProjectGraphAsync, readCachedProjectGraph, Workspaces } =
requireNx();
const { Workspaces } = requireNx();

/**
* Convert an Nx Executor into an Angular Devkit Builder
Expand All @@ -21,12 +19,6 @@ export function convertNxExecutor(executor: Executor) {
});

const promise = async () => {
let projectGraph: ProjectGraph;
try {
projectGraph = readCachedProjectGraph();
} catch {
projectGraph = await createProjectGraphAsync();
}
const context: ExecutorContext = {
root: builderContext.workspaceRoot,
projectName: builderContext.target.project,
Expand All @@ -36,7 +28,8 @@ export function convertNxExecutor(executor: Executor) {
projectsConfigurations,
nxJsonConfiguration,
cwd: process.cwd(),
projectGraph,
projectGraph: null,
taskGraph: null,
isVerbose: false,
};
return executor(options, context);
Expand Down
54 changes: 28 additions & 26 deletions packages/nx/bin/run-executor.ts
@@ -1,5 +1,6 @@
import { appendFileSync, openSync, writeFileSync } from 'fs';
import { run } from '../src/command-line/run/run';
import { Target, run } from '../src/command-line/run/run';
import { TaskGraph } from '../src/config/task-graph';

if (process.env.NX_TERMINAL_OUTPUT_PATH) {
setUpOutputWatching(
Expand All @@ -12,32 +13,8 @@ if (!process.env.NX_WORKSPACE_ROOT) {
console.error('Invalid Nx command invocation');
process.exit(1);
}
requireCli();

function requireCli() {
process.env.NX_CLI_SET = 'true';
try {
const args = JSON.parse(process.argv[2]);
run(
process.cwd(),
process.env.NX_WORKSPACE_ROOT,
args.targetDescription,
args.overrides,
args.isVerbose,
false
)
.then((statusCode) => {
process.exit(statusCode);
})
.catch((e) => {
console.error(`Unexpected error`);
console.error(e);
});
} catch (e) {
console.error(`Could not find 'nx' module in this workspace.`, e);
process.exit(1);
}
}
process.env.NX_CLI_SET = 'true';

/**
* We need to collect all stdout and stderr and store it, so the caching mechanism
Expand Down Expand Up @@ -93,3 +70,28 @@ function setUpOutputWatching(captureStderr: boolean, streamOutput: boolean) {
}
});
}

process.on(
'message',
async (message: {
targetDescription: Target;
overrides: Record<string, any>;
taskGraph: TaskGraph;
isVerbose: boolean;
}) => {
try {
const statusCode = await run(
process.cwd(),
process.env.NX_WORKSPACE_ROOT,
message.targetDescription,
message.overrides,
message.isVerbose,
message.taskGraph
);
process.exit(statusCode);
} catch (e) {
console.error(`Could not find 'nx' module in this workspace.`, e);
process.exit(1);
}
}
);
4 changes: 1 addition & 3 deletions packages/nx/src/command-line/run/run-one.ts
Expand Up @@ -57,9 +57,7 @@ export async function runOne(
process.env.NX_VERBOSE_LOGGING = 'true';
}
if (nxArgs.help) {
await (
await import('./run')
).run(cwd, workspaceRoot, opts, {}, false, true);
await (await import('./run')).printTargetRunHelp(opts, workspaceRoot);
process.exit(0);
}

Expand Down
122 changes: 78 additions & 44 deletions packages/nx/src/command-line/run/run.ts
Expand Up @@ -20,6 +20,7 @@ import {
ProjectsConfigurations,
} from '../../config/workspace-json-project-json';
import { Executor, ExecutorContext } from '../../config/misc-interfaces';
import { TaskGraph } from '../../config/task-graph';
import { serializeOverridesIntoCommandLine } from '../../utils/serialize-overrides-into-command-line';
import {
readCachedProjectGraph,
Expand Down Expand Up @@ -123,28 +124,13 @@ function createImplicitTargetConfig(
return buildTargetFromScript(targetName, nx);
}

async function runExecutorInternal<T extends { success: boolean }>(
{
project,
target,
configuration,
}: {
project: string;
target: string;
configuration?: string;
},
overrides: { [k: string]: any },
async function parseExecutorAndTarget(
ws: Workspaces,
{ project, target, configuration }: Target,
root: string,
cwd: string,
projectsConfigurations: ProjectsConfigurations,
nxJsonConfiguration: NxJsonConfiguration,
projectGraph: ProjectGraph,
isVerbose: boolean,
printHelp: boolean
): Promise<AsyncIterableIterator<T>> {
validateProject(projectsConfigurations, project);

const ws = new Workspaces(root);
nxJsonConfiguration: NxJsonConfiguration
) {
const proj = projectsConfigurations.projects[project];
const targetConfig =
proj.targets?.[target] ||
Expand All @@ -159,21 +145,60 @@ async function runExecutorInternal<T extends { success: boolean }>(
throw new Error(`Cannot find target '${target}' for project '${project}'`);
}

configuration = configuration ?? targetConfig.defaultConfiguration;

const [nodeModule, executor] = targetConfig.executor.split(':');
const { schema, implementationFactory } = ws.readExecutor(
nodeModule,
executor
);

if (printHelp) {
printRunHelp({ project, target }, schema, {
plugin: nodeModule,
entity: executor,
});
process.exit(0);
}
return { executor, implementationFactory, nodeModule, schema, targetConfig };
}

async function printTargetRunHelpInternal(
{ project, target, configuration }: Target,
root: string,
projectsConfigurations: ProjectsConfigurations,
nxJsonConfiguration: NxJsonConfiguration
) {
const ws = new Workspaces(root);
const { executor, nodeModule, schema } = await parseExecutorAndTarget(
ws,
{ project, target, configuration },
root,
projectsConfigurations,
nxJsonConfiguration
);

printRunHelp({ project, target }, schema, {
plugin: nodeModule,
entity: executor,
});
process.exit(0);
}

async function runExecutorInternal<T extends { success: boolean }>(
{ project, target, configuration }: Target,
overrides: { [k: string]: any },
root: string,
cwd: string,
projectsConfigurations: ProjectsConfigurations,
nxJsonConfiguration: NxJsonConfiguration,
projectGraph: ProjectGraph,
taskGraph: TaskGraph,
isVerbose: boolean
): Promise<AsyncIterableIterator<T>> {
validateProject(projectsConfigurations, project);

const ws = new Workspaces(root);
const { executor, implementationFactory, nodeModule, schema, targetConfig } =
await parseExecutorAndTarget(
ws,
{ project, target, configuration },
root,
projectsConfigurations,
nxJsonConfiguration
);
configuration ??= targetConfig.defaultConfiguration;

const combinedOptions = combineOptionsForExecutor(
overrides,
Expand All @@ -197,6 +222,7 @@ async function runExecutorInternal<T extends { success: boolean }>(
targetName: target,
configurationName: configuration,
projectGraph,
taskGraph,
cwd,
isVerbose,
}) as Promise<T> | AsyncIterableIterator<T>;
Expand Down Expand Up @@ -254,11 +280,7 @@ async function runExecutorInternal<T extends { success: boolean }>(
* Note that the return value is a promise of an iterator, so you need to await before iterating over it.
*/
export async function runExecutor<T extends { success: boolean }>(
targetDescription: {
project: string;
target: string;
configuration?: string;
},
targetDescription: Target,
overrides: { [k: string]: any },
context: ExecutorContext
): Promise<AsyncIterableIterator<T>> {
Expand All @@ -273,22 +295,34 @@ export async function runExecutor<T extends { success: boolean }>(
context.projectsConfigurations,
context.nxJsonConfiguration,
context.projectGraph,
context.isVerbose,
false
context.taskGraph,
context.isVerbose
);
}

export function printTargetRunHelp(targetDescription: Target, root: string) {
const projectGraph = readCachedProjectGraph();
return handleErrors(false, async () => {
const projectsConfigurations =
readProjectsConfigurationFromProjectGraph(projectGraph);
const nxJsonConfiguration = readNxJson();

printTargetRunHelpInternal(
targetDescription,
root,
projectsConfigurations,
nxJsonConfiguration
);
});
}

export function run(
cwd: string,
root: string,
targetDescription: {
project: string;
target: string;
configuration?: string;
},
targetDescription: Target,
overrides: { [k: string]: any },
isVerbose: boolean,
isHelp: boolean
taskGraph: TaskGraph
) {
const projectGraph = readCachedProjectGraph();
return handleErrors(isVerbose, async () => {
Expand All @@ -303,8 +337,8 @@ export function run(
projectsConfigurations,
readNxJson(),
projectGraph,
isVerbose,
isHelp
taskGraph,
isVerbose
)
);
});
Expand Down
6 changes: 6 additions & 0 deletions packages/nx/src/config/misc-interfaces.ts
Expand Up @@ -210,6 +210,12 @@ export interface ExecutorContext {
*/
projectGraph?: ProjectGraph;

/**
* A snapshot of the task graph as
* it existed when the Nx command was kicked off
*/
taskGraph?: TaskGraph;

/**
* Deprecated. Use projectsConfigurations or nxJsonConfiguration
* The full workspace configuration
Expand Down
6 changes: 1 addition & 5 deletions packages/nx/src/executors/utils/convert-nx-executor.ts
Expand Up @@ -5,11 +5,6 @@
import type { Observable } from 'rxjs';
import { Workspaces } from '../../config/workspaces';
import { Executor, ExecutorContext } from '../../config/misc-interfaces';
import {
createProjectGraphAsync,
readCachedProjectGraph,
} from '../../project-graph/project-graph';
import { ProjectGraph } from '../../config/project-graph';

/**
* Convert an Nx Executor into an Angular Devkit Builder
Expand All @@ -34,6 +29,7 @@ export function convertNxExecutor(executor: Executor) {
nxJsonConfiguration,
cwd: process.cwd(),
projectGraph: null,
taskGraph: null,
isVerbose: false,
};
return executor(options, context);
Expand Down
3 changes: 2 additions & 1 deletion packages/nx/src/tasks-runner/batch/batch-messages.ts
Expand Up @@ -8,7 +8,8 @@ export enum BatchMessageType {
export interface BatchTasksMessage {
type: BatchMessageType.Tasks;
executorName: string;
taskGraph: TaskGraph;
batchTaskGraph: TaskGraph;
fullTaskGraph: TaskGraph;
}
/**
* Results of running the batch. Mapped from task id to results
Expand Down

1 comment on commit 8f6fcf2

@vercel
Copy link

@vercel vercel bot commented on 8f6fcf2 May 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-five.vercel.app
nx-dev-nrwl.vercel.app
nx.dev
nx-dev-git-master-nrwl.vercel.app

Please sign in to comment.