feat(core): add pre and post run apis (#29636)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> There is no specific API for running things before and after tasks run. ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> This PR adds an API akin to npm's `preinstall` and `postinstall`. Plugins can now specify `preTasksExecution` and `postTasksExecution` functions which run before and after Nx runs tasks respectively. ```ts import type { PreTasksExecutionContext, PostTasksExecutionContext } from '@nx/devkit'; interface PluginOptions { field: any; } export function preTasksExecution(options: PluginOptions, context: PreTasksExecutionContext) { console.log('prerun') } export function postTasksExecution(options: PluginOptions, context: PostTasksExecutionContext) { console.log('postrun', context.taskResults) } ``` ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
f02a88a72c
commit
4a9508b368
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
Ƭ **NxPlugin**: [`NxPluginV2`](../../devkit/documents/NxPluginV2)
|
Ƭ **NxPlugin**: [`NxPluginV2`](../../devkit/documents/NxPluginV2)
|
||||||
|
|
||||||
A plugin for Nx
|
A plugin which enhances the behavior of Nx
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Ƭ **NxPluginV2**\<`TOptions`\>: `Object`
|
Ƭ **NxPluginV2**\<`TOptions`\>: `Object`
|
||||||
|
|
||||||
A plugin for Nx which creates nodes and dependencies for the [ProjectGraph](../../devkit/documents/ProjectGraph)
|
A plugin which enhances the behavior of Nx
|
||||||
|
|
||||||
#### Type parameters
|
#### Type parameters
|
||||||
|
|
||||||
@ -19,3 +19,5 @@ A plugin for Nx which creates nodes and dependencies for the [ProjectGraph](../.
|
|||||||
| `createNodes?` | [`CreateNodes`](../../devkit/documents/CreateNodes)\<`TOptions`\> | Provides a file pattern and function that retrieves configuration info from those files. e.g. { '**/\*.csproj': buildProjectsFromCsProjFile } **`Deprecated`\*\* Use createNodesV2 instead. In Nx 21 support for calling createNodes with a single file for the first argument will be removed. |
|
| `createNodes?` | [`CreateNodes`](../../devkit/documents/CreateNodes)\<`TOptions`\> | Provides a file pattern and function that retrieves configuration info from those files. e.g. { '**/\*.csproj': buildProjectsFromCsProjFile } **`Deprecated`\*\* Use createNodesV2 instead. In Nx 21 support for calling createNodes with a single file for the first argument will be removed. |
|
||||||
| `createNodesV2?` | [`CreateNodesV2`](../../devkit/documents/CreateNodesV2)\<`TOptions`\> | Provides a file pattern and function that retrieves configuration info from those files. e.g. { '\*_/_.csproj': buildProjectsFromCsProjFiles } In Nx 21 createNodes will be replaced with this property. In Nx 22, this property will be removed. |
|
| `createNodesV2?` | [`CreateNodesV2`](../../devkit/documents/CreateNodesV2)\<`TOptions`\> | Provides a file pattern and function that retrieves configuration info from those files. e.g. { '\*_/_.csproj': buildProjectsFromCsProjFiles } In Nx 21 createNodes will be replaced with this property. In Nx 22, this property will be removed. |
|
||||||
| `name` | `string` | - |
|
| `name` | `string` | - |
|
||||||
|
| `postTasksExecution?` | [`PostTasksExecution`](../../devkit/documents/PostTasksExecution)\<`TOptions`\> | Provides a function to run after the Nx runs tasks |
|
||||||
|
| `preTasksExecution?` | [`PreTasksExecution`](../../devkit/documents/PreTasksExecution)\<`TOptions`\> | Provides a function to run before the Nx runs tasks |
|
||||||
|
|||||||
24
docs/generated/devkit/PostTasksExecution.md
Normal file
24
docs/generated/devkit/PostTasksExecution.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Type alias: PostTasksExecution\<TOptions\>
|
||||||
|
|
||||||
|
Ƭ **PostTasksExecution**\<`TOptions`\>: (`options`: `TOptions` \| `undefined`, `context`: [`PostTasksExecutionContext`](../../devkit/documents/PostTasksExecutionContext)) => `void` \| `Promise`\<`void`\>
|
||||||
|
|
||||||
|
#### Type parameters
|
||||||
|
|
||||||
|
| Name | Type |
|
||||||
|
| :--------- | :-------- |
|
||||||
|
| `TOptions` | `unknown` |
|
||||||
|
|
||||||
|
#### Type declaration
|
||||||
|
|
||||||
|
▸ (`options`, `context`): `void` \| `Promise`\<`void`\>
|
||||||
|
|
||||||
|
##### Parameters
|
||||||
|
|
||||||
|
| Name | Type |
|
||||||
|
| :-------- | :------------------------------------------------------------------------------ |
|
||||||
|
| `options` | `TOptions` \| `undefined` |
|
||||||
|
| `context` | [`PostTasksExecutionContext`](../../devkit/documents/PostTasksExecutionContext) |
|
||||||
|
|
||||||
|
##### Returns
|
||||||
|
|
||||||
|
`void` \| `Promise`\<`void`\>
|
||||||
11
docs/generated/devkit/PostTasksExecutionContext.md
Normal file
11
docs/generated/devkit/PostTasksExecutionContext.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Type alias: PostTasksExecutionContext
|
||||||
|
|
||||||
|
Ƭ **PostTasksExecutionContext**: `Object`
|
||||||
|
|
||||||
|
#### Type declaration
|
||||||
|
|
||||||
|
| Name | Type |
|
||||||
|
| :-------------------- | :------------------------------------------------------------------ |
|
||||||
|
| `nxJsonConfiguration` | [`NxJsonConfiguration`](../../devkit/documents/NxJsonConfiguration) |
|
||||||
|
| `taskResults` | [`TaskResults`](../../devkit/documents/TaskResults) |
|
||||||
|
| `workspaceRoot` | `string` |
|
||||||
24
docs/generated/devkit/PreTasksExecution.md
Normal file
24
docs/generated/devkit/PreTasksExecution.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Type alias: PreTasksExecution\<TOptions\>
|
||||||
|
|
||||||
|
Ƭ **PreTasksExecution**\<`TOptions`\>: (`options`: `TOptions` \| `undefined`, `context`: [`PreTasksExecutionContext`](../../devkit/documents/PreTasksExecutionContext)) => `void` \| `Promise`\<`void`\>
|
||||||
|
|
||||||
|
#### Type parameters
|
||||||
|
|
||||||
|
| Name | Type |
|
||||||
|
| :--------- | :-------- |
|
||||||
|
| `TOptions` | `unknown` |
|
||||||
|
|
||||||
|
#### Type declaration
|
||||||
|
|
||||||
|
▸ (`options`, `context`): `void` \| `Promise`\<`void`\>
|
||||||
|
|
||||||
|
##### Parameters
|
||||||
|
|
||||||
|
| Name | Type |
|
||||||
|
| :-------- | :---------------------------------------------------------------------------- |
|
||||||
|
| `options` | `TOptions` \| `undefined` |
|
||||||
|
| `context` | [`PreTasksExecutionContext`](../../devkit/documents/PreTasksExecutionContext) |
|
||||||
|
|
||||||
|
##### Returns
|
||||||
|
|
||||||
|
`void` \| `Promise`\<`void`\>
|
||||||
10
docs/generated/devkit/PreTasksExecutionContext.md
Normal file
10
docs/generated/devkit/PreTasksExecutionContext.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Type alias: PreTasksExecutionContext
|
||||||
|
|
||||||
|
Ƭ **PreTasksExecutionContext**: `Object`
|
||||||
|
|
||||||
|
#### Type declaration
|
||||||
|
|
||||||
|
| Name | Type |
|
||||||
|
| :-------------------- | :------------------------------------------------------------------ |
|
||||||
|
| `nxJsonConfiguration` | [`NxJsonConfiguration`](../../devkit/documents/NxJsonConfiguration) |
|
||||||
|
| `workspaceRoot` | `string` |
|
||||||
@ -59,6 +59,7 @@ It only uses language primitives and immutable objects
|
|||||||
- [Task](../../devkit/documents/Task)
|
- [Task](../../devkit/documents/Task)
|
||||||
- [TaskGraph](../../devkit/documents/TaskGraph)
|
- [TaskGraph](../../devkit/documents/TaskGraph)
|
||||||
- [TaskHasher](../../devkit/documents/TaskHasher)
|
- [TaskHasher](../../devkit/documents/TaskHasher)
|
||||||
|
- [TaskResult](../../devkit/documents/TaskResult)
|
||||||
- [Tree](../../devkit/documents/Tree)
|
- [Tree](../../devkit/documents/Tree)
|
||||||
- [Workspace](../../devkit/documents/Workspace)
|
- [Workspace](../../devkit/documents/Workspace)
|
||||||
|
|
||||||
@ -86,6 +87,10 @@ It only uses language primitives and immutable objects
|
|||||||
- [NxPluginV2](../../devkit/documents/NxPluginV2)
|
- [NxPluginV2](../../devkit/documents/NxPluginV2)
|
||||||
- [PackageManager](../../devkit/documents/PackageManager)
|
- [PackageManager](../../devkit/documents/PackageManager)
|
||||||
- [PluginConfiguration](../../devkit/documents/PluginConfiguration)
|
- [PluginConfiguration](../../devkit/documents/PluginConfiguration)
|
||||||
|
- [PostTasksExecution](../../devkit/documents/PostTasksExecution)
|
||||||
|
- [PostTasksExecutionContext](../../devkit/documents/PostTasksExecutionContext)
|
||||||
|
- [PreTasksExecution](../../devkit/documents/PreTasksExecution)
|
||||||
|
- [PreTasksExecutionContext](../../devkit/documents/PreTasksExecutionContext)
|
||||||
- [ProjectType](../../devkit/documents/ProjectType)
|
- [ProjectType](../../devkit/documents/ProjectType)
|
||||||
- [ProjectsMetadata](../../devkit/documents/ProjectsMetadata)
|
- [ProjectsMetadata](../../devkit/documents/ProjectsMetadata)
|
||||||
- [PromiseExecutor](../../devkit/documents/PromiseExecutor)
|
- [PromiseExecutor](../../devkit/documents/PromiseExecutor)
|
||||||
@ -94,6 +99,7 @@ It only uses language primitives and immutable objects
|
|||||||
- [StringChange](../../devkit/documents/StringChange)
|
- [StringChange](../../devkit/documents/StringChange)
|
||||||
- [TargetDefaults](../../devkit/documents/TargetDefaults)
|
- [TargetDefaults](../../devkit/documents/TargetDefaults)
|
||||||
- [TaskGraphExecutor](../../devkit/documents/TaskGraphExecutor)
|
- [TaskGraphExecutor](../../devkit/documents/TaskGraphExecutor)
|
||||||
|
- [TaskResults](../../devkit/documents/TaskResults)
|
||||||
- [ToJSOptions](../../devkit/documents/ToJSOptions)
|
- [ToJSOptions](../../devkit/documents/ToJSOptions)
|
||||||
- [WorkspaceJsonConfiguration](../../devkit/documents/WorkspaceJsonConfiguration)
|
- [WorkspaceJsonConfiguration](../../devkit/documents/WorkspaceJsonConfiguration)
|
||||||
|
|
||||||
|
|||||||
36
docs/generated/devkit/TaskResult.md
Normal file
36
docs/generated/devkit/TaskResult.md
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# Interface: TaskResult
|
||||||
|
|
||||||
|
The result of a completed [Task](../../devkit/documents/Task)
|
||||||
|
|
||||||
|
## Table of contents
|
||||||
|
|
||||||
|
### Properties
|
||||||
|
|
||||||
|
- [code](../../devkit/documents/TaskResult#code): number
|
||||||
|
- [status](../../devkit/documents/TaskResult#status): TaskStatus
|
||||||
|
- [task](../../devkit/documents/TaskResult#task): Task
|
||||||
|
- [terminalOutput](../../devkit/documents/TaskResult#terminaloutput): string
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### code
|
||||||
|
|
||||||
|
• **code**: `number`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### status
|
||||||
|
|
||||||
|
• **status**: `TaskStatus`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### task
|
||||||
|
|
||||||
|
• **task**: [`Task`](../../devkit/documents/Task)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### terminalOutput
|
||||||
|
|
||||||
|
• `Optional` **terminalOutput**: `string`
|
||||||
5
docs/generated/devkit/TaskResults.md
Normal file
5
docs/generated/devkit/TaskResults.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Type alias: TaskResults
|
||||||
|
|
||||||
|
Ƭ **TaskResults**: `Record`\<`string`, [`TaskResult`](../../devkit/documents/TaskResult)\>
|
||||||
|
|
||||||
|
A map of [TaskResult](../../devkit/documents/TaskResult) keyed by the ID of the completed [Task](../../devkit/documents/Task)s
|
||||||
@ -59,6 +59,7 @@ It only uses language primitives and immutable objects
|
|||||||
- [Task](../../devkit/documents/Task)
|
- [Task](../../devkit/documents/Task)
|
||||||
- [TaskGraph](../../devkit/documents/TaskGraph)
|
- [TaskGraph](../../devkit/documents/TaskGraph)
|
||||||
- [TaskHasher](../../devkit/documents/TaskHasher)
|
- [TaskHasher](../../devkit/documents/TaskHasher)
|
||||||
|
- [TaskResult](../../devkit/documents/TaskResult)
|
||||||
- [Tree](../../devkit/documents/Tree)
|
- [Tree](../../devkit/documents/Tree)
|
||||||
- [Workspace](../../devkit/documents/Workspace)
|
- [Workspace](../../devkit/documents/Workspace)
|
||||||
|
|
||||||
@ -86,6 +87,10 @@ It only uses language primitives and immutable objects
|
|||||||
- [NxPluginV2](../../devkit/documents/NxPluginV2)
|
- [NxPluginV2](../../devkit/documents/NxPluginV2)
|
||||||
- [PackageManager](../../devkit/documents/PackageManager)
|
- [PackageManager](../../devkit/documents/PackageManager)
|
||||||
- [PluginConfiguration](../../devkit/documents/PluginConfiguration)
|
- [PluginConfiguration](../../devkit/documents/PluginConfiguration)
|
||||||
|
- [PostTasksExecution](../../devkit/documents/PostTasksExecution)
|
||||||
|
- [PostTasksExecutionContext](../../devkit/documents/PostTasksExecutionContext)
|
||||||
|
- [PreTasksExecution](../../devkit/documents/PreTasksExecution)
|
||||||
|
- [PreTasksExecutionContext](../../devkit/documents/PreTasksExecutionContext)
|
||||||
- [ProjectType](../../devkit/documents/ProjectType)
|
- [ProjectType](../../devkit/documents/ProjectType)
|
||||||
- [ProjectsMetadata](../../devkit/documents/ProjectsMetadata)
|
- [ProjectsMetadata](../../devkit/documents/ProjectsMetadata)
|
||||||
- [PromiseExecutor](../../devkit/documents/PromiseExecutor)
|
- [PromiseExecutor](../../devkit/documents/PromiseExecutor)
|
||||||
@ -94,6 +99,7 @@ It only uses language primitives and immutable objects
|
|||||||
- [StringChange](../../devkit/documents/StringChange)
|
- [StringChange](../../devkit/documents/StringChange)
|
||||||
- [TargetDefaults](../../devkit/documents/TargetDefaults)
|
- [TargetDefaults](../../devkit/documents/TargetDefaults)
|
||||||
- [TaskGraphExecutor](../../devkit/documents/TaskGraphExecutor)
|
- [TaskGraphExecutor](../../devkit/documents/TaskGraphExecutor)
|
||||||
|
- [TaskResults](../../devkit/documents/TaskResults)
|
||||||
- [ToJSOptions](../../devkit/documents/ToJSOptions)
|
- [ToJSOptions](../../devkit/documents/ToJSOptions)
|
||||||
- [WorkspaceJsonConfiguration](../../devkit/documents/WorkspaceJsonConfiguration)
|
- [WorkspaceJsonConfiguration](../../devkit/documents/WorkspaceJsonConfiguration)
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import {
|
|||||||
describe('Jest', () => {
|
describe('Jest', () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
newProject({ name: uniq('proj-jest'), packages: ['@nx/js', '@nx/node'] });
|
newProject({ name: uniq('proj-jest'), packages: ['@nx/js', '@nx/node'] });
|
||||||
|
process.env.NX_E2E_VERBOSE_LOGGING = 'true';
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => cleanupProject());
|
afterAll(() => cleanupProject());
|
||||||
|
|||||||
@ -29,7 +29,7 @@ describe('Convert Nx Executor', () => {
|
|||||||
|
|
||||||
const registry = new schema.CoreSchemaRegistry();
|
const registry = new schema.CoreSchemaRegistry();
|
||||||
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
|
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
|
||||||
const testArchitectHost = new TestingArchitectHost();
|
const testArchitectHost = new TestingArchitectHost(fs.tempDir, fs.tempDir);
|
||||||
testArchitectHost.workspaceRoot = fs.tempDir;
|
testArchitectHost.workspaceRoot = fs.tempDir;
|
||||||
const architect = new Architect(testArchitectHost, registry);
|
const architect = new Architect(testArchitectHost, registry);
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,11 @@ import {
|
|||||||
import { deepMergeJson } from './config/deep-merge-json';
|
import { deepMergeJson } from './config/deep-merge-json';
|
||||||
import { filterReleaseGroups } from './config/filter-release-groups';
|
import { filterReleaseGroups } from './config/filter-release-groups';
|
||||||
import { printConfigAndExit } from './utils/print-config';
|
import { printConfigAndExit } from './utils/print-config';
|
||||||
|
import { workspaceRoot } from '../../utils/workspace-root';
|
||||||
|
import {
|
||||||
|
runPostTasksExecution,
|
||||||
|
runPreTasksExecution,
|
||||||
|
} from '../../project-graph/plugins/tasks-execution-hooks';
|
||||||
|
|
||||||
export interface PublishProjectsResult {
|
export interface PublishProjectsResult {
|
||||||
[projectName: string]: {
|
[projectName: string]: {
|
||||||
@ -249,6 +254,10 @@ async function runPublishOnProjects(
|
|||||||
].join('\n')}\n`
|
].join('\n')}\n`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
await runPreTasksExecution({
|
||||||
|
workspaceRoot,
|
||||||
|
nxJsonConfiguration: nxJson,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the relevant nx-release-publish executor on each of the selected projects.
|
* Run the relevant nx-release-publish executor on each of the selected projects.
|
||||||
@ -276,6 +285,11 @@ async function runPublishOnProjects(
|
|||||||
code: taskData.code,
|
code: taskData.code,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
await runPostTasksExecution({
|
||||||
|
taskResults: commandResults,
|
||||||
|
workspaceRoot,
|
||||||
|
nxJsonConfiguration: nxJson,
|
||||||
|
});
|
||||||
|
|
||||||
return publishProjectsResult;
|
return publishProjectsResult;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,6 +78,16 @@ import {
|
|||||||
type HandleFlushSyncGeneratorChangesToDiskMessage,
|
type HandleFlushSyncGeneratorChangesToDiskMessage,
|
||||||
} from '../message-types/flush-sync-generator-changes-to-disk';
|
} from '../message-types/flush-sync-generator-changes-to-disk';
|
||||||
import { DelayedSpinner } from '../../utils/delayed-spinner';
|
import { DelayedSpinner } from '../../utils/delayed-spinner';
|
||||||
|
import {
|
||||||
|
PostTasksExecutionContext,
|
||||||
|
PreTasksExecutionContext,
|
||||||
|
} from '../../project-graph/plugins/public-api';
|
||||||
|
import {
|
||||||
|
HandlePostTasksExecutionMessage,
|
||||||
|
HandlePreTasksExecutionMessage,
|
||||||
|
POST_TASKS_EXECUTION,
|
||||||
|
PRE_TASKS_EXECUTION,
|
||||||
|
} from '../message-types/run-tasks-execution-hooks';
|
||||||
|
|
||||||
const DAEMON_ENV_SETTINGS = {
|
const DAEMON_ENV_SETTINGS = {
|
||||||
NX_PROJECT_GLOB_CACHE: 'false',
|
NX_PROJECT_GLOB_CACHE: 'false',
|
||||||
@ -435,6 +445,26 @@ export class DaemonClient {
|
|||||||
return this.sendToDaemonViaQueue(message);
|
return this.sendToDaemonViaQueue(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async runPreTasksExecution(
|
||||||
|
context: PreTasksExecutionContext
|
||||||
|
): Promise<NodeJS.ProcessEnv[]> {
|
||||||
|
const message: HandlePreTasksExecutionMessage = {
|
||||||
|
type: PRE_TASKS_EXECUTION,
|
||||||
|
context,
|
||||||
|
};
|
||||||
|
return this.sendToDaemonViaQueue(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
async runPostTasksExecution(
|
||||||
|
context: PostTasksExecutionContext
|
||||||
|
): Promise<void> {
|
||||||
|
const message: HandlePostTasksExecutionMessage = {
|
||||||
|
type: POST_TASKS_EXECUTION,
|
||||||
|
context,
|
||||||
|
};
|
||||||
|
return this.sendToDaemonViaQueue(message);
|
||||||
|
}
|
||||||
|
|
||||||
async isServerAvailable(): Promise<boolean> {
|
async isServerAvailable(): Promise<boolean> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
import type {
|
||||||
|
PostTasksExecutionContext,
|
||||||
|
PreTasksExecutionContext,
|
||||||
|
} from '../../project-graph/plugins';
|
||||||
|
|
||||||
|
export const PRE_TASKS_EXECUTION = 'PRE_TASKS_EXECUTION' as const;
|
||||||
|
export const POST_TASKS_EXECUTION = 'POST_TASKS_EXECUTION' as const;
|
||||||
|
|
||||||
|
export type HandlePreTasksExecutionMessage = {
|
||||||
|
type: typeof PRE_TASKS_EXECUTION;
|
||||||
|
context: PreTasksExecutionContext;
|
||||||
|
};
|
||||||
|
export type HandlePostTasksExecutionMessage = {
|
||||||
|
type: typeof POST_TASKS_EXECUTION;
|
||||||
|
context: PostTasksExecutionContext;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function isHandlePreTasksExecutionMessage(
|
||||||
|
message: unknown
|
||||||
|
): message is HandlePreTasksExecutionMessage {
|
||||||
|
return (
|
||||||
|
typeof message === 'object' &&
|
||||||
|
message !== null &&
|
||||||
|
'type' in message &&
|
||||||
|
message['type'] === PRE_TASKS_EXECUTION
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isHandlePostTasksExecutionMessage(
|
||||||
|
message: unknown
|
||||||
|
): message is HandlePostTasksExecutionMessage {
|
||||||
|
return (
|
||||||
|
typeof message === 'object' &&
|
||||||
|
message !== null &&
|
||||||
|
'type' in message &&
|
||||||
|
message['type'] === POST_TASKS_EXECUTION
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
import type {
|
||||||
|
PostTasksExecutionContext,
|
||||||
|
PreTasksExecutionContext,
|
||||||
|
} from '../../project-graph/plugins/public-api';
|
||||||
|
import {
|
||||||
|
runPostTasksExecution,
|
||||||
|
runPreTasksExecution,
|
||||||
|
} from '../../project-graph/plugins/tasks-execution-hooks';
|
||||||
|
|
||||||
|
export async function handleRunPreTasksExecution(
|
||||||
|
context: PreTasksExecutionContext
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const envs = await runPreTasksExecution(context);
|
||||||
|
return {
|
||||||
|
response: JSON.stringify(envs),
|
||||||
|
description: 'handleRunPreTasksExecution',
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
error: e,
|
||||||
|
description: `Error when running preTasksExecution.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export async function handleRunPostTasksExecution(
|
||||||
|
context: PostTasksExecutionContext
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
await runPostTasksExecution(context);
|
||||||
|
return {
|
||||||
|
response: 'true',
|
||||||
|
description: 'handleRunPostTasksExecution',
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
error: e,
|
||||||
|
description: `Error when running postTasksExecution.`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -110,6 +110,16 @@ import {
|
|||||||
isHandleFlushSyncGeneratorChangesToDiskMessage,
|
isHandleFlushSyncGeneratorChangesToDiskMessage,
|
||||||
} from '../message-types/flush-sync-generator-changes-to-disk';
|
} from '../message-types/flush-sync-generator-changes-to-disk';
|
||||||
import { handleFlushSyncGeneratorChangesToDisk } from './handle-flush-sync-generator-changes-to-disk';
|
import { handleFlushSyncGeneratorChangesToDisk } from './handle-flush-sync-generator-changes-to-disk';
|
||||||
|
import {
|
||||||
|
isHandlePostTasksExecutionMessage,
|
||||||
|
isHandlePreTasksExecutionMessage,
|
||||||
|
POST_TASKS_EXECUTION,
|
||||||
|
PRE_TASKS_EXECUTION,
|
||||||
|
} from '../message-types/run-tasks-execution-hooks';
|
||||||
|
import {
|
||||||
|
handleRunPostTasksExecution,
|
||||||
|
handleRunPreTasksExecution,
|
||||||
|
} from './handle-tasks-execution-hooks';
|
||||||
|
|
||||||
let performanceObserver: PerformanceObserver | undefined;
|
let performanceObserver: PerformanceObserver | undefined;
|
||||||
let workspaceWatcherError: Error | undefined;
|
let workspaceWatcherError: Error | undefined;
|
||||||
@ -281,6 +291,14 @@ async function handleMessage(socket, data: string) {
|
|||||||
payload.deletedFiles
|
payload.deletedFiles
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} else if (isHandlePreTasksExecutionMessage(payload)) {
|
||||||
|
await handleResult(socket, PRE_TASKS_EXECUTION, () =>
|
||||||
|
handleRunPreTasksExecution(payload.context)
|
||||||
|
);
|
||||||
|
} else if (isHandlePostTasksExecutionMessage(payload)) {
|
||||||
|
await handleResult(socket, POST_TASKS_EXECUTION, () =>
|
||||||
|
handleRunPostTasksExecution(payload.context)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
await respondWithErrorAndExit(
|
await respondWithErrorAndExit(
|
||||||
socket,
|
socket,
|
||||||
|
|||||||
@ -57,6 +57,10 @@ export type {
|
|||||||
CreateMetadata,
|
CreateMetadata,
|
||||||
CreateMetadataContext,
|
CreateMetadataContext,
|
||||||
ProjectsMetadata,
|
ProjectsMetadata,
|
||||||
|
PreTasksExecution,
|
||||||
|
PreTasksExecutionContext,
|
||||||
|
PostTasksExecution,
|
||||||
|
PostTasksExecutionContext,
|
||||||
} from './project-graph/plugins';
|
} from './project-graph/plugins';
|
||||||
|
|
||||||
export { AggregateCreateNodesError } from './project-graph/error-types';
|
export { AggregateCreateNodesError } from './project-graph/error-types';
|
||||||
@ -64,10 +68,15 @@ export { AggregateCreateNodesError } from './project-graph/error-types';
|
|||||||
export { createNodesFromFiles } from './project-graph/plugins';
|
export { createNodesFromFiles } from './project-graph/plugins';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @category Workspace
|
* @category Tasks
|
||||||
*/
|
*/
|
||||||
export type { Task, TaskGraph } from './config/task-graph';
|
export type { Task, TaskGraph } from './config/task-graph';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @category Tasks
|
||||||
|
*/
|
||||||
|
export type { TaskResult, TaskResults } from './tasks-runner/life-cycle';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @category Workspace
|
* @category Workspace
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import {
|
|||||||
cleanupPluginTSTranspiler,
|
cleanupPluginTSTranspiler,
|
||||||
pluginTranspilerIsRegistered,
|
pluginTranspilerIsRegistered,
|
||||||
} from './transpiler';
|
} from './transpiler';
|
||||||
|
import { isIsolationEnabled } from './isolation/enabled';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stuff for specified NX Plugins.
|
* Stuff for specified NX Plugins.
|
||||||
@ -97,23 +98,6 @@ export function cleanupPlugins() {
|
|||||||
* Stuff for generic loading
|
* Stuff for generic loading
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function isIsolationEnabled() {
|
|
||||||
// Explicitly enabled, regardless of further conditions
|
|
||||||
if (process.env.NX_ISOLATE_PLUGINS === 'true') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
// Explicitly disabled
|
|
||||||
process.env.NX_ISOLATE_PLUGINS === 'false' ||
|
|
||||||
// Isolation is disabled on WASM builds currently.
|
|
||||||
IS_WASM
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Default value
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const loadingMethod = isIsolationEnabled()
|
const loadingMethod = isIsolationEnabled()
|
||||||
? loadNxPluginInIsolation
|
? loadNxPluginInIsolation
|
||||||
: loadNxPlugin;
|
: loadNxPlugin;
|
||||||
|
|||||||
18
packages/nx/src/project-graph/plugins/isolation/enabled.ts
Normal file
18
packages/nx/src/project-graph/plugins/isolation/enabled.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { IS_WASM } from '../../../native';
|
||||||
|
|
||||||
|
export function isIsolationEnabled() {
|
||||||
|
// Explicitly enabled, regardless of further conditions
|
||||||
|
if (process.env.NX_ISOLATE_PLUGINS === 'true') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
// Explicitly disabled
|
||||||
|
process.env.NX_ISOLATE_PLUGINS === 'false' ||
|
||||||
|
// Isolation is disabled on WASM builds currently.
|
||||||
|
IS_WASM
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Default value
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@ -1,13 +1,15 @@
|
|||||||
import { ProjectGraph } from '../../../config/project-graph';
|
import type { ProjectGraph } from '../../../config/project-graph';
|
||||||
import { PluginConfiguration } from '../../../config/nx-json';
|
import type { PluginConfiguration } from '../../../config/nx-json';
|
||||||
import {
|
import type {
|
||||||
CreateDependenciesContext,
|
CreateDependenciesContext,
|
||||||
CreateMetadataContext,
|
CreateMetadataContext,
|
||||||
CreateNodesContextV2,
|
CreateNodesContextV2,
|
||||||
|
PreTasksExecutionContext,
|
||||||
|
PostTasksExecutionContext,
|
||||||
} from '../public-api';
|
} from '../public-api';
|
||||||
import type { LoadedNxPlugin } from '../loaded-nx-plugin';
|
import type { LoadedNxPlugin } from '../loaded-nx-plugin';
|
||||||
import { Serializable } from 'child_process';
|
import type { Serializable } from 'child_process';
|
||||||
import { Socket } from 'net';
|
import type { Socket } from 'net';
|
||||||
|
|
||||||
export interface PluginWorkerLoadMessage {
|
export interface PluginWorkerLoadMessage {
|
||||||
type: 'load';
|
type: 'load';
|
||||||
@ -31,6 +33,8 @@ export interface PluginWorkerLoadResult {
|
|||||||
hasCreateDependencies: boolean;
|
hasCreateDependencies: boolean;
|
||||||
hasProcessProjectGraph: boolean;
|
hasProcessProjectGraph: boolean;
|
||||||
hasCreateMetadata: boolean;
|
hasCreateMetadata: boolean;
|
||||||
|
hasPreTasksExecution: boolean;
|
||||||
|
hasPostTasksExecution: boolean;
|
||||||
success: true;
|
success: true;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
@ -110,17 +114,66 @@ export interface PluginCreateMetadataResult {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PluginWorkerPreTasksExecutionMessage {
|
||||||
|
type: 'preTasksExecution';
|
||||||
|
payload: {
|
||||||
|
tx: string;
|
||||||
|
context: PreTasksExecutionContext;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PluginWorkerPreTasksExecutionMessageResult {
|
||||||
|
type: 'preTasksExecutionResult';
|
||||||
|
payload:
|
||||||
|
| {
|
||||||
|
tx: string;
|
||||||
|
success: true;
|
||||||
|
mutations: NodeJS.ProcessEnv;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
success: false;
|
||||||
|
error: Error;
|
||||||
|
tx: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PluginWorkerPostTasksExecutionMessage {
|
||||||
|
type: 'postTasksExecution';
|
||||||
|
payload: {
|
||||||
|
tx: string;
|
||||||
|
context: PostTasksExecutionContext;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PluginWorkerPostTasksExecutionMessageResult {
|
||||||
|
type: 'postTasksExecutionResult';
|
||||||
|
payload:
|
||||||
|
| {
|
||||||
|
tx: string;
|
||||||
|
success: true;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
success: false;
|
||||||
|
error: Error;
|
||||||
|
tx: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export type PluginWorkerMessage =
|
export type PluginWorkerMessage =
|
||||||
| PluginWorkerLoadMessage
|
| PluginWorkerLoadMessage
|
||||||
| PluginWorkerCreateNodesMessage
|
| PluginWorkerCreateNodesMessage
|
||||||
| PluginCreateDependenciesMessage
|
| PluginCreateDependenciesMessage
|
||||||
| PluginCreateMetadataMessage;
|
| PluginCreateMetadataMessage
|
||||||
|
| PluginWorkerPreTasksExecutionMessage
|
||||||
|
| PluginWorkerPostTasksExecutionMessage;
|
||||||
|
|
||||||
export type PluginWorkerResult =
|
export type PluginWorkerResult =
|
||||||
| PluginWorkerLoadResult
|
| PluginWorkerLoadResult
|
||||||
| PluginWorkerCreateNodesResult
|
| PluginWorkerCreateNodesResult
|
||||||
| PluginCreateDependenciesResult
|
| PluginCreateDependenciesResult
|
||||||
| PluginCreateMetadataResult;
|
| PluginCreateMetadataResult
|
||||||
|
| PluginWorkerPreTasksExecutionMessageResult
|
||||||
|
| PluginWorkerPostTasksExecutionMessageResult;
|
||||||
|
|
||||||
export function isPluginWorkerMessage(
|
export function isPluginWorkerMessage(
|
||||||
message: Serializable
|
message: Serializable
|
||||||
@ -133,9 +186,11 @@ export function isPluginWorkerMessage(
|
|||||||
'load',
|
'load',
|
||||||
'createNodes',
|
'createNodes',
|
||||||
'createDependencies',
|
'createDependencies',
|
||||||
'processProjectGraph',
|
|
||||||
'createMetadata',
|
'createMetadata',
|
||||||
|
'processProjectGraph',
|
||||||
'shutdown',
|
'shutdown',
|
||||||
|
'preTasksExecution',
|
||||||
|
'postTasksExecution',
|
||||||
].includes(message.type)
|
].includes(message.type)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -153,6 +208,8 @@ export function isPluginWorkerResult(
|
|||||||
'createDependenciesResult',
|
'createDependenciesResult',
|
||||||
'processProjectGraphResult',
|
'processProjectGraphResult',
|
||||||
'createMetadataResult',
|
'createMetadataResult',
|
||||||
|
'preTasksExecutionResult',
|
||||||
|
'postTasksExecutionResult',
|
||||||
].includes(message.type)
|
].includes(message.type)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ const MAX_MESSAGE_WAIT =
|
|||||||
|
|
||||||
interface PendingPromise {
|
interface PendingPromise {
|
||||||
promise: Promise<unknown>;
|
promise: Promise<unknown>;
|
||||||
resolver: (result: any) => void;
|
resolver: (result?: any) => void;
|
||||||
rejector: (err: any) => void;
|
rejector: (err: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,6 +217,46 @@ function createWorkerHandler(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
|
preTasksExecution: result.hasPreTasksExecution
|
||||||
|
? (context) => {
|
||||||
|
const tx =
|
||||||
|
pluginName + worker.pid + ':preTasksExecution:' + txId++;
|
||||||
|
return registerPendingPromise(
|
||||||
|
tx,
|
||||||
|
pending,
|
||||||
|
() => {
|
||||||
|
sendMessageOverSocket(socket, {
|
||||||
|
type: 'preTasksExecution',
|
||||||
|
payload: { tx, context },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plugin: pluginName,
|
||||||
|
operation: 'preTasksExecution',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
postTasksExecution: result.hasPostTasksExecution
|
||||||
|
? (context) => {
|
||||||
|
const tx =
|
||||||
|
pluginName + worker.pid + ':postTasksExecution:' + txId++;
|
||||||
|
return registerPendingPromise(
|
||||||
|
tx,
|
||||||
|
pending,
|
||||||
|
() => {
|
||||||
|
sendMessageOverSocket(socket, {
|
||||||
|
type: 'postTasksExecution',
|
||||||
|
payload: { tx, context },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plugin: pluginName,
|
||||||
|
operation: 'postTasksExecution',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
});
|
});
|
||||||
} else if (result.success === false) {
|
} else if (result.success === false) {
|
||||||
onloadError(result.error);
|
onloadError(result.error);
|
||||||
@ -246,6 +286,22 @@ function createWorkerHandler(
|
|||||||
rejector(result.error);
|
rejector(result.error);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
preTasksExecutionResult: ({ tx, ...result }) => {
|
||||||
|
const { resolver, rejector } = pending.get(tx);
|
||||||
|
if (result.success) {
|
||||||
|
resolver(result.mutations);
|
||||||
|
} else if (result.success === false) {
|
||||||
|
rejector(result.error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
postTasksExecutionResult: ({ tx, ...result }) => {
|
||||||
|
const { resolver, rejector } = pending.get(tx);
|
||||||
|
if (result.success) {
|
||||||
|
resolver();
|
||||||
|
} else if (result.success === false) {
|
||||||
|
rejector(result.error);
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { consumeMessage, isPluginWorkerMessage } from './messaging';
|
import { consumeMessage, isPluginWorkerMessage } from './messaging';
|
||||||
import { createSerializableError } from '../../../utils/serializable-error';
|
import { createSerializableError } from '../../../utils/serializable-error';
|
||||||
import { consumeMessagesFromSocket } from '../../../utils/consume-messages-from-socket';
|
import { consumeMessagesFromSocket } from '../../../utils/consume-messages-from-socket';
|
||||||
|
import type { LoadedNxPlugin } from '../loaded-nx-plugin';
|
||||||
|
|
||||||
import { createServer } from 'net';
|
import { createServer } from 'net';
|
||||||
import { unlinkSync } from 'fs';
|
import { unlinkSync } from 'fs';
|
||||||
@ -12,7 +13,7 @@ if (process.env.NX_PERF_LOGGING === 'true') {
|
|||||||
global.NX_GRAPH_CREATION = true;
|
global.NX_GRAPH_CREATION = true;
|
||||||
global.NX_PLUGIN_WORKER = true;
|
global.NX_PLUGIN_WORKER = true;
|
||||||
let connected = false;
|
let connected = false;
|
||||||
let plugin;
|
let plugin: LoadedNxPlugin;
|
||||||
|
|
||||||
const socketPath = process.argv[2];
|
const socketPath = process.argv[2];
|
||||||
|
|
||||||
@ -75,6 +76,10 @@ const server = createServer((socket) => {
|
|||||||
!!plugin.processProjectGraph,
|
!!plugin.processProjectGraph,
|
||||||
hasCreateMetadata:
|
hasCreateMetadata:
|
||||||
'createMetadata' in plugin && !!plugin.createMetadata,
|
'createMetadata' in plugin && !!plugin.createMetadata,
|
||||||
|
hasPreTasksExecution:
|
||||||
|
'preTasksExecution' in plugin && !!plugin.preTasksExecution,
|
||||||
|
hasPostTasksExecution:
|
||||||
|
'postTasksExecution' in plugin && !!plugin.postTasksExecution,
|
||||||
success: true,
|
success: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -142,6 +147,42 @@ const server = createServer((socket) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
preTasksExecution: async ({ tx, context }) => {
|
||||||
|
try {
|
||||||
|
const mutations = await plugin.preTasksExecution?.(context);
|
||||||
|
return {
|
||||||
|
type: 'preTasksExecutionResult',
|
||||||
|
payload: { success: true, tx, mutations },
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
type: 'preTasksExecutionResult',
|
||||||
|
payload: {
|
||||||
|
success: false,
|
||||||
|
error: createSerializableError(e),
|
||||||
|
tx,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
postTasksExecution: async ({ tx, context }) => {
|
||||||
|
try {
|
||||||
|
await plugin.postTasksExecution?.(context);
|
||||||
|
return {
|
||||||
|
type: 'postTasksExecutionResult',
|
||||||
|
payload: { success: true, tx },
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
return {
|
||||||
|
type: 'postTasksExecutionResult',
|
||||||
|
payload: {
|
||||||
|
success: false,
|
||||||
|
error: createSerializableError(e),
|
||||||
|
tx,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@ -18,7 +18,10 @@ async function importPluginModule(pluginPath: string): Promise<NxPlugin> {
|
|||||||
m.default &&
|
m.default &&
|
||||||
('createNodes' in m.default ||
|
('createNodes' in m.default ||
|
||||||
'createNodesV2' in m.default ||
|
'createNodesV2' in m.default ||
|
||||||
'createDependencies' in m.default)
|
'createDependencies' in m.default ||
|
||||||
|
'createMetadata' in m.default ||
|
||||||
|
'preTasksExecution' in m.default ||
|
||||||
|
'postTasksExecution' in m.default)
|
||||||
) {
|
) {
|
||||||
return m.default;
|
return m.default;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,9 +11,13 @@ import type {
|
|||||||
CreateNodesContextV2,
|
CreateNodesContextV2,
|
||||||
CreateNodesResult,
|
CreateNodesResult,
|
||||||
NxPluginV2,
|
NxPluginV2,
|
||||||
|
PostTasksExecutionContext,
|
||||||
|
PreTasksExecutionContext,
|
||||||
ProjectsMetadata,
|
ProjectsMetadata,
|
||||||
} from './public-api';
|
} from './public-api';
|
||||||
import { createNodesFromFiles } from './utils';
|
import { createNodesFromFiles } from './utils';
|
||||||
|
import { isIsolationEnabled } from './isolation/enabled';
|
||||||
|
import { isDaemonEnabled } from '../../daemon/client/client';
|
||||||
|
|
||||||
export class LoadedNxPlugin {
|
export class LoadedNxPlugin {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
@ -35,6 +39,12 @@ export class LoadedNxPlugin {
|
|||||||
graph: ProjectGraph,
|
graph: ProjectGraph,
|
||||||
context: CreateMetadataContext
|
context: CreateMetadataContext
|
||||||
) => Promise<ProjectsMetadata>;
|
) => Promise<ProjectsMetadata>;
|
||||||
|
readonly preTasksExecution?: (
|
||||||
|
context: PreTasksExecutionContext
|
||||||
|
) => Promise<NodeJS.ProcessEnv>;
|
||||||
|
readonly postTasksExecution?: (
|
||||||
|
context: PostTasksExecutionContext
|
||||||
|
) => Promise<void>;
|
||||||
|
|
||||||
readonly options?: unknown;
|
readonly options?: unknown;
|
||||||
readonly include?: string[];
|
readonly include?: string[];
|
||||||
@ -107,10 +117,37 @@ export class LoadedNxPlugin {
|
|||||||
this.createMetadata = async (graph, context) =>
|
this.createMetadata = async (graph, context) =>
|
||||||
plugin.createMetadata(graph, this.options, context);
|
plugin.createMetadata(graph, this.options, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (plugin.preTasksExecution) {
|
||||||
|
this.preTasksExecution = async (context: PreTasksExecutionContext) => {
|
||||||
|
const updates = {};
|
||||||
|
let revokeFn: () => void;
|
||||||
|
if (isIsolationEnabled() || isDaemonEnabled()) {
|
||||||
|
const { proxy, revoke } = Proxy.revocable<NodeJS.ProcessEnv>(
|
||||||
|
process.env,
|
||||||
|
{
|
||||||
|
set: (target, key: string, value) => {
|
||||||
|
target[key] = value;
|
||||||
|
updates[key] = value;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
process.env = proxy;
|
||||||
|
revokeFn = revoke;
|
||||||
|
}
|
||||||
|
await plugin.preTasksExecution(this.options, context);
|
||||||
|
|
||||||
|
if (revokeFn) {
|
||||||
|
revokeFn();
|
||||||
|
}
|
||||||
|
return updates;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (plugin.postTasksExecution) {
|
||||||
|
this.postTasksExecution = async (context: PostTasksExecutionContext) =>
|
||||||
|
plugin.postTasksExecution(this.options, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CreateNodesResultWithContext = CreateNodesResult & {
|
|
||||||
file: string;
|
|
||||||
pluginName: string;
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
// This file represents the public API for plugins which live in nx.json's plugins array.
|
// This file represents the public API for plugins which live in nx.json's plugins array.
|
||||||
// For methods to interact with plugins from within Nx, see `./internal-api.ts`.
|
// For methods to interact with plugins from within Nx, see `./internal-api.ts`.
|
||||||
|
|
||||||
import {
|
import type {
|
||||||
FileMap,
|
FileMap,
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectGraphExternalNode,
|
ProjectGraphExternalNode,
|
||||||
} from '../../config/project-graph';
|
} from '../../config/project-graph';
|
||||||
|
|
||||||
import { ProjectConfiguration } from '../../config/workspace-json-project-json';
|
import type { ProjectConfiguration } from '../../config/workspace-json-project-json';
|
||||||
|
|
||||||
import { NxJsonConfiguration } from '../../config/nx-json';
|
import type { NxJsonConfiguration } from '../../config/nx-json';
|
||||||
import { RawProjectGraphDependency } from '../project-graph-builder';
|
import type { RawProjectGraphDependency } from '../project-graph-builder';
|
||||||
|
import type { TaskResults } from '../../tasks-runner/life-cycle';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context for {@link CreateNodesFunction}
|
* Context for {@link CreateNodesFunction}
|
||||||
@ -146,7 +147,7 @@ export type CreateMetadata<T = unknown> = (
|
|||||||
) => ProjectsMetadata | Promise<ProjectsMetadata>;
|
) => ProjectsMetadata | Promise<ProjectsMetadata>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A plugin for Nx which creates nodes and dependencies for the {@link ProjectGraph}
|
* A plugin which enhances the behavior of Nx
|
||||||
*/
|
*/
|
||||||
export type NxPluginV2<TOptions = unknown> = {
|
export type NxPluginV2<TOptions = unknown> = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -176,9 +177,37 @@ export type NxPluginV2<TOptions = unknown> = {
|
|||||||
* Provides a function to create metadata for the {@link ProjectGraph}
|
* Provides a function to create metadata for the {@link ProjectGraph}
|
||||||
*/
|
*/
|
||||||
createMetadata?: CreateMetadata<TOptions>;
|
createMetadata?: CreateMetadata<TOptions>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a function to run before the Nx runs tasks
|
||||||
|
*/
|
||||||
|
preTasksExecution?: PreTasksExecution<TOptions>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a function to run after the Nx runs tasks
|
||||||
|
*/
|
||||||
|
postTasksExecution?: PostTasksExecution<TOptions>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PreTasksExecutionContext = {
|
||||||
|
readonly workspaceRoot: string;
|
||||||
|
readonly nxJsonConfiguration: NxJsonConfiguration;
|
||||||
|
};
|
||||||
|
export type PostTasksExecutionContext = {
|
||||||
|
readonly workspaceRoot: string;
|
||||||
|
readonly nxJsonConfiguration: NxJsonConfiguration;
|
||||||
|
readonly taskResults: TaskResults;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PreTasksExecution<TOptions = unknown> = (
|
||||||
|
options: TOptions | undefined,
|
||||||
|
context: PreTasksExecutionContext
|
||||||
|
) => void | Promise<void>;
|
||||||
|
export type PostTasksExecution<TOptions = unknown> = (
|
||||||
|
options: TOptions | undefined,
|
||||||
|
context: PostTasksExecutionContext
|
||||||
|
) => void | Promise<void>;
|
||||||
/**
|
/**
|
||||||
* A plugin for Nx
|
* A plugin which enhances the behavior of Nx
|
||||||
*/
|
*/
|
||||||
export type NxPlugin = NxPluginV2;
|
export type NxPlugin = NxPluginV2;
|
||||||
|
|||||||
@ -0,0 +1,89 @@
|
|||||||
|
import type {
|
||||||
|
PostTasksExecutionContext,
|
||||||
|
PreTasksExecutionContext,
|
||||||
|
} from './public-api';
|
||||||
|
import { getPlugins } from './get-plugins';
|
||||||
|
import { isOnDaemon } from '../../daemon/is-on-daemon';
|
||||||
|
import { daemonClient, isDaemonEnabled } from '../../daemon/client/client';
|
||||||
|
|
||||||
|
export async function runPreTasksExecution(
|
||||||
|
pluginContext: PreTasksExecutionContext
|
||||||
|
) {
|
||||||
|
if (isOnDaemon() || !isDaemonEnabled()) {
|
||||||
|
performance.mark(`preTasksExecution:start`);
|
||||||
|
const plugins = await getPlugins(pluginContext.workspaceRoot);
|
||||||
|
const envs = await Promise.all(
|
||||||
|
plugins
|
||||||
|
.filter((p) => p.preTasksExecution)
|
||||||
|
.map(async (plugin) => {
|
||||||
|
performance.mark(`${plugin.name}:preTasksExecution:start`);
|
||||||
|
try {
|
||||||
|
return await plugin.preTasksExecution(pluginContext);
|
||||||
|
} finally {
|
||||||
|
performance.mark(`${plugin.name}:preTasksExecution:end`);
|
||||||
|
performance.measure(
|
||||||
|
`${plugin.name}:preTasksExecution`,
|
||||||
|
`${plugin.name}:preTasksExecution:start`,
|
||||||
|
`${plugin.name}:preTasksExecution:end`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDaemonEnabled()) {
|
||||||
|
applyProcessEnvs(envs);
|
||||||
|
}
|
||||||
|
performance.mark(`preTasksExecution:end`);
|
||||||
|
performance.measure(
|
||||||
|
`preTasksExecution`,
|
||||||
|
`preTasksExecution:start`,
|
||||||
|
`preTasksExecution:end`
|
||||||
|
);
|
||||||
|
return envs;
|
||||||
|
} else {
|
||||||
|
const envs = await daemonClient.runPreTasksExecution(pluginContext);
|
||||||
|
applyProcessEnvs(envs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyProcessEnvs(envs: NodeJS.ProcessEnv[]) {
|
||||||
|
for (const env of envs) {
|
||||||
|
for (const key in env) {
|
||||||
|
process.env[key] = env[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function runPostTasksExecution(
|
||||||
|
context: PostTasksExecutionContext
|
||||||
|
) {
|
||||||
|
if (isOnDaemon() || !isDaemonEnabled()) {
|
||||||
|
performance.mark(`postTasksExecution:start`);
|
||||||
|
const plugins = await getPlugins();
|
||||||
|
await Promise.all(
|
||||||
|
plugins
|
||||||
|
.filter((p) => p.postTasksExecution)
|
||||||
|
.map(async (plugin) => {
|
||||||
|
performance.mark(`${plugin.name}:postTasksExecution:start`);
|
||||||
|
try {
|
||||||
|
await plugin.postTasksExecution(context);
|
||||||
|
} finally {
|
||||||
|
performance.mark(`${plugin.name}:postTasksExecution:end`);
|
||||||
|
performance.measure(
|
||||||
|
`${plugin.name}:postTasksExecution`,
|
||||||
|
`${plugin.name}:postTasksExecution:start`,
|
||||||
|
`${plugin.name}:postTasksExecution:end`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
performance.mark(`postTasksExecution:end`);
|
||||||
|
performance.measure(
|
||||||
|
`postTasksExecution`,
|
||||||
|
`postTasksExecution:start`,
|
||||||
|
`postTasksExecution:end`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await daemonClient.runPostTasksExecution(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -97,7 +97,7 @@ export async function retrieveProjectConfigurationsWithAngularProjects(
|
|||||||
pluginsToLoad.push(join(__dirname, '../../adapter/angular-json'));
|
pluginsToLoad.push(join(__dirname, '../../adapter/angular-json'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugins = await getPlugins();
|
const plugins = await getPlugins(workspaceRoot);
|
||||||
|
|
||||||
const res = await retrieveProjectConfigurations(
|
const res = await retrieveProjectConfigurations(
|
||||||
plugins,
|
plugins,
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import { TaskStatus } from './tasks-runner';
|
import { TaskStatus } from './tasks-runner';
|
||||||
import { Task } from '../config/task-graph';
|
import { Task } from '../config/task-graph';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result of a completed {@link Task}
|
||||||
|
*/
|
||||||
export interface TaskResult {
|
export interface TaskResult {
|
||||||
task: Task;
|
task: Task;
|
||||||
status: TaskStatus;
|
status: TaskStatus;
|
||||||
@ -8,6 +11,11 @@ export interface TaskResult {
|
|||||||
terminalOutput?: string;
|
terminalOutput?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of {@link TaskResult} keyed by the ID of the completed {@link Task}s
|
||||||
|
*/
|
||||||
|
export type TaskResults = Record<string, TaskResult>;
|
||||||
|
|
||||||
export interface TaskMetadata {
|
export interface TaskMetadata {
|
||||||
groupId: number;
|
groupId: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,12 @@ import {
|
|||||||
} from '../utils/sync-generators';
|
} from '../utils/sync-generators';
|
||||||
import { workspaceRoot } from '../utils/workspace-root';
|
import { workspaceRoot } from '../utils/workspace-root';
|
||||||
import { createTaskGraph } from './create-task-graph';
|
import { createTaskGraph } from './create-task-graph';
|
||||||
import { CompositeLifeCycle, LifeCycle, TaskResult } from './life-cycle';
|
import {
|
||||||
|
CompositeLifeCycle,
|
||||||
|
LifeCycle,
|
||||||
|
TaskResult,
|
||||||
|
TaskResults,
|
||||||
|
} from './life-cycle';
|
||||||
import { createRunManyDynamicOutputRenderer } from './life-cycles/dynamic-run-many-terminal-output-life-cycle';
|
import { createRunManyDynamicOutputRenderer } from './life-cycles/dynamic-run-many-terminal-output-life-cycle';
|
||||||
import { createRunOneDynamicOutputRenderer } from './life-cycles/dynamic-run-one-terminal-output-life-cycle';
|
import { createRunOneDynamicOutputRenderer } from './life-cycles/dynamic-run-one-terminal-output-life-cycle';
|
||||||
import { StaticRunManyTerminalOutputLifeCycle } from './life-cycles/static-run-many-terminal-output-life-cycle';
|
import { StaticRunManyTerminalOutputLifeCycle } from './life-cycles/static-run-many-terminal-output-life-cycle';
|
||||||
@ -55,6 +60,10 @@ import { shouldStreamOutput } from './utils';
|
|||||||
import chalk = require('chalk');
|
import chalk = require('chalk');
|
||||||
import type { Observable } from 'rxjs';
|
import type { Observable } from 'rxjs';
|
||||||
import { printPowerpackLicense } from '../utils/powerpack';
|
import { printPowerpackLicense } from '../utils/powerpack';
|
||||||
|
import {
|
||||||
|
runPostTasksExecution,
|
||||||
|
runPreTasksExecution,
|
||||||
|
} from '../project-graph/plugins/tasks-execution-hooks';
|
||||||
|
|
||||||
async function getTerminalOutputLifeCycle(
|
async function getTerminalOutputLifeCycle(
|
||||||
initiatingProject: string,
|
initiatingProject: string,
|
||||||
@ -177,23 +186,42 @@ export async function runCommand(
|
|||||||
const status = await handleErrors(
|
const status = await handleErrors(
|
||||||
process.env.NX_VERBOSE_LOGGING === 'true',
|
process.env.NX_VERBOSE_LOGGING === 'true',
|
||||||
async () => {
|
async () => {
|
||||||
|
await runPreTasksExecution({
|
||||||
|
workspaceRoot,
|
||||||
|
nxJsonConfiguration: nxJson,
|
||||||
|
});
|
||||||
|
|
||||||
const taskResults = await runCommandForTasks(
|
const taskResults = await runCommandForTasks(
|
||||||
projectsToRun,
|
projectsToRun,
|
||||||
currentProjectGraph,
|
currentProjectGraph,
|
||||||
{ nxJson },
|
{ nxJson },
|
||||||
nxArgs,
|
{
|
||||||
|
...nxArgs,
|
||||||
|
skipNxCache:
|
||||||
|
nxArgs.skipNxCache ||
|
||||||
|
process.env.NX_SKIP_NX_CACHE === 'true' ||
|
||||||
|
process.env.NX_DISABLE_NX_CACHE === 'true',
|
||||||
|
},
|
||||||
overrides,
|
overrides,
|
||||||
initiatingProject,
|
initiatingProject,
|
||||||
extraTargetDependencies,
|
extraTargetDependencies,
|
||||||
extraOptions
|
extraOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
return Object.values(taskResults).some(
|
const result = Object.values(taskResults).some(
|
||||||
(taskResult) =>
|
(taskResult) =>
|
||||||
taskResult.status === 'failure' || taskResult.status === 'skipped'
|
taskResult.status === 'failure' || taskResult.status === 'skipped'
|
||||||
)
|
)
|
||||||
? 1
|
? 1
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
|
await runPostTasksExecution({
|
||||||
|
taskResults,
|
||||||
|
workspaceRoot,
|
||||||
|
nxJsonConfiguration: nxJson,
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -209,7 +237,7 @@ export async function runCommandForTasks(
|
|||||||
initiatingProject: string | null,
|
initiatingProject: string | null,
|
||||||
extraTargetDependencies: Record<string, (TargetDependencyConfig | string)[]>,
|
extraTargetDependencies: Record<string, (TargetDependencyConfig | string)[]>,
|
||||||
extraOptions: { excludeTaskDependencies: boolean; loadDotEnvFiles: boolean }
|
extraOptions: { excludeTaskDependencies: boolean; loadDotEnvFiles: boolean }
|
||||||
): Promise<{ [id: string]: TaskResult }> {
|
): Promise<TaskResults> {
|
||||||
const projectNames = projectsToRun.map((t) => t.name);
|
const projectNames = projectsToRun.map((t) => t.name);
|
||||||
|
|
||||||
const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(
|
const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(
|
||||||
|
|||||||
@ -230,7 +230,6 @@ export class TaskOrchestrator {
|
|||||||
task: Task;
|
task: Task;
|
||||||
status: 'local-cache' | 'local-cache-kept-existing' | 'remote-cache';
|
status: 'local-cache' | 'local-cache-kept-existing' | 'remote-cache';
|
||||||
}> {
|
}> {
|
||||||
task.startTime = Date.now();
|
|
||||||
const cachedResult = await this.cache.get(task);
|
const cachedResult = await this.cache.get(task);
|
||||||
if (!cachedResult || cachedResult.code !== 0) return null;
|
if (!cachedResult || cachedResult.code !== 0) return null;
|
||||||
|
|
||||||
@ -241,7 +240,6 @@ export class TaskOrchestrator {
|
|||||||
if (shouldCopyOutputsFromCache) {
|
if (shouldCopyOutputsFromCache) {
|
||||||
await this.cache.copyFilesFromCache(task.hash, cachedResult, outputs);
|
await this.cache.copyFilesFromCache(task.hash, cachedResult, outputs);
|
||||||
}
|
}
|
||||||
task.endTime = Date.now();
|
|
||||||
const status = cachedResult.remote
|
const status = cachedResult.remote
|
||||||
? 'remote-cache'
|
? 'remote-cache'
|
||||||
: shouldCopyOutputsFromCache
|
: shouldCopyOutputsFromCache
|
||||||
@ -545,6 +543,10 @@ export class TaskOrchestrator {
|
|||||||
|
|
||||||
// region Lifecycle
|
// region Lifecycle
|
||||||
private async preRunSteps(tasks: Task[], metadata: TaskMetadata) {
|
private async preRunSteps(tasks: Task[], metadata: TaskMetadata) {
|
||||||
|
const now = Date.now();
|
||||||
|
for (const task of tasks) {
|
||||||
|
task.startTime = now;
|
||||||
|
}
|
||||||
await this.options.lifeCycle.startTasks(tasks, metadata);
|
await this.options.lifeCycle.startTasks(tasks, metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,7 +560,9 @@ export class TaskOrchestrator {
|
|||||||
doNotSkipCache: boolean,
|
doNotSkipCache: boolean,
|
||||||
{ groupId }: { groupId: number }
|
{ groupId }: { groupId: number }
|
||||||
) {
|
) {
|
||||||
|
const now = Date.now();
|
||||||
for (const task of tasks) {
|
for (const task of tasks) {
|
||||||
|
task.endTime = now;
|
||||||
await this.recordOutputsHash(task);
|
await this.recordOutputsHash(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user