Skip to content

Commit

Permalink
feat(core): allow executor definition to point to another executor (#…
Browse files Browse the repository at this point in the history
…23576)

Add support for executor definitions that point to another executor. The
upcoming Angular 18 uses this feature:
https://github.com/angular/angular-cli/blob/main/packages/angular_devkit/build_angular/builders.json#L4,
so we need to be able to resolve the builders correctly using such a
configuration.

Note: the change is also in [the Angular 18
PR](#22509), where it's tested with the
Angular version that requires it. I'm extracting the change to this PR
to facilitate reviews and reduce the size of the Angular 18 PR.

<!-- 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` -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

(cherry picked from commit c240c26)
  • Loading branch information
leosvelperez authored and FrozenPandaz committed May 21, 2024
1 parent 91cc154 commit 4f43ac1
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 21 deletions.
30 changes: 18 additions & 12 deletions packages/nx/src/adapter/ngcli-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
Executor,
ExecutorConfig,
ExecutorContext,
ExecutorJsonEntryConfig,
ExecutorsJson,
GeneratorCallback,
TaskGraphExecutor,
Expand Down Expand Up @@ -1174,14 +1175,11 @@ async function getWrappedWorkspaceNodeModulesArchitectHost(
builderName
);
const builderInfo = this.readExecutor(packageName, builderName);
const { builders, executors } =
readJsonFile<ExecutorsJson>(executorsFilePath);

return {
name: builderStr,
builderName,
description:
builders?.[builderName]?.description ??
executors?.[builderName]?.description,
description: executorConfig.description,
optionSchema: builderInfo.schema,
import: resolveImplementation(
executorConfig.implementation,
Expand All @@ -1190,7 +1188,14 @@ async function getWrappedWorkspaceNodeModulesArchitectHost(
};
}

private readExecutorsJson(nodeModule: string, builder: string) {
private readExecutorsJson(
nodeModule: string,
builder: string
): {
executorsFilePath: string;
executorConfig: ExecutorJsonEntryConfig;
isNgCompat: true;
} {
const { json: packageJson, path: packageJsonPath } =
readPluginPackageJson(
nodeModule,
Expand All @@ -1209,18 +1214,19 @@ async function getWrappedWorkspaceNodeModulesArchitectHost(
join(dirname(packageJsonPath), executorsFile)
);
const executorsJson = readJsonFile<ExecutorsJson>(executorsFilePath);
const executorConfig: {
implementation: string;
batchImplementation?: string;
schema: string;
hasher?: string;
} =
const executorConfig =
executorsJson.builders?.[builder] ?? executorsJson.executors?.[builder];
if (!executorConfig) {
throw new Error(
`Cannot find builder '${builder}' in ${executorsFilePath}.`
);
}
if (typeof executorConfig === 'string') {
// Angular CLI can have a builder pointing to another package:builder
const [packageName, executorName] = executorConfig.split(':');
return this.readExecutorsJson(packageName, executorName);
}

return { executorsFilePath, executorConfig, isNgCompat: true };
}

Expand Down
13 changes: 7 additions & 6 deletions packages/nx/src/command-line/run/executor-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,18 @@ function readExecutorJson(
join(dirname(packageJsonPath), executorsFile)
);
const executorsJson = readJsonFile<ExecutorsJson>(executorsFilePath);
const executorConfig: {
implementation: string;
batchImplementation?: string;
schema: string;
hasher?: string;
} = executorsJson.executors?.[executor] || executorsJson.builders?.[executor];
const executorConfig =
executorsJson.executors?.[executor] || executorsJson.builders?.[executor];
if (!executorConfig) {
throw new Error(
`Cannot find executor '${executor}' in ${executorsFilePath}.`
);
}
if (typeof executorConfig === 'string') {
// Angular CLI can have a builder pointing to another package:builder
const [packageName, executorName] = executorConfig.split(':');
return readExecutorJson(packageName, executorName, root, projects);
}
const isNgCompat = !executorsJson.executors?.[executor];
return { executorsFilePath, executorConfig, isNgCompat };
}
3 changes: 2 additions & 1 deletion packages/nx/src/config/misc-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ export interface GeneratorsJsonEntry {

export type OutputCaptureMethod = 'direct-nodejs' | 'pipe';

export interface ExecutorsJsonEntry {
export interface ExecutorJsonEntryConfig {
schema: string;
implementation: string;
batchImplementation?: string;
description?: string;
hasher?: string;
}
export type ExecutorsJsonEntry = string | ExecutorJsonEntryConfig;

export type Dependencies = 'dependencies' | 'devDependencies';

Expand Down
49 changes: 48 additions & 1 deletion packages/nx/src/utils/plugins/plugin-capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { workspaceRoot } from '../workspace-root';
import { hasElements } from './shared';

import type { PluginCapabilities } from './models';
import type { ExecutorsJsonEntry } from '../../config/misc-interfaces';

function tryGetCollection<T extends object>(
packageJsonPath: string,
Expand Down Expand Up @@ -179,7 +180,11 @@ export async function listPluginCapabilities(
bodyLines.push('');
bodyLines.push(
...Object.keys(plugin.executors).map(
(name) => `${chalk.bold(name)} : ${plugin.executors[name].description}`
(name) =>
`${chalk.bold(name)} : ${resolveExecutorDescription(
plugin.executors[name],
projects
)}`
)
);
}
Expand All @@ -197,3 +202,45 @@ export async function listPluginCapabilities(
bodyLines,
});
}

function resolveExecutorDescription(
executorJsonEntry: ExecutorsJsonEntry,
projects: Record<string, ProjectConfiguration>
) {
try {
if (typeof executorJsonEntry === 'string') {
// it points to another executor, resolve it
const [pkgName, executor] = executorJsonEntry.split(':');
const collection = loadExecutorsCollection(
workspaceRoot,
pkgName,
projects
);

return resolveExecutorDescription(collection[executor], projects);
}

return executorJsonEntry.description;
} catch {
return 'No description available';
}
}

function loadExecutorsCollection(
workspaceRoot: string,
pluginName: string,
projects: Record<string, ProjectConfiguration>
): { [name: string]: ExecutorsJsonEntry } {
const { json: packageJson, path: packageJsonPath } = readPluginPackageJson(
pluginName,
projects,
getNxRequirePaths(workspaceRoot)
);

return {
...tryGetCollection(packageJsonPath, packageJson.builders, 'builders'),
...tryGetCollection(packageJsonPath, packageJson.executors, 'builders'),
...tryGetCollection(packageJsonPath, packageJson.builders, 'executors'),
...tryGetCollection(packageJsonPath, packageJson.executors, 'executors'),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ function deleteCliPropFromSchemaFile(
entry: ExecutorsJsonEntry | GeneratorsJsonEntry,
tree: Tree
) {
if (!entry.schema) {
if (typeof entry === 'string' || !entry.schema) {
return;
}
const schemaPath = joinPathFragments(dirname(collectionPath), entry.schema);
Expand Down

0 comments on commit 4f43ac1

Please sign in to comment.