feat(core): allow executors to specify if they are continuous (#30821)
<!-- 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 --> The only way to set if a task is continuous is either directly in `project.json` or via Project Graph Plugins. ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> Executors know if they are definitely continuous or not. Plenty of existing continuous tasks are using executors. Executors are now able to define if they are continuous in their `schema.json` files. Thus, existing tasks configured with certain executors will automatically become continuous. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
eb5138e858
commit
4254c4bcce
@ -51,7 +51,7 @@ The `nx.json` configuration from the workspace
|
||||
|
||||
• `Readonly` **projects**: `Record`\<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\>
|
||||
|
||||
The configuration of each project in the workspace.
|
||||
The configuration of each project in the workspace keyed by project name.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/angular/src/builders/dev-server/dev-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Webpack Dev Server",
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Module Federation Dev Server",
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"description": "Serves host [Module Federation](https://module-federation.io/) applications ([webpack](https://webpack.js.org/)-based) allowing to specify which remote applications should be served with the host.",
|
||||
"type": "object",
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Module Federation SSR Dev Server Target",
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"description": "The module-federation-ssr-dev-server executor is reserved exclusively for use with host SSR Module Federation applications. It allows the user to specify which remote applications should be served with the host.",
|
||||
"type": "object",
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
"version": 2,
|
||||
"title": "Verdaccio Local Registry",
|
||||
"description": "Start a local registry with Verdaccio.",
|
||||
"continuous": true,
|
||||
"cli": "nx",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/next/src/executors/server/server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "pipe",
|
||||
"cli": "nx",
|
||||
"title": "Next Serve",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/react/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation Dev Server",
|
||||
"description": "Serve a web application.",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/react/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation SSR Dev Server",
|
||||
"description": "Serve a SSR Consumer (host) application along with its known Producers (remotes).",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/react/src/executors/module-federation-static-server/module-federation-static-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation Static Dev Server",
|
||||
"description": "Serve a Consumer (host) application statically along with its Producers (remotes).",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/remix/src/executors/serve/serve.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "pipe",
|
||||
"cli": "nx",
|
||||
"title": "Remix Serve",
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
"version": 2,
|
||||
"title": "Rspack dev-server executor",
|
||||
"description": "Run @rspack/dev-server to serve a project.",
|
||||
"continuous": true,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"buildTarget": {
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/rspack/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Rspack Module Federation Dev Server",
|
||||
"description": "Serve a module federation application.",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/rspack/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation SSR Dev Server",
|
||||
"description": "Serve a SSR Consumer (host) application along with its known Producers (remotes).",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/rspack/src/executors/module-federation-static-server/module-federation-static-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation Static Dev Server",
|
||||
"description": "Serve a Consumer (host) application statically along with it's Producers (remotes).",
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
"name": "ssr-dev-server",
|
||||
"implementation": "/packages/rspack/src/executors/ssr-dev-server/ssr-dev-server.impl.ts",
|
||||
"schema": {
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Rspack SSR Dev Server",
|
||||
"description": "Serve a SSR application using rspack.",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/storybook/src/executors/storybook/storybook.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Storybook Dev Builder",
|
||||
"cli": "nx",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/vite/src/executors/dev-server/dev-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Vite Dev Server",
|
||||
"cli": "nx",
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
"cli": "nx",
|
||||
"title": "Vite Preview Server",
|
||||
"description": "Preview Server for Vite.",
|
||||
"continuous": true,
|
||||
"type": "object",
|
||||
"presets": [
|
||||
{ "name": "Default minimum setup", "keys": ["buildTarget"] },
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/web/src/executors/file-server/file-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "File Server",
|
||||
"description": "Serve a web application from a folder. This executor is a wrapper around the [http-server](https://www.npmjs.com/package/http-server) package.",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/webpack/src/executors/dev-server/dev-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Webpack dev server",
|
||||
"description": "Serve an application using webpack.",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"implementation": "/packages/webpack/src/executors/ssr-dev-server/ssr-dev-server.impl.ts",
|
||||
"schema": {
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Webpack SSR Dev Server",
|
||||
"description": "Serve a SSR application using webpack.",
|
||||
|
||||
@ -135,16 +135,9 @@ const angularV1Json = (appName: string) => `{
|
||||
"projectType": "application",
|
||||
"architect": {
|
||||
"e2e": {
|
||||
"builder": "@nx/cypress:cypress",
|
||||
"builder": "@nx/playwright:playwright",
|
||||
"options": {
|
||||
"cypressConfig": "${appName}-e2e/cypress.json",
|
||||
"devServerTarget": "${appName}:serve:development",
|
||||
"testingType": "e2e"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "${appName}:serve:production"
|
||||
}
|
||||
"config": "${appName}-e2e/playwright.config.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Webpack Dev Server",
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Module Federation Dev Server",
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"description": "Serves host [Module Federation](https://module-federation.io/) applications ([webpack](https://webpack.js.org/)-based) allowing to specify which remote applications should be served with the host.",
|
||||
"type": "object",
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Module Federation SSR Dev Server Target",
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"description": "The module-federation-ssr-dev-server executor is reserved exclusively for use with host SSR Module Federation applications. It allows the user to specify which remote applications should be served with the host.",
|
||||
"type": "object",
|
||||
|
||||
@ -12,7 +12,10 @@ import {
|
||||
import { join } from 'path';
|
||||
import { CypressExecutorOptions } from '../executors/cypress/cypress.impl';
|
||||
import * as detectPort from 'detect-port';
|
||||
import { getExecutorInformation } from 'nx/src/command-line/run/executor-utils';
|
||||
import {
|
||||
getExecutorInformation,
|
||||
parseExecutor,
|
||||
} from 'nx/src/command-line/run/executor-utils';
|
||||
import { existsSync, writeFileSync } from 'fs';
|
||||
|
||||
export async function* startDevServer(
|
||||
@ -190,7 +193,7 @@ ${e.message || e}`);
|
||||
context.projectsConfigurations?.projects?.[target.project];
|
||||
const targetConfig = projectConfig.targets[target.target];
|
||||
|
||||
const [collection, executor] = targetConfig.executor.split(':');
|
||||
const [collection, executor] = parseExecutor(targetConfig.executor);
|
||||
const { schema } = getExecutorInformation(
|
||||
collection,
|
||||
executor,
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
calculateDefaultProjectName,
|
||||
combineOptionsForExecutor,
|
||||
getExecutorInformation,
|
||||
parseExecutor,
|
||||
} from 'nx/src/devkit-internals';
|
||||
|
||||
/**
|
||||
@ -29,7 +30,9 @@ export function readTargetOptions<T = any>(
|
||||
throw new Error(`Unable to find target ${target} for project ${project}`);
|
||||
}
|
||||
|
||||
const [nodeModule, executorName] = targetConfiguration.executor.split(':');
|
||||
const [nodeModule, executorName] = parseExecutor(
|
||||
targetConfiguration.executor
|
||||
);
|
||||
const { schema } = getExecutorInformation(
|
||||
nodeModule,
|
||||
executorName,
|
||||
|
||||
@ -33,6 +33,7 @@ import { dirname, isAbsolute, join, relative, resolve } from 'path';
|
||||
import { getInstalledJestMajorVersion } from '../utils/version-utils';
|
||||
import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context';
|
||||
import { normalize, sep } from 'node:path';
|
||||
import { getNxRequirePaths } from 'nx/src/utils/installation-directory';
|
||||
|
||||
const pmc = getPackageManagerCommand();
|
||||
|
||||
@ -654,7 +655,7 @@ function resolveJestPath(projectRoot: string, workspaceRoot: string): string {
|
||||
}
|
||||
|
||||
resolvedJestPaths[projectRoot] = require.resolve('jest', {
|
||||
paths: [projectRoot, workspaceRoot, __dirname],
|
||||
paths: [projectRoot, ...getNxRequirePaths(workspaceRoot), __dirname],
|
||||
});
|
||||
|
||||
return resolvedJestPaths[projectRoot];
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"version": 2,
|
||||
"title": "Verdaccio Local Registry",
|
||||
"description": "Start a local registry with Verdaccio.",
|
||||
"continuous": true,
|
||||
"cli": "nx",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "pipe",
|
||||
"cli": "nx",
|
||||
"title": "Next Serve",
|
||||
|
||||
@ -24,6 +24,7 @@ export function normalizeExecutorSchema(
|
||||
version,
|
||||
outputCapture:
|
||||
schema.outputCapture ?? version < 2 ? 'direct-nodejs' : 'pipe',
|
||||
continuous: schema.continuous ?? false,
|
||||
properties:
|
||||
!schema.properties || typeof schema.properties !== 'object'
|
||||
? {}
|
||||
@ -36,12 +37,21 @@ function cacheKey(nodeModule: string, executor: string, root: string) {
|
||||
return `${root}:${nodeModule}:${executor}`;
|
||||
}
|
||||
|
||||
export function parseExecutor(
|
||||
executorString: string
|
||||
): [module: string, name: string] {
|
||||
return executorString.split(':') as [string, string];
|
||||
}
|
||||
|
||||
const cachedExecutorInformation = {};
|
||||
|
||||
export function getExecutorInformation(
|
||||
nodeModule: string,
|
||||
executor: string,
|
||||
root: string,
|
||||
/**
|
||||
* A map of projects keyed by project name
|
||||
*/
|
||||
projects: Record<string, ProjectConfiguration>
|
||||
): ExecutorConfig & { isNgCompat: boolean; isNxExecutor: boolean } {
|
||||
try {
|
||||
|
||||
@ -18,7 +18,7 @@ import {
|
||||
getLastValueFromAsyncIterableIterator,
|
||||
isAsyncIterator,
|
||||
} from '../../utils/async-iterator';
|
||||
import { getExecutorInformation } from './executor-utils';
|
||||
import { getExecutorInformation, parseExecutor } from './executor-utils';
|
||||
import {
|
||||
createPseudoTerminal,
|
||||
PseudoTerminal,
|
||||
@ -83,7 +83,7 @@ async function parseExecutorAndTarget(
|
||||
throw new Error(`Cannot find target '${target}' for project '${project}'`);
|
||||
}
|
||||
|
||||
const [nodeModule, executor] = targetConfig.executor.split(':');
|
||||
const [nodeModule, executor] = parseExecutor(targetConfig.executor);
|
||||
const { schema, implementationFactory } = getExecutorInformation(
|
||||
nodeModule,
|
||||
executor,
|
||||
|
||||
@ -110,6 +110,7 @@ export interface ExecutorConfig {
|
||||
schema: {
|
||||
version?: number;
|
||||
outputCapture?: OutputCaptureMethod;
|
||||
continuous?: boolean;
|
||||
} & Schema;
|
||||
hasherFactory?: () => CustomHasher;
|
||||
implementationFactory: () => Executor;
|
||||
|
||||
@ -4,7 +4,10 @@
|
||||
* These may not be available in certain version of Nx, so be sure to check them first.
|
||||
*/
|
||||
export { createTempNpmDirectory } from './utils/package-manager';
|
||||
export { getExecutorInformation } from './command-line/run/executor-utils';
|
||||
export {
|
||||
getExecutorInformation,
|
||||
parseExecutor,
|
||||
} from './command-line/run/executor-utils';
|
||||
export { readNxJson as readNxJsonFromDisk } from './config/nx-json';
|
||||
export { calculateDefaultProjectName } from './config/calculate-default-project-name';
|
||||
export { retrieveProjectConfigurationsWithAngularProjects } from './project-graph/utils/retrieve-workspace-files';
|
||||
|
||||
@ -214,7 +214,12 @@ export function buildProjectConfigurationFromPackageJson(
|
||||
root: projectRoot,
|
||||
name,
|
||||
...packageJson.nx,
|
||||
targets: readTargetsFromPackageJson(packageJson, nxJson),
|
||||
targets: readTargetsFromPackageJson(
|
||||
packageJson,
|
||||
nxJson,
|
||||
projectRoot,
|
||||
workspaceRoot
|
||||
),
|
||||
tags: getTagsFromPackageJson(packageJson),
|
||||
metadata: getMetadataFromPackageJson(
|
||||
packageJson,
|
||||
|
||||
@ -99,7 +99,7 @@ export interface CreateDependenciesContext {
|
||||
readonly externalNodes: ProjectGraph['externalNodes'];
|
||||
|
||||
/**
|
||||
* The configuration of each project in the workspace.
|
||||
* The configuration of each project in the workspace keyed by project name.
|
||||
*/
|
||||
readonly projects: Record<string, ProjectConfiguration>;
|
||||
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
import { ProjectGraphProjectNode } from '../../config/project-graph';
|
||||
import { ProjectGraphBuilder } from '../project-graph-builder';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
} from '../../config/workspace-json-project-json';
|
||||
import { ProjectConfiguration } from '../../config/workspace-json-project-json';
|
||||
import { findMatchingProjects } from '../../utils/find-matching-projects';
|
||||
import { CreateDependenciesContext } from '../plugins';
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import { NxPluginV2 } from '../plugins';
|
||||
import { LoadedNxPlugin } from '../plugins/loaded-nx-plugin';
|
||||
import { dirname } from 'path';
|
||||
import { isProjectConfigurationsError } from '../error-types';
|
||||
import { workspaceRoot } from '../../utils/workspace-root';
|
||||
|
||||
describe('project-configuration-utils', () => {
|
||||
describe('target merging', () => {
|
||||
@ -1658,7 +1659,7 @@ describe('project-configuration-utils', () => {
|
||||
foo: { command: 'echo {projectRoot}' },
|
||||
},
|
||||
};
|
||||
expect(normalizeTarget(config.targets.foo, config))
|
||||
expect(normalizeTarget(config.targets.foo, config, workspaceRoot, {}))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"configurations": {},
|
||||
@ -1701,8 +1702,8 @@ describe('project-configuration-utils', () => {
|
||||
};
|
||||
const originalConfig = JSON.stringify(config, null, 2);
|
||||
|
||||
normalizeTarget(config.targets.foo, config);
|
||||
normalizeTarget(config.targets.bar, config);
|
||||
normalizeTarget(config.targets.foo, config, workspaceRoot, {});
|
||||
normalizeTarget(config.targets.bar, config, workspaceRoot, {});
|
||||
expect(JSON.stringify(config, null, 2)).toEqual(originalConfig);
|
||||
});
|
||||
});
|
||||
|
||||
@ -33,6 +33,10 @@ import {
|
||||
import { CreateNodesResult } from '../plugins/public-api';
|
||||
import { isGlobPattern } from '../../utils/globs';
|
||||
import { DelayedSpinner } from '../../utils/delayed-spinner';
|
||||
import {
|
||||
getExecutorInformation,
|
||||
parseExecutor,
|
||||
} from '../../command-line/run/executor-utils';
|
||||
|
||||
export type SourceInformation = [file: string | null, plugin: string];
|
||||
export type ConfigurationSourceMaps = Record<
|
||||
@ -447,7 +451,7 @@ export async function createProjectConfigurationsWithPlugins(
|
||||
spinner?.cleanup();
|
||||
|
||||
const { projectRootMap, externalNodes, rootMap, configurationSourceMaps } =
|
||||
mergeCreateNodesResults(results, nxJson, errors);
|
||||
mergeCreateNodesResults(results, nxJson, root, errors);
|
||||
|
||||
performance.mark('build-project-configs:end');
|
||||
performance.measure(
|
||||
@ -484,6 +488,7 @@ function mergeCreateNodesResults(
|
||||
pluginIndex?: number
|
||||
])[][],
|
||||
nxJsonConfiguration: NxJsonConfiguration,
|
||||
workspaceRoot: string,
|
||||
errors: (
|
||||
| AggregateCreateNodesError
|
||||
| MergeNodesError
|
||||
@ -539,6 +544,7 @@ function mergeCreateNodesResults(
|
||||
|
||||
try {
|
||||
validateAndNormalizeProjectRootMap(
|
||||
workspaceRoot,
|
||||
projectRootMap,
|
||||
nxJsonConfiguration,
|
||||
configurationSourceMaps
|
||||
@ -643,6 +649,7 @@ export function readProjectConfigurationsFromRootMap(
|
||||
}
|
||||
|
||||
function validateAndNormalizeProjectRootMap(
|
||||
workspaceRoot: string,
|
||||
projectRootMap: Record<string, ProjectConfiguration>,
|
||||
nxJsonConfiguration: NxJsonConfiguration,
|
||||
sourceMaps: ConfigurationSourceMaps = {}
|
||||
@ -678,7 +685,13 @@ function validateAndNormalizeProjectRootMap(
|
||||
}
|
||||
}
|
||||
|
||||
normalizeTargets(project, sourceMaps, nxJsonConfiguration);
|
||||
normalizeTargets(
|
||||
project,
|
||||
sourceMaps,
|
||||
nxJsonConfiguration,
|
||||
workspaceRoot,
|
||||
projects
|
||||
);
|
||||
}
|
||||
|
||||
if (conflicts.size > 0) {
|
||||
@ -693,12 +706,19 @@ function validateAndNormalizeProjectRootMap(
|
||||
function normalizeTargets(
|
||||
project: ProjectConfiguration,
|
||||
sourceMaps: ConfigurationSourceMaps,
|
||||
nxJsonConfiguration: NxJsonConfiguration<'*' | string[]>
|
||||
nxJsonConfiguration: NxJsonConfiguration,
|
||||
workspaceRoot: string,
|
||||
/**
|
||||
* Project configurations keyed by project name
|
||||
*/
|
||||
projects: Record<string, ProjectConfiguration>
|
||||
) {
|
||||
for (const targetName in project.targets) {
|
||||
project.targets[targetName] = normalizeTarget(
|
||||
project.targets[targetName],
|
||||
project
|
||||
project,
|
||||
workspaceRoot,
|
||||
projects
|
||||
);
|
||||
|
||||
const projectSourceMaps = sourceMaps[project.root];
|
||||
@ -717,7 +737,7 @@ function normalizeTargets(
|
||||
project.targets[targetName] = mergeTargetDefaultWithTargetDefinition(
|
||||
targetName,
|
||||
project,
|
||||
normalizeTarget(targetDefaults, project),
|
||||
normalizeTarget(targetDefaults, project, workspaceRoot, projects),
|
||||
projectSourceMaps
|
||||
);
|
||||
}
|
||||
@ -1161,14 +1181,16 @@ function resolveCommandSyntacticSugar(
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand's `command` syntactic sugar and replaces tokens in options.
|
||||
* Expand's `command` syntactic sugar, replaces tokens in options, and adds information from executor schema.
|
||||
* @param target The target to normalize
|
||||
* @param project The project that the target belongs to
|
||||
* @returns The normalized target configuration
|
||||
*/
|
||||
export function normalizeTarget(
|
||||
target: TargetConfiguration,
|
||||
project: ProjectConfiguration
|
||||
project: ProjectConfiguration,
|
||||
workspaceRoot: string,
|
||||
projectsMap: Record<string, ProjectConfiguration>
|
||||
) {
|
||||
target = {
|
||||
...target,
|
||||
@ -1195,5 +1217,26 @@ export function normalizeTarget(
|
||||
|
||||
target.parallelism ??= true;
|
||||
|
||||
if (target.executor && !('continuous' in target)) {
|
||||
try {
|
||||
const [executorNodeModule, executorName] = parseExecutor(target.executor);
|
||||
|
||||
const { schema } = getExecutorInformation(
|
||||
executorNodeModule,
|
||||
executorName,
|
||||
workspaceRoot,
|
||||
projectsMap
|
||||
);
|
||||
|
||||
if (schema.continuous) {
|
||||
target.continuous ??= schema.continuous;
|
||||
}
|
||||
} catch (e) {
|
||||
// If the executor is not found, we assume that it is not a valid executor.
|
||||
// This means that we should not set the continuous property.
|
||||
// We could throw an error here, but it would be better to just ignore it.
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
@ -12,7 +12,10 @@ import { ExecutorContext } from '../../config/misc-interfaces';
|
||||
import { readProjectsConfigurationFromProjectGraph } from '../../project-graph/project-graph';
|
||||
import { readNxJson } from '../../config/configuration';
|
||||
import { isAsyncIterator } from '../../utils/async-iterator';
|
||||
import { getExecutorInformation } from '../../command-line/run/executor-utils';
|
||||
import {
|
||||
getExecutorInformation,
|
||||
parseExecutor,
|
||||
} from '../../command-line/run/executor-utils';
|
||||
import { ProjectConfiguration } from '../../config/workspace-json-project-json';
|
||||
import { ProjectGraph } from '../../config/project-graph';
|
||||
|
||||
@ -20,7 +23,7 @@ function getBatchExecutor(
|
||||
executorName: string,
|
||||
projects: Record<string, ProjectConfiguration>
|
||||
) {
|
||||
const [nodeModule, exportName] = executorName.split(':');
|
||||
const [nodeModule, exportName] = parseExecutor(executorName);
|
||||
return getExecutorInformation(
|
||||
nodeModule,
|
||||
exportName,
|
||||
|
||||
@ -521,7 +521,7 @@ export function getNonDummyDeps(
|
||||
}
|
||||
}
|
||||
|
||||
export function createTaskId(
|
||||
function createTaskId(
|
||||
project: string,
|
||||
target: string,
|
||||
configuration: string | undefined
|
||||
|
||||
@ -40,7 +40,7 @@ import {
|
||||
processSyncGeneratorResultErrors,
|
||||
} from '../utils/sync-generators';
|
||||
import { workspaceRoot } from '../utils/workspace-root';
|
||||
import { createTaskGraph, createTaskId } from './create-task-graph';
|
||||
import { createTaskGraph } from './create-task-graph';
|
||||
import { isTuiEnabled } from './is-tui-enabled';
|
||||
import {
|
||||
CompositeLifeCycle,
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
import { minimatch } from 'minimatch';
|
||||
import { relative } from 'node:path';
|
||||
import { join } from 'node:path/posix';
|
||||
import { getExecutorInformation } from '../command-line/run/executor-utils';
|
||||
import {
|
||||
getExecutorInformation,
|
||||
parseExecutor,
|
||||
} from '../command-line/run/executor-utils';
|
||||
import { CustomHasher, ExecutorConfig } from '../config/misc-interfaces';
|
||||
import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph';
|
||||
import { Task, TaskGraph } from '../config/task-graph';
|
||||
@ -429,7 +432,7 @@ export function getExecutorForTask(
|
||||
projectGraph: ProjectGraph
|
||||
): ExecutorConfig & { isNgCompat: boolean; isNxExecutor: boolean } {
|
||||
const executor = getExecutorNameForTask(task, projectGraph);
|
||||
const [nodeModule, executorName] = executor.split(':');
|
||||
const [nodeModule, executorName] = parseExecutor(executor);
|
||||
|
||||
return getExecutorInformation(
|
||||
nodeModule,
|
||||
|
||||
@ -48,7 +48,12 @@ describe('readTargetsFromPackageJson', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const result1 = readTargetsFromPackageJson(packageJson, nxJson1);
|
||||
const result1 = readTargetsFromPackageJson(
|
||||
packageJson,
|
||||
nxJson1,
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
expect(result1['nx-release-publish']).toMatchInlineSnapshot(`
|
||||
{
|
||||
"dependsOn": [
|
||||
@ -69,7 +74,12 @@ describe('readTargetsFromPackageJson', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
const result2 = readTargetsFromPackageJson(packageJson, nxJson2);
|
||||
const result2 = readTargetsFromPackageJson(
|
||||
packageJson,
|
||||
nxJson2,
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
expect(result2['nx-release-publish']).toMatchInlineSnapshot(`
|
||||
{
|
||||
"dependsOn": [
|
||||
@ -83,7 +93,12 @@ describe('readTargetsFromPackageJson', () => {
|
||||
});
|
||||
|
||||
it('should read targets from project.json and package.json', () => {
|
||||
const result = readTargetsFromPackageJson(packageJson, {});
|
||||
const result = readTargetsFromPackageJson(
|
||||
packageJson,
|
||||
{},
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"build": {
|
||||
@ -123,7 +138,9 @@ describe('readTargetsFromPackageJson', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{}
|
||||
{},
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
expect(result).toEqual({
|
||||
build: { ...packageJsonBuildTarget, outputs: ['custom'] },
|
||||
@ -148,9 +165,10 @@ describe('readTargetsFromPackageJson', () => {
|
||||
includedScripts: ['test'],
|
||||
},
|
||||
},
|
||||
{}
|
||||
{},
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
{
|
||||
"nx-release-publish": {
|
||||
@ -190,7 +208,9 @@ describe('readTargetsFromPackageJson', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{}
|
||||
{},
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
expect(result.build).toMatchInlineSnapshot(`
|
||||
{
|
||||
@ -228,7 +248,9 @@ describe('readTargetsFromPackageJson', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{}
|
||||
{},
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
expect(result.build).toMatchInlineSnapshot(`
|
||||
{
|
||||
@ -261,7 +283,9 @@ describe('readTargetsFromPackageJson', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{}
|
||||
{},
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
expect(result.build).toMatchInlineSnapshot(`
|
||||
{
|
||||
@ -289,7 +313,9 @@ describe('readTargetsFromPackageJson', () => {
|
||||
},
|
||||
},
|
||||
},
|
||||
{}
|
||||
{},
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
expect(result.build).toMatchInlineSnapshot(`
|
||||
{
|
||||
@ -356,7 +382,9 @@ describe('readTargetsFromPackageJson', () => {
|
||||
includedScripts: [],
|
||||
},
|
||||
},
|
||||
{}
|
||||
{},
|
||||
workspaceRoot,
|
||||
'/root'
|
||||
);
|
||||
expect(result.test).toMatchInlineSnapshot(`
|
||||
{
|
||||
|
||||
@ -10,8 +10,8 @@ import { mergeTargetConfigurations } from '../project-graph/utils/project-config
|
||||
import { readJsonFile } from './fileutils';
|
||||
import { getNxRequirePaths } from './installation-directory';
|
||||
import {
|
||||
PackageManagerCommands,
|
||||
getPackageManagerCommand,
|
||||
PackageManagerCommands,
|
||||
} from './package-manager';
|
||||
|
||||
export interface NxProjectPackageJsonConfiguration
|
||||
@ -186,7 +186,9 @@ export function getTagsFromPackageJson(packageJson: PackageJson): string[] {
|
||||
|
||||
export function readTargetsFromPackageJson(
|
||||
packageJson: PackageJson,
|
||||
nxJson: NxJsonConfiguration
|
||||
nxJson: NxJsonConfiguration,
|
||||
projectRoot: string,
|
||||
workspaceRoot: string
|
||||
) {
|
||||
const { scripts, nx, private: isPrivate } = packageJson ?? {};
|
||||
const res: Record<string, TargetConfiguration> = {};
|
||||
@ -210,7 +212,11 @@ export function readTargetsFromPackageJson(
|
||||
* Any targetDefaults for the nx-release-publish target set by the user should
|
||||
* be merged with the implicit target.
|
||||
*/
|
||||
if (!isPrivate && !res['nx-release-publish']) {
|
||||
if (
|
||||
!isPrivate &&
|
||||
!res['nx-release-publish'] &&
|
||||
hasNxJsPlugin(projectRoot, workspaceRoot)
|
||||
) {
|
||||
const nxReleasePublishTargetDefaults =
|
||||
nxJson?.targetDefaults?.['nx-release-publish'] ?? {};
|
||||
res['nx-release-publish'] = {
|
||||
@ -230,6 +236,18 @@ export function readTargetsFromPackageJson(
|
||||
return res;
|
||||
}
|
||||
|
||||
function hasNxJsPlugin(projectRoot: string, workspaceRoot: string) {
|
||||
try {
|
||||
// nx-ignore-next-line
|
||||
require.resolve('@nx/js', {
|
||||
paths: [projectRoot, ...getNxRequirePaths(workspaceRoot), __dirname],
|
||||
});
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses `require.resolve` to read the package.json for a module.
|
||||
*
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation Dev Server",
|
||||
"description": "Serve a web application.",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation SSR Dev Server",
|
||||
"description": "Serve a SSR Consumer (host) application along with its known Producers (remotes).",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation Static Dev Server",
|
||||
"description": "Serve a Consumer (host) application statically along with its Producers (remotes).",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "pipe",
|
||||
"cli": "nx",
|
||||
"title": "Remix Serve",
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
"version": 2,
|
||||
"title": "Rspack dev-server executor",
|
||||
"description": "Run @rspack/dev-server to serve a project.",
|
||||
"continuous": true,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"buildTarget": {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Rspack Module Federation Dev Server",
|
||||
"description": "Serve a module federation application.",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation SSR Dev Server",
|
||||
"description": "Serve a SSR Consumer (host) application along with its known Producers (remotes).",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Module Federation Static Dev Server",
|
||||
"description": "Serve a Consumer (host) application statically along with it's Producers (remotes).",
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Rspack SSR Dev Server",
|
||||
"description": "Serve a SSR application using rspack.",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Storybook Dev Builder",
|
||||
"cli": "nx",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Vite Dev Server",
|
||||
"cli": "nx",
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
"cli": "nx",
|
||||
"title": "Vite Preview Server",
|
||||
"description": "Preview Server for Vite.",
|
||||
"continuous": true,
|
||||
"type": "object",
|
||||
"presets": [
|
||||
{
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "File Server",
|
||||
"description": "Serve a web application from a folder. This executor is a wrapper around the [http-server](https://www.npmjs.com/package/http-server) package.",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Webpack dev server",
|
||||
"description": "Serve an application using webpack.",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
{
|
||||
"version": 2,
|
||||
"continuous": true,
|
||||
"outputCapture": "direct-nodejs",
|
||||
"title": "Webpack SSR Dev Server",
|
||||
"description": "Serve a SSR application using webpack.",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user