Skip to content

Commit

Permalink
chore(core): copy isNxExecutor out of Workspaces class (nrwl#17996)
Browse files Browse the repository at this point in the history
  • Loading branch information
xiongemi authored Jul 14, 2023
1 parent 6ccbbbc commit 1c6a359
Show file tree
Hide file tree
Showing 14 changed files with 283 additions and 227 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import type { Schema } from './schema';
import {
logger,
readCachedProjectGraph,
workspaceRoot,
Workspaces,
} from '@nx/devkit';
import { logger, readCachedProjectGraph, workspaceRoot } from '@nx/devkit';
import { scheduleTarget } from 'nx/src/adapter/ngcli-adapter';
import { executeWebpackDevServerBuilder } from '../webpack-dev-server/webpack-dev-server.impl';
import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph';
import { getExecutorInformation } from 'nx/src/command-line/run/executor-utils';
import {
getDynamicRemotes,
getStaticRemotes,
Expand All @@ -25,7 +21,6 @@ export function executeModuleFederationDevServerBuilder(
const projectGraph = readCachedProjectGraph();
const { projects: workspaceProjects } =
readProjectsConfigurationFromProjectGraph(projectGraph);
const ws = new Workspaces(workspaceRoot);
const project = workspaceProjects[context.target.project];

let pathToManifestFile = join(
Expand Down Expand Up @@ -101,7 +96,11 @@ export function executeModuleFederationDevServerBuilder(
if (options.verbose) {
const [collection, executor] =
workspaceProjects[remote].targets[target].executor.split(':');
const { schema } = ws.readExecutor(collection, executor);
const { schema } = getExecutorInformation(
collection,
executor,
workspaceRoot
);

if (schema.additionalProperties || 'verbose' in schema.properties) {
runOptions.verbose = options.verbose;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Schema } from './schema';
import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph';
import { readCachedProjectGraph, workspaceRoot, Workspaces } from '@nx/devkit';
import { getExecutorInformation } from 'nx/src/command-line/run/executor-utils';
import { readCachedProjectGraph, workspaceRoot } from '@nx/devkit';
import {
getDynamicRemotes,
getStaticRemotes,
Expand All @@ -21,7 +22,6 @@ export function executeModuleFederationDevSSRBuilder(
const projectGraph = readCachedProjectGraph();
const { projects: workspaceProjects } =
readProjectsConfigurationFromProjectGraph(projectGraph);
const ws = new Workspaces(workspaceRoot);
const project = workspaceProjects[context.target.project];

let pathToManifestFile = join(
Expand Down Expand Up @@ -90,7 +90,11 @@ export function executeModuleFederationDevSSRBuilder(
if (options.verbose) {
const [collection, executor] =
workspaceProjects[remote].targets[target].executor.split(':');
const { schema } = ws.readExecutor(collection, executor);
const { schema } = getExecutorInformation(
collection,
executor,
workspaceRoot
);

if (schema.additionalProperties || 'verbose' in schema.properties) {
runOptions.verbose = options.verbose;
Expand Down
14 changes: 10 additions & 4 deletions packages/cypress/src/executors/cypress/cypress.impl.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getTempTailwindPath } from '../../utils/ct-helpers';
import { ExecutorContext, stripIndents } from '@nx/devkit';
import * as executorUtils from 'nx/src/command-line/run/executor-utils';
import * as path from 'path';
import { installedCypressVersion } from '../../utils/cypress-version';
import cypressExecutor, { CypressExecutorOptions } from './cypress.impl';
Expand Down Expand Up @@ -43,9 +44,17 @@ describe('Cypress builder', () => {
},
},
} as any;
(devkit as any).readTargetOptions = jest.fn().mockReturnValue({
jest.spyOn(devkit, 'readTargetOptions').mockReturnValue({
watch: true,
});
jest.spyOn(executorUtils, 'getExecutorInformation').mockReturnValue({
schema: { properties: {} },
hasherFactory: jest.fn(),
implementationFactory: jest.fn(),
batchImplementationFactory: jest.fn(),
isNgCompat: true,
isNxExecutor: true,
});
let runExecutor: any;
let mockGetTailwindPath: jest.Mock<ReturnType<typeof getTempTailwindPath>> =
getTempTailwindPath as any;
Expand All @@ -57,9 +66,6 @@ describe('Cypress builder', () => {
baseUrl: 'http://localhost:4200',
},
]);
(devkit as any).Workspaces = jest.fn().mockReturnValue({
readExecutor: () => ({ schema: { properties: {} } }),
});
(devkit as any).stripIndents = (s) => s;
(devkit as any).parseTargetString = (s) => {
const [project, target, configuration] = s.split(':');
Expand Down
9 changes: 6 additions & 3 deletions packages/cypress/src/executors/cypress/cypress.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import {
readTargetOptions,
runExecutor,
stripIndents,
Workspaces,
Target,
targetToTargetString,
output,
} from '@nx/devkit';
import { getExecutorInformation } from 'nx/src/command-line/run/executor-utils';
import 'dotenv/config';
import { existsSync, readdirSync, unlinkSync, writeFileSync } from 'fs';
import { basename, dirname, join } from 'path';
Expand Down Expand Up @@ -421,9 +421,12 @@ ${e.message || e}`);
context.projectsConfigurations?.projects?.[target.project];
const targetConfig = projectConfig.targets[target.target];

const workspace = new Workspaces(context.root);
const [collection, executor] = targetConfig.executor.split(':');
const { schema } = workspace.readExecutor(collection, executor);
const { schema } = getExecutorInformation(
collection,
executor,
context.root
);

// NOTE: schema won't have a default since readTargetOptions would have
// already set that and this check wouldn't need to be made
Expand Down
8 changes: 6 additions & 2 deletions packages/devkit/src/executors/read-target-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { ExecutorContext } from 'nx/src/config/misc-interfaces';
import { combineOptionsForExecutor } from 'nx/src/utils/params';
import { requireNx } from '../../nx';

const { Workspaces } = requireNx();
const { Workspaces, getExecutorInformation } = requireNx();

/**
* Reads and combines options for a given target.
Expand All @@ -22,7 +22,11 @@ export function readTargetOptions<T = any>(

const ws = new Workspaces(context.root);
const [nodeModule, executorName] = targetConfiguration.executor.split(':');
const { schema } = ws.readExecutor(nodeModule, executorName);
const { schema } = getExecutorInformation(
nodeModule,
executorName,
context.root
);

const defaultProject = ws.calculateDefaultProjectName(
context.cwd,
Expand Down
19 changes: 10 additions & 9 deletions packages/nx/src/adapter/ngcli-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import {
toNewFormat,
toOldFormat,
} from './angular-json';
import { normalizeExecutorSchema, Workspaces } from '../config/workspaces';
import { normalizeExecutorSchema } from '../command-line/run/executor-utils';
import { Workspaces } from '../config/workspaces';
import {
CustomHasher,
Executor,
Expand All @@ -55,6 +56,11 @@ import {
TaskGraphExecutor,
} from '../config/misc-interfaces';
import { readPluginPackageJson } from '../utils/nx-plugin';
import {
getImplementationFactory,
resolveImplementation,
resolveSchema,
} from '../config/schema-utils';

export async function scheduleTarget(
root: string,
Expand Down Expand Up @@ -106,7 +112,7 @@ export async function scheduleTarget(
readJsonFile<ExecutorsJson>(executorsFilePath).builders[builderName]
.description,
optionSchema: builderInfo.schema,
import: this.workspaces['resolveImplementation'].bind(this.workspaces)(
import: resolveImplementation(
executorConfig.implementation,
dirname(executorsFilePath)
),
Expand Down Expand Up @@ -153,9 +159,7 @@ export async function scheduleTarget(
const { executorsFilePath, executorConfig, isNgCompat } =
this.readExecutorsJson(nodeModule, executor);
const executorsDir = dirname(executorsFilePath);
const schemaPath = this.workspaces['resolveSchema'].bind(
this.workspaces
)(executorConfig.schema, executorsDir);
const schemaPath = resolveSchema(executorConfig.schema, executorsDir);
const schema = normalizeExecutorSchema(readJsonFile(schemaPath));

const implementationFactory = this.getImplementationFactory<Executor>(
Expand Down Expand Up @@ -195,10 +199,7 @@ export async function scheduleTarget(
implementation: string,
executorsDir: string
): () => T {
return this.workspaces['getImplementationFactory'].bind(this.workspaces)(
implementation,
executorsDir
);
return getImplementationFactory(implementation, executorsDir);
}
}

Expand Down
128 changes: 128 additions & 0 deletions packages/nx/src/command-line/run/executor-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { dirname, join } from 'path';

import { readPluginPackageJson } from '../../utils/nx-plugin';
import {
CustomHasher,
Executor,
ExecutorConfig,
ExecutorsJson,
TaskGraphExecutor,
} from '../../config/misc-interfaces';
import { readJsonFile } from '../../utils/fileutils';
import {
getImplementationFactory,
resolveSchema,
} from '../../config/schema-utils';
import { getNxRequirePaths } from '../../utils/installation-directory';

export function normalizeExecutorSchema(
schema: Partial<ExecutorConfig['schema']>
): ExecutorConfig['schema'] {
const version = (schema.version ??= 1);
return {
version,
outputCapture:
schema.outputCapture ?? version < 2 ? 'direct-nodejs' : 'pipe',
properties:
!schema.properties || typeof schema.properties !== 'object'
? {}
: schema.properties,
...schema,
};
}

export function getExecutorInformation(
nodeModule: string,
executor: string,
root: string
): ExecutorConfig & { isNgCompat: boolean; isNxExecutor: boolean } {
try {
const { executorsFilePath, executorConfig, isNgCompat } = readExecutorsJson(
nodeModule,
executor,
root
);
const executorsDir = dirname(executorsFilePath);
const schemaPath = resolveSchema(executorConfig.schema, executorsDir);
const schema = normalizeExecutorSchema(readJsonFile(schemaPath));

const implementationFactory = getImplementationFactory<Executor>(
executorConfig.implementation,
executorsDir
);

const batchImplementationFactory = executorConfig.batchImplementation
? getImplementationFactory<TaskGraphExecutor>(
executorConfig.batchImplementation,
executorsDir
)
: null;

const hasherFactory = executorConfig.hasher
? getImplementationFactory<CustomHasher>(
executorConfig.hasher,
executorsDir
)
: null;

return {
schema,
implementationFactory,
batchImplementationFactory,
hasherFactory,
isNgCompat,
isNxExecutor: !isNgCompat,
};
} catch (e) {
throw new Error(
`Unable to resolve ${nodeModule}:${executor}.\n${e.message}`
);
}
}

function readExecutorsJson(
nodeModule: string,
executor: string,
root: string
): {
executorsFilePath: string;
executorConfig: {
implementation: string;
batchImplementation?: string;
schema: string;
hasher?: string;
};
isNgCompat: boolean;
} {
const { json: packageJson, path: packageJsonPath } = readPluginPackageJson(
nodeModule,
root
? [root, __dirname, process.cwd(), ...getNxRequirePaths()]
: [__dirname, process.cwd(), ...getNxRequirePaths()]
);
const executorsFile = packageJson.executors ?? packageJson.builders;

if (!executorsFile) {
throw new Error(
`The "${nodeModule}" package does not support Nx executors.`
);
}

const executorsFilePath = require.resolve(
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];
if (!executorConfig) {
throw new Error(
`Cannot find executor '${executor}' in ${executorsFilePath}.`
);
}
const isNgCompat = !executorsJson.executors?.[executor];
return { executorsFilePath, executorConfig, isNgCompat };
}
8 changes: 5 additions & 3 deletions packages/nx/src/command-line/run/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
getLastValueFromAsyncIterableIterator,
isAsyncIterator,
} from '../../utils/async-iterator';
import { getExecutorInformation } from './executor-utils';

export interface Target {
project: string;
Expand Down Expand Up @@ -131,9 +132,10 @@ async function parseExecutorAndTarget(
}

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

return { executor, implementationFactory, nodeModule, schema, targetConfig };
Expand Down Expand Up @@ -195,7 +197,7 @@ async function runExecutorInternal<T extends { success: boolean }>(
isVerbose
);

if (ws.isNxExecutor(nodeModule, executor)) {
if (getExecutorInformation(nodeModule, executor, root).isNxExecutor) {
const implementation = implementationFactory() as Executor<any>;
const r = implementation(combinedOptions, {
root,
Expand Down
Loading

0 comments on commit 1c6a359

Please sign in to comment.