fix(misc): register plugins correctly in migration generators (#26670)
<!-- 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 --> ## 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 NXP-816 --> Fixes #
This commit is contained in:
parent
8872ca5c8f
commit
c936f864b8
@ -495,33 +495,46 @@ describe('Cypress - Convert Executors To Plugin', () => {
|
||||
|
||||
// nx.json modifications
|
||||
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||
const addedTestCypressPlugin = nxJsonPlugins.find((plugin) => {
|
||||
if (
|
||||
typeof plugin !== 'string' &&
|
||||
plugin.plugin === '@nx/cypress/plugin' &&
|
||||
plugin.include?.length === 2
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
expect(addedTestCypressPlugin).toBeTruthy();
|
||||
expect(
|
||||
(addedTestCypressPlugin as ExpandedPluginConfiguration).include
|
||||
).toEqual(['myapp-e2e/**/*', 'second/**/*']);
|
||||
|
||||
const addedIntegrationCypressPlugin = nxJsonPlugins.find((plugin) => {
|
||||
if (
|
||||
typeof plugin !== 'string' &&
|
||||
plugin.plugin === '@nx/cypress/plugin' &&
|
||||
plugin.include?.length === 1
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
expect(addedIntegrationCypressPlugin).toBeTruthy();
|
||||
expect(
|
||||
(addedIntegrationCypressPlugin as ExpandedPluginConfiguration).include
|
||||
).toEqual(['third/**/*']);
|
||||
const addedCypressPlugins = nxJsonPlugins.filter(
|
||||
(plugin) =>
|
||||
typeof plugin !== 'string' && plugin.plugin === '@nx/cypress/plugin'
|
||||
);
|
||||
expect(addedCypressPlugins).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"options": {
|
||||
"ciTargetName": "e2e-ci",
|
||||
"targetName": "e2e",
|
||||
},
|
||||
"plugin": "@nx/cypress/plugin",
|
||||
},
|
||||
{
|
||||
"include": [
|
||||
"myapp-e2e/**/*",
|
||||
"second/**/*",
|
||||
],
|
||||
"options": {
|
||||
"ciTargetName": "e2e-ci",
|
||||
"componentTestingTargetName": "component-test",
|
||||
"openTargetName": "open-cypress",
|
||||
"targetName": "test",
|
||||
},
|
||||
"plugin": "@nx/cypress/plugin",
|
||||
},
|
||||
{
|
||||
"include": [
|
||||
"third/**/*",
|
||||
],
|
||||
"options": {
|
||||
"ciTargetName": "e2e-ci",
|
||||
"componentTestingTargetName": "component-test",
|
||||
"openTargetName": "open-cypress",
|
||||
"targetName": "integration",
|
||||
},
|
||||
"plugin": "@nx/cypress/plugin",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
it('should keep Cypress options in project.json', async () => {
|
||||
|
||||
@ -4,16 +4,16 @@ import {
|
||||
type TargetConfiguration,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { createNodesV2 } from '../../plugins/plugin';
|
||||
import { targetOptionsToCliMap } from './lib/target-options-map';
|
||||
import { upsertBaseUrl } from './lib/upsert-baseUrl';
|
||||
import { addDevServerTargetToConfig } from './lib/add-dev-server-target-to-config';
|
||||
import { addExcludeSpecPattern } from './lib/add-exclude-spec-pattern';
|
||||
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import {
|
||||
processTargetOutputs,
|
||||
toProjectRelativePath,
|
||||
} from '@nx/devkit/src/generators/plugin-migrations/plugin-migration-utils';
|
||||
import { createNodesV2, type CypressPluginOptions } from '../../plugins/plugin';
|
||||
import { addDevServerTargetToConfig } from './lib/add-dev-server-target-to-config';
|
||||
import { addExcludeSpecPattern } from './lib/add-exclude-spec-pattern';
|
||||
import { targetOptionsToCliMap } from './lib/target-options-map';
|
||||
import { upsertBaseUrl } from './lib/upsert-baseUrl';
|
||||
|
||||
interface Schema {
|
||||
project?: string;
|
||||
@ -23,38 +23,29 @@ interface Schema {
|
||||
|
||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||
const projectGraph = await createProjectGraphAsync();
|
||||
const migratedProjectsModern = await migrateExecutorToPlugin(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/cypress:cypress',
|
||||
'@nx/cypress/plugin',
|
||||
(targetName) => ({
|
||||
targetName,
|
||||
ciTargetName: 'e2e-ci',
|
||||
}),
|
||||
postTargetTransformer,
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedProjectsLegacy = await migrateExecutorToPlugin(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nrwl/cypress:cypress',
|
||||
'@nx/cypress/plugin',
|
||||
(targetName) => ({
|
||||
targetName,
|
||||
ciTargetName: 'e2e-ci',
|
||||
}),
|
||||
postTargetTransformer,
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedProjects =
|
||||
migratedProjectsModern.size + migratedProjectsLegacy.size;
|
||||
await migrateProjectExecutorsToPlugin<CypressPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/cypress/plugin',
|
||||
createNodesV2,
|
||||
{
|
||||
targetName: 'cypress',
|
||||
ciTargetName: 'e2e-ci',
|
||||
componentTestingTargetName: 'component-test',
|
||||
openTargetName: 'open-cypress',
|
||||
},
|
||||
[
|
||||
{
|
||||
executors: ['@nx/cypress:cypress', '@nrwl/cypress:cypress'],
|
||||
postTargetTransformer,
|
||||
targetPluginOptionMapper: (targetName) => ({ targetName }),
|
||||
},
|
||||
],
|
||||
options.project
|
||||
);
|
||||
|
||||
if (migratedProjects === 0) {
|
||||
if (migratedProjects.size === 0) {
|
||||
throw new Error('Could not find any targets to migrate.');
|
||||
}
|
||||
|
||||
|
||||
@ -1,36 +1,32 @@
|
||||
import type { RunCommandsOptions } from 'nx/src/executors/run-commands/run-commands.impl';
|
||||
|
||||
import { minimatch } from 'minimatch';
|
||||
import { deepStrictEqual } from 'node:assert';
|
||||
|
||||
import { forEachExecutorOptions } from '../executor-options-utils';
|
||||
import { deleteMatchingProperties } from './plugin-migration-utils';
|
||||
|
||||
import {
|
||||
readNxJson,
|
||||
updateNxJson,
|
||||
updateProjectConfiguration,
|
||||
readProjectConfiguration,
|
||||
ProjectGraph,
|
||||
ExpandedPluginConfiguration,
|
||||
NxJsonConfiguration,
|
||||
TargetConfiguration,
|
||||
Tree,
|
||||
CreateNodes,
|
||||
CreateNodesV2,
|
||||
} from 'nx/src/devkit-exports';
|
||||
|
||||
import {
|
||||
mergeTargetConfigurations,
|
||||
retrieveProjectConfigurations,
|
||||
LoadedNxPlugin,
|
||||
ProjectConfigurationsError,
|
||||
} from 'nx/src/devkit-internals';
|
||||
import type { ConfigurationResult } from 'nx/src/project-graph/utils/project-configuration-utils';
|
||||
import type {
|
||||
InputDefinition,
|
||||
ProjectConfiguration,
|
||||
} from 'nx/src/config/workspace-json-project-json';
|
||||
import {
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
updateNxJson,
|
||||
updateProjectConfiguration,
|
||||
type CreateNodes,
|
||||
type CreateNodesV2,
|
||||
type ExpandedPluginConfiguration,
|
||||
type NxJsonConfiguration,
|
||||
type ProjectGraph,
|
||||
type TargetConfiguration,
|
||||
type Tree,
|
||||
} from 'nx/src/devkit-exports';
|
||||
import {
|
||||
LoadedNxPlugin,
|
||||
ProjectConfigurationsError,
|
||||
mergeTargetConfigurations,
|
||||
retrieveProjectConfigurations,
|
||||
} from 'nx/src/devkit-internals';
|
||||
import type { RunCommandsOptions } from 'nx/src/executors/run-commands/run-commands.impl';
|
||||
import type { ConfigurationResult } from 'nx/src/project-graph/utils/project-configuration-utils';
|
||||
import { forEachExecutorOptions } from '../executor-options-utils';
|
||||
import { deleteMatchingProperties } from './plugin-migration-utils';
|
||||
|
||||
type PluginOptionsBuilder<T> = (targetName: string) => T;
|
||||
type PostTargetTransformer = (
|
||||
@ -100,7 +96,6 @@ class ExecutorToPluginMigrator<T> {
|
||||
for (const targetName of this.#targetAndProjectsToMigrate.keys()) {
|
||||
await this.#migrateTarget(targetName);
|
||||
}
|
||||
await this.#addPlugins();
|
||||
}
|
||||
return this.#targetAndProjectsToMigrate;
|
||||
}
|
||||
@ -235,91 +230,6 @@ class ExecutorToPluginMigrator<T> {
|
||||
}
|
||||
}
|
||||
|
||||
async #pluginRequiresIncludes(
|
||||
targetName: string,
|
||||
plugin: ExpandedPluginConfiguration<T>
|
||||
) {
|
||||
const loadedPlugin = new LoadedNxPlugin(
|
||||
{
|
||||
createNodesV2: this.#createNodesV2,
|
||||
createNodes: this.#createNodes,
|
||||
name: this.#pluginPath,
|
||||
},
|
||||
plugin
|
||||
);
|
||||
|
||||
const originalResults = this.#createNodesResultsForTargets.get(targetName);
|
||||
|
||||
let resultsWithIncludes: ConfigurationResult;
|
||||
try {
|
||||
resultsWithIncludes = await retrieveProjectConfigurations(
|
||||
[loadedPlugin],
|
||||
this.tree.root,
|
||||
this.#nxJson
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof ProjectConfigurationsError) {
|
||||
resultsWithIncludes = e.partialProjectConfigurationsResult;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return !deepEqual(originalResults, resultsWithIncludes);
|
||||
}
|
||||
|
||||
async #addPlugins() {
|
||||
for (const [targetName, plugin] of this.#pluginToAddForTarget.entries()) {
|
||||
const pluginOptions = this.#pluginOptionsBuilder(targetName);
|
||||
|
||||
const existingPlugin = this.#nxJson.plugins.find(
|
||||
(plugin: ExpandedPluginConfiguration<T>) => {
|
||||
if (
|
||||
typeof plugin === 'string' ||
|
||||
plugin.plugin !== this.#pluginPath
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const key in plugin.options) {
|
||||
if (plugin.options[key] !== pluginOptions[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
) as ExpandedPluginConfiguration<T>;
|
||||
|
||||
if (existingPlugin?.include) {
|
||||
// Add to the existing plugin includes
|
||||
existingPlugin.include = existingPlugin.include.concat(
|
||||
// Any include that is in the new plugin's include list
|
||||
plugin.include.filter(
|
||||
(projectPath) =>
|
||||
// And is not already covered by the existing plugin's include list
|
||||
!existingPlugin.include.some((pluginIncludes) =>
|
||||
minimatch(projectPath, pluginIncludes, { dot: true })
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if (!(await this.#pluginRequiresIncludes(targetName, existingPlugin))) {
|
||||
delete existingPlugin.include;
|
||||
}
|
||||
}
|
||||
|
||||
if (!existingPlugin) {
|
||||
if (!(await this.#pluginRequiresIncludes(targetName, plugin))) {
|
||||
plugin.include = undefined;
|
||||
}
|
||||
this.#nxJson.plugins.push(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
updateNxJson(this.tree, this.#nxJson);
|
||||
}
|
||||
|
||||
#getTargetAndProjectsToMigrate() {
|
||||
forEachExecutorOptions(
|
||||
this.tree,
|
||||
@ -403,96 +313,289 @@ class ExecutorToPluginMigrator<T> {
|
||||
}
|
||||
|
||||
global.NX_GRAPH_CREATION = true;
|
||||
for (const targetName of this.#targetAndProjectsToMigrate.keys()) {
|
||||
const loadedPlugin = new LoadedNxPlugin(
|
||||
{
|
||||
createNodesV2: this.#createNodesV2,
|
||||
createNodes: this.#createNodes,
|
||||
name: this.#pluginPath,
|
||||
},
|
||||
{
|
||||
plugin: this.#pluginPath,
|
||||
options: this.#pluginOptionsBuilder(targetName),
|
||||
}
|
||||
);
|
||||
let projectConfigs: ConfigurationResult;
|
||||
try {
|
||||
projectConfigs = await retrieveProjectConfigurations(
|
||||
[loadedPlugin],
|
||||
this.tree.root,
|
||||
try {
|
||||
for (const targetName of this.#targetAndProjectsToMigrate.keys()) {
|
||||
const result = await getCreateNodesResultsForPlugin(
|
||||
this.tree,
|
||||
{
|
||||
plugin: this.#pluginPath,
|
||||
options: this.#pluginOptionsBuilder(targetName),
|
||||
},
|
||||
this.#pluginPath,
|
||||
this.#createNodes,
|
||||
this.#createNodesV2,
|
||||
this.#nxJson
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof ProjectConfigurationsError) {
|
||||
projectConfigs = e.partialProjectConfigurationsResult;
|
||||
} else {
|
||||
global.NX_GRAPH_CREATION = false;
|
||||
throw e;
|
||||
this.#createNodesResultsForTargets.set(targetName, result);
|
||||
}
|
||||
} finally {
|
||||
global.NX_GRAPH_CREATION = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function migrateProjectExecutorsToPlugin<T>(
|
||||
tree: Tree,
|
||||
projectGraph: ProjectGraph,
|
||||
pluginPath: string,
|
||||
createNodesV2: CreateNodesV2<T>,
|
||||
defaultPluginOptions: T,
|
||||
migrations: Array<{
|
||||
executors: string[];
|
||||
targetPluginOptionMapper: (targetName: string) => Partial<T>;
|
||||
postTargetTransformer: PostTargetTransformer;
|
||||
skipProjectFilter?: SkipProjectFilter;
|
||||
skipTargetFilter?: SkipTargetFilter;
|
||||
}>,
|
||||
specificProjectToMigrate?: string
|
||||
): Promise<Map<string, Record<string, string>>> {
|
||||
const projects = await migrateProjects(
|
||||
tree,
|
||||
projectGraph,
|
||||
pluginPath,
|
||||
undefined,
|
||||
createNodesV2,
|
||||
defaultPluginOptions,
|
||||
migrations,
|
||||
specificProjectToMigrate
|
||||
);
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
export async function migrateProjectExecutorsToPluginV1<T>(
|
||||
tree: Tree,
|
||||
projectGraph: ProjectGraph,
|
||||
pluginPath: string,
|
||||
createNodes: CreateNodes<T>,
|
||||
defaultPluginOptions: T,
|
||||
migrations: Array<{
|
||||
executors: string[];
|
||||
targetPluginOptionMapper: (targetName: string) => Partial<T>;
|
||||
postTargetTransformer: PostTargetTransformer;
|
||||
skipProjectFilter?: SkipProjectFilter;
|
||||
skipTargetFilter?: SkipTargetFilter;
|
||||
}>,
|
||||
specificProjectToMigrate?: string
|
||||
): Promise<Map<string, Record<string, string>>> {
|
||||
const projects = await migrateProjects(
|
||||
tree,
|
||||
projectGraph,
|
||||
pluginPath,
|
||||
createNodes,
|
||||
undefined,
|
||||
defaultPluginOptions,
|
||||
migrations,
|
||||
specificProjectToMigrate
|
||||
);
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
async function migrateProjects<T>(
|
||||
tree: Tree,
|
||||
projectGraph: ProjectGraph,
|
||||
pluginPath: string,
|
||||
createNodes: CreateNodes<T>,
|
||||
createNodesV2: CreateNodesV2<T>,
|
||||
defaultPluginOptions: T,
|
||||
migrations: Array<{
|
||||
executors: string[];
|
||||
targetPluginOptionMapper: (targetName: string) => Partial<T>;
|
||||
postTargetTransformer: PostTargetTransformer;
|
||||
skipProjectFilter?: SkipProjectFilter;
|
||||
skipTargetFilter?: SkipTargetFilter;
|
||||
}>,
|
||||
specificProjectToMigrate?: string
|
||||
): Promise<Map<string, Record<string, string>>> {
|
||||
const projects = new Map<string, Record<string, string>>();
|
||||
|
||||
for (const migration of migrations) {
|
||||
for (const executor of migration.executors) {
|
||||
const migrator = new ExecutorToPluginMigrator(
|
||||
tree,
|
||||
projectGraph,
|
||||
executor,
|
||||
pluginPath,
|
||||
migration.targetPluginOptionMapper,
|
||||
migration.postTargetTransformer,
|
||||
createNodes,
|
||||
createNodesV2,
|
||||
specificProjectToMigrate,
|
||||
{
|
||||
skipProjectFilter: migration.skipProjectFilter,
|
||||
skipTargetFilter: migration.skipTargetFilter,
|
||||
}
|
||||
);
|
||||
|
||||
const result = await migrator.run();
|
||||
|
||||
// invert the result to have a map of projects to their targets
|
||||
for (const [target, projectList] of result.entries()) {
|
||||
for (const project of projectList) {
|
||||
if (!projects.has(project)) {
|
||||
projects.set(project, {});
|
||||
}
|
||||
|
||||
projects.set(project, {
|
||||
...projects.get(project),
|
||||
...migration.targetPluginOptionMapper(target),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.#createNodesResultsForTargets.set(targetName, projectConfigs);
|
||||
}
|
||||
}
|
||||
|
||||
// apply default options
|
||||
for (const [project, pluginOptions] of projects.entries()) {
|
||||
projects.set(project, {
|
||||
...defaultPluginOptions,
|
||||
...pluginOptions,
|
||||
});
|
||||
}
|
||||
|
||||
await addPluginRegistrations(
|
||||
tree,
|
||||
projects,
|
||||
pluginPath,
|
||||
createNodes,
|
||||
createNodesV2,
|
||||
defaultPluginOptions,
|
||||
projectGraph
|
||||
);
|
||||
|
||||
return projects;
|
||||
}
|
||||
|
||||
async function addPluginRegistrations<T>(
|
||||
tree: Tree,
|
||||
projects: Map<string, Record<string, string>>,
|
||||
pluginPath: string,
|
||||
createNodes: CreateNodes | undefined,
|
||||
createNodesV2: CreateNodesV2 | undefined,
|
||||
defaultPluginOptions: T,
|
||||
projectGraph: ProjectGraph
|
||||
) {
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
// collect createNodes results for each project before adding the plugins
|
||||
const createNodesResults = new Map<string, ConfigurationResult>();
|
||||
global.NX_GRAPH_CREATION = true;
|
||||
try {
|
||||
for (const [project, options] of projects.entries()) {
|
||||
const projectConfigs = await getCreateNodesResultsForPlugin(
|
||||
tree,
|
||||
{ plugin: pluginPath, options },
|
||||
pluginPath,
|
||||
createNodes,
|
||||
createNodesV2,
|
||||
nxJson
|
||||
);
|
||||
|
||||
createNodesResults.set(project, projectConfigs);
|
||||
}
|
||||
} finally {
|
||||
global.NX_GRAPH_CREATION = false;
|
||||
}
|
||||
|
||||
const arePluginIncludesRequired = async (
|
||||
project: string,
|
||||
pluginConfiguration: ExpandedPluginConfiguration
|
||||
): Promise<boolean> => {
|
||||
global.NX_GRAPH_CREATION = true;
|
||||
let result: ConfigurationResult;
|
||||
try {
|
||||
result = await getCreateNodesResultsForPlugin(
|
||||
tree,
|
||||
pluginConfiguration,
|
||||
pluginPath,
|
||||
createNodes,
|
||||
createNodesV2,
|
||||
nxJson
|
||||
);
|
||||
} finally {
|
||||
global.NX_GRAPH_CREATION = false;
|
||||
}
|
||||
|
||||
const originalResults = createNodesResults.get(project);
|
||||
|
||||
return !deepEqual(originalResults, result);
|
||||
};
|
||||
|
||||
for (const [project, options] of projects.entries()) {
|
||||
const existingPlugin = nxJson.plugins?.find(
|
||||
(plugin): plugin is ExpandedPluginConfiguration =>
|
||||
typeof plugin !== 'string' &&
|
||||
plugin.plugin === pluginPath &&
|
||||
Object.keys(options).every(
|
||||
(key) =>
|
||||
plugin.options[key] === options[key] ||
|
||||
(plugin.options[key] === undefined &&
|
||||
options[key] === defaultPluginOptions[key])
|
||||
)
|
||||
);
|
||||
|
||||
const projectIncludeGlob = `${projectGraph.nodes[project].data.root}/**/*`;
|
||||
if (!existingPlugin) {
|
||||
nxJson.plugins ??= [];
|
||||
const plugin: ExpandedPluginConfiguration = {
|
||||
plugin: pluginPath,
|
||||
options,
|
||||
include: [projectIncludeGlob],
|
||||
};
|
||||
|
||||
if (!(await arePluginIncludesRequired(project, plugin))) {
|
||||
delete plugin.include;
|
||||
}
|
||||
|
||||
nxJson.plugins.push(plugin);
|
||||
} else if (existingPlugin.include) {
|
||||
if (
|
||||
!existingPlugin.include.some((include) =>
|
||||
minimatch(projectIncludeGlob, include, { dot: true })
|
||||
)
|
||||
) {
|
||||
existingPlugin.include.push(projectIncludeGlob);
|
||||
|
||||
if (!(await arePluginIncludesRequired(project, existingPlugin))) {
|
||||
delete existingPlugin.include;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
|
||||
export async function migrateExecutorToPlugin<T>(
|
||||
async function getCreateNodesResultsForPlugin(
|
||||
tree: Tree,
|
||||
projectGraph: ProjectGraph,
|
||||
executor: string,
|
||||
pluginConfiguration: ExpandedPluginConfiguration,
|
||||
pluginPath: string,
|
||||
pluginOptionsBuilder: PluginOptionsBuilder<T>,
|
||||
postTargetTransformer: PostTargetTransformer,
|
||||
createNodes: CreateNodesV2<T>,
|
||||
specificProjectToMigrate?: string,
|
||||
filters?: {
|
||||
skipProjectFilter?: SkipProjectFilter;
|
||||
skipTargetFilter?: SkipTargetFilter;
|
||||
}
|
||||
): Promise<Map<string, Set<string>>> {
|
||||
const migrator = new ExecutorToPluginMigrator<T>(
|
||||
tree,
|
||||
projectGraph,
|
||||
executor,
|
||||
pluginPath,
|
||||
pluginOptionsBuilder,
|
||||
postTargetTransformer,
|
||||
undefined,
|
||||
createNodes,
|
||||
specificProjectToMigrate,
|
||||
filters
|
||||
);
|
||||
return await migrator.run();
|
||||
}
|
||||
createNodes: CreateNodes | undefined,
|
||||
createNodesV2: CreateNodesV2 | undefined,
|
||||
nxJson: NxJsonConfiguration
|
||||
): Promise<ConfigurationResult> {
|
||||
let projectConfigs: ConfigurationResult;
|
||||
|
||||
export async function migrateExecutorToPluginV1<T>(
|
||||
tree: Tree,
|
||||
projectGraph: ProjectGraph,
|
||||
executor: string,
|
||||
pluginPath: string,
|
||||
pluginOptionsBuilder: PluginOptionsBuilder<T>,
|
||||
postTargetTransformer: PostTargetTransformer,
|
||||
createNodes: CreateNodes<T>,
|
||||
specificProjectToMigrate?: string,
|
||||
filters?: {
|
||||
skipProjectFilter?: SkipProjectFilter;
|
||||
skipTargetFilter?: SkipTargetFilter;
|
||||
try {
|
||||
const plugin = new LoadedNxPlugin(
|
||||
{ createNodes, createNodesV2, name: pluginPath },
|
||||
pluginConfiguration
|
||||
);
|
||||
projectConfigs = await retrieveProjectConfigurations(
|
||||
[plugin],
|
||||
tree.root,
|
||||
nxJson
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof ProjectConfigurationsError) {
|
||||
projectConfigs = e.partialProjectConfigurationsResult;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
): Promise<Map<string, Set<string>>> {
|
||||
const migrator = new ExecutorToPluginMigrator<T>(
|
||||
tree,
|
||||
projectGraph,
|
||||
executor,
|
||||
pluginPath,
|
||||
pluginOptionsBuilder,
|
||||
postTargetTransformer,
|
||||
createNodes,
|
||||
undefined,
|
||||
specificProjectToMigrate,
|
||||
filters
|
||||
);
|
||||
return await migrator.run();
|
||||
|
||||
return projectConfigs;
|
||||
}
|
||||
|
||||
// Checks if two objects are structurely equal, without caring
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { createNodesV2, EslintPluginOptions } from '../../plugins/plugin';
|
||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { targetOptionsToCliMap } from './lib/target-options-map';
|
||||
import { interpolate } from 'nx/src/tasks-runner/utils';
|
||||
import {
|
||||
@ -22,33 +22,24 @@ interface Schema {
|
||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||
const projectGraph = await createProjectGraphAsync();
|
||||
|
||||
const migratedProjectsModern =
|
||||
await migrateExecutorToPlugin<EslintPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/eslint:lint',
|
||||
'@nx/eslint/plugin',
|
||||
(targetName) => ({ targetName }),
|
||||
postTargetTransformer,
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedProjectsLegacy =
|
||||
await migrateExecutorToPlugin<EslintPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nrwl/linter:eslint',
|
||||
'@nx/eslint/plugin',
|
||||
(targetName) => ({ targetName }),
|
||||
postTargetTransformer,
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedProjects =
|
||||
migratedProjectsModern.size + migratedProjectsLegacy.size;
|
||||
if (migratedProjects === 0) {
|
||||
await migrateProjectExecutorsToPlugin<EslintPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/eslint/plugin',
|
||||
createNodesV2,
|
||||
{ targetName: 'lint' },
|
||||
[
|
||||
{
|
||||
executors: ['@nx/eslint:lint', '@nrwl/linter:eslint'],
|
||||
postTargetTransformer,
|
||||
targetPluginOptionMapper: (targetName) => ({ targetName }),
|
||||
},
|
||||
],
|
||||
options.project
|
||||
);
|
||||
|
||||
if (migratedProjects.size === 0) {
|
||||
throw new Error('Could not find any targets to migrate.');
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import {
|
||||
type TargetConfiguration,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import {
|
||||
processTargetOutputs,
|
||||
toProjectRelativePath,
|
||||
@ -22,34 +22,24 @@ interface Schema {
|
||||
|
||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||
const projectGraph = await createProjectGraphAsync();
|
||||
const migratedProjectsModern =
|
||||
await migrateExecutorToPlugin<JestPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/jest:jest',
|
||||
'@nx/jest/plugin',
|
||||
(targetName) => ({ targetName }),
|
||||
postTargetTransformer,
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedProjectsLegacy =
|
||||
await migrateExecutorToPlugin<JestPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nrwl/jest:jest',
|
||||
'@nx/jest/plugin',
|
||||
(targetName) => ({ targetName }),
|
||||
postTargetTransformer,
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedProjects =
|
||||
migratedProjectsModern.size + migratedProjectsLegacy.size;
|
||||
await migrateProjectExecutorsToPlugin<JestPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/jest/plugin',
|
||||
createNodesV2,
|
||||
{ targetName: 'test' },
|
||||
[
|
||||
{
|
||||
executors: ['@nx/jest:jest', '@nrwl/jest:jest'],
|
||||
postTargetTransformer,
|
||||
targetPluginOptionMapper: (targetName) => ({ targetName }),
|
||||
},
|
||||
],
|
||||
options.project
|
||||
);
|
||||
|
||||
if (migratedProjects === 0) {
|
||||
if (migratedProjects.size === 0) {
|
||||
throw new Error('Could not find any targets to migrate.');
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { createNodesV2, PlaywrightPluginOptions } from '../../plugins/plugin';
|
||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
|
||||
interface Schema {
|
||||
project?: string;
|
||||
@ -17,14 +17,19 @@ interface Schema {
|
||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||
const projectGraph = await createProjectGraphAsync();
|
||||
const migratedProjects =
|
||||
await migrateExecutorToPlugin<PlaywrightPluginOptions>(
|
||||
await migrateProjectExecutorsToPlugin<PlaywrightPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/playwright:playwright',
|
||||
'@nx/playwright/plugin',
|
||||
(targetName) => ({ targetName, ciTargetName: 'e2e-ci' }),
|
||||
postTargetTransformer,
|
||||
createNodesV2,
|
||||
{ targetName: 'e2e', ciTargetName: 'e2e-ci' },
|
||||
[
|
||||
{
|
||||
executors: ['@nx/playwright:playwright'],
|
||||
postTargetTransformer,
|
||||
targetPluginOptionMapper: (targetName) => ({ targetName }),
|
||||
},
|
||||
],
|
||||
options.project
|
||||
);
|
||||
|
||||
|
||||
@ -239,7 +239,7 @@ describe('Remix - Convert To Inferred', () => {
|
||||
plugin: '@nx/remix/plugin',
|
||||
options: {
|
||||
buildTargetName: 'build',
|
||||
devTargetName: defaultTestProjectOptions.serveTargetName,
|
||||
devTargetName: 'custom-dev',
|
||||
startTargetName: 'start',
|
||||
typecheckTargetName: 'typecheck',
|
||||
staticServeTargetName: 'static-serve',
|
||||
|
||||
@ -1,15 +1,9 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
createProjectGraphAsync,
|
||||
formatFiles,
|
||||
runTasksInSerial,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { createProjectGraphAsync, formatFiles, type Tree } from '@nx/devkit';
|
||||
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
|
||||
import { migrateExecutorToPluginV1 } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { migrateProjectExecutorsToPluginV1 } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { createNodes } from '../../plugins/plugin';
|
||||
import { buildPostTargetTransformer } from './lib/build-post-target-transformer';
|
||||
import { servePostTargetTransformer } from './lib/serve-post-target-transformer';
|
||||
import { createNodes } from '../../plugins/plugin';
|
||||
|
||||
interface Schema {
|
||||
project?: string;
|
||||
@ -19,43 +13,38 @@ interface Schema {
|
||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||
const projectGraph = await createProjectGraphAsync();
|
||||
const migrationLogs = new AggregatedLog();
|
||||
const migratedBuildProjects = await migrateExecutorToPluginV1(
|
||||
const migratedProjects = await migrateProjectExecutorsToPluginV1(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/remix:build',
|
||||
'@nx/remix/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: targetName,
|
||||
createNodes,
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
devTargetName: 'dev',
|
||||
startTargetName: 'start',
|
||||
typecheckTargetName: 'typecheck',
|
||||
staticServeTargetName: 'static-serve',
|
||||
}),
|
||||
buildPostTargetTransformer(migrationLogs),
|
||||
createNodes,
|
||||
typecheckTargetName: 'typecheck',
|
||||
},
|
||||
[
|
||||
{
|
||||
executors: ['@nx/remix:build'],
|
||||
postTargetTransformer: buildPostTargetTransformer(migrationLogs),
|
||||
targetPluginOptionMapper: (targetName) => ({
|
||||
buildTargetName: targetName,
|
||||
}),
|
||||
},
|
||||
{
|
||||
executors: ['@nx/remix:serve'],
|
||||
postTargetTransformer: servePostTargetTransformer(migrationLogs),
|
||||
targetPluginOptionMapper: (targetName) => ({
|
||||
devTargetName: targetName,
|
||||
}),
|
||||
},
|
||||
],
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedServeProjects = await migrateExecutorToPluginV1(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/remix:serve',
|
||||
'@nx/remix/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: 'build',
|
||||
devTargetName: targetName,
|
||||
startTargetName: 'start',
|
||||
typecheckTargetName: 'typecheck',
|
||||
staticServeTargetName: 'static-serve',
|
||||
}),
|
||||
servePostTargetTransformer(migrationLogs),
|
||||
createNodes,
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedProjects =
|
||||
migratedBuildProjects.size + migratedServeProjects.size;
|
||||
if (migratedProjects === 0) {
|
||||
if (migratedProjects.size === 0) {
|
||||
throw new Error('Could not find any targets to migrate.');
|
||||
}
|
||||
|
||||
|
||||
@ -287,8 +287,8 @@ describe('Storybook - Convert To Inferred', () => {
|
||||
nxJson.plugins.push({
|
||||
plugin: '@nx/storybook/plugin',
|
||||
options: {
|
||||
buildTargetName: 'storybook-build',
|
||||
serveTargetName: defaultTestProjectOptions.serveTargetName,
|
||||
buildStorybookTargetName: 'storybook-build',
|
||||
serveStorybookTargetName: 'custom-storybook',
|
||||
staticStorybookTargetName: 'static-storybook',
|
||||
testStorybookTargetName: 'test-storybook',
|
||||
},
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
|
||||
import { migrateExecutorToPluginV1 } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { migrateProjectExecutorsToPluginV1 } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { buildPostTargetTransformer } from './lib/build-post-target-transformer';
|
||||
import { servePostTargetTransformer } from './lib/serve-post-target-transformer';
|
||||
import { createNodes } from '../../plugins/plugin';
|
||||
@ -20,41 +20,37 @@ interface Schema {
|
||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||
const projectGraph = await createProjectGraphAsync();
|
||||
const migrationLogs = new AggregatedLog();
|
||||
const migratedBuildProjects = await migrateExecutorToPluginV1(
|
||||
const migratedProjects = await migrateProjectExecutorsToPluginV1(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/storybook:build',
|
||||
'@nx/storybook/plugin',
|
||||
(targetName) => ({
|
||||
buildStorybookTargetName: targetName,
|
||||
createNodes,
|
||||
{
|
||||
buildStorybookTargetName: 'build-storybook',
|
||||
serveStorybookTargetName: 'storybook',
|
||||
staticStorybookTargetName: 'static-storybook',
|
||||
testStorybookTargetName: 'test-storybook',
|
||||
}),
|
||||
buildPostTargetTransformer(migrationLogs),
|
||||
createNodes,
|
||||
},
|
||||
[
|
||||
{
|
||||
executors: ['@nx/storybook:build', '@nrwl/storybook:build'],
|
||||
postTargetTransformer: buildPostTargetTransformer(migrationLogs),
|
||||
targetPluginOptionMapper: (targetName) => ({
|
||||
buildStorybookTargetName: targetName,
|
||||
}),
|
||||
},
|
||||
{
|
||||
executors: ['@nx/storybook:storybook', '@nrwl/storybook:storybook'],
|
||||
postTargetTransformer: servePostTargetTransformer(migrationLogs),
|
||||
targetPluginOptionMapper: (targetName) => ({
|
||||
serveStorybookTargetName: targetName,
|
||||
}),
|
||||
},
|
||||
],
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedServeProjects = await migrateExecutorToPluginV1(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/storybook:storybook',
|
||||
'@nx/storybook/plugin',
|
||||
(targetName) => ({
|
||||
buildStorybookTargetName: 'build-storybook',
|
||||
serveStorybookTargetName: targetName,
|
||||
staticStorybookTargetName: 'static-storybook',
|
||||
testStorybookTargetName: 'test-storybook',
|
||||
}),
|
||||
servePostTargetTransformer(migrationLogs),
|
||||
createNodes,
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedProjects =
|
||||
migratedBuildProjects.size + migratedServeProjects.size;
|
||||
if (migratedProjects === 0) {
|
||||
if (migratedProjects.size === 0) {
|
||||
throw new Error('Could not find any targets to migrate.');
|
||||
}
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import { TempFs } from '@nx/devkit/internal-testing-utils';
|
||||
import { join } from 'node:path';
|
||||
import type { VitePluginOptions } from '../../plugins/plugin';
|
||||
|
||||
let fs: TempFs;
|
||||
|
||||
@ -514,33 +515,116 @@ describe('Vite - Convert Executors To Plugin', () => {
|
||||
|
||||
// nx.json modifications
|
||||
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||
const addedTestVitePlugin = nxJsonPlugins.find((plugin) => {
|
||||
if (
|
||||
typeof plugin !== 'string' &&
|
||||
plugin.plugin === '@nx/vite/plugin' &&
|
||||
plugin.include?.length === 2
|
||||
) {
|
||||
const addedVitePlugins = nxJsonPlugins.filter((plugin) => {
|
||||
if (typeof plugin !== 'string' && plugin.plugin === '@nx/vite/plugin') {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
expect(addedTestVitePlugin).toBeTruthy();
|
||||
expect(
|
||||
(addedTestVitePlugin as ExpandedPluginConfiguration).include
|
||||
).toEqual(['myapp/**/*', 'second/**/*']);
|
||||
expect(addedVitePlugins).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"options": {
|
||||
"buildTargetName": "build",
|
||||
"previewTargetName": "preview",
|
||||
"serveTargetName": "serve",
|
||||
"testTargetName": "test",
|
||||
},
|
||||
"plugin": "@nx/vite/plugin",
|
||||
},
|
||||
{
|
||||
"include": [
|
||||
"myapp/**/*",
|
||||
"second/**/*",
|
||||
],
|
||||
"options": {
|
||||
"buildTargetName": "bundle",
|
||||
"previewTargetName": "preview",
|
||||
"serveStaticTargetName": "serve-static",
|
||||
"serveTargetName": "serve",
|
||||
"testTargetName": "test",
|
||||
},
|
||||
"plugin": "@nx/vite/plugin",
|
||||
},
|
||||
{
|
||||
"include": [
|
||||
"third/**/*",
|
||||
],
|
||||
"options": {
|
||||
"buildTargetName": "build-base",
|
||||
"previewTargetName": "preview",
|
||||
"serveStaticTargetName": "serve-static",
|
||||
"serveTargetName": "serve",
|
||||
"testTargetName": "test",
|
||||
},
|
||||
"plugin": "@nx/vite/plugin",
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
const addedIntegrationVitePlugin = nxJsonPlugins.find((plugin) => {
|
||||
if (
|
||||
typeof plugin !== 'string' &&
|
||||
plugin.plugin === '@nx/vite/plugin' &&
|
||||
plugin.include?.length === 1
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
it('should handle multiple different target names for the same project', async () => {
|
||||
const project1 = createTestProject(tree);
|
||||
const project2 = createTestProject(tree, {
|
||||
appRoot: 'project2',
|
||||
appName: 'project2',
|
||||
});
|
||||
expect(addedIntegrationVitePlugin).toBeTruthy();
|
||||
expect(
|
||||
(addedIntegrationVitePlugin as ExpandedPluginConfiguration).include
|
||||
).toEqual(['third/**/*']);
|
||||
const project3 = createTestProject(tree, {
|
||||
appRoot: 'project3',
|
||||
appName: 'project3',
|
||||
buildTargetName: 'vite-build',
|
||||
serveTargetName: 'vite-serve',
|
||||
});
|
||||
const project4 = createTestProject(tree, {
|
||||
appRoot: 'project4',
|
||||
appName: 'project4',
|
||||
buildTargetName: 'build',
|
||||
serveTargetName: 'vite-serve',
|
||||
});
|
||||
const project5 = createTestProject(tree, {
|
||||
appRoot: 'project5',
|
||||
appName: 'project5',
|
||||
buildTargetName: 'vite-build',
|
||||
serveTargetName: 'serve',
|
||||
});
|
||||
|
||||
await convertToInferred(tree, { skipFormat: true });
|
||||
|
||||
// nx.json modifications
|
||||
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||
const vitePluginRegistrations = nxJsonPlugins.filter(
|
||||
(plugin): plugin is ExpandedPluginConfiguration<VitePluginOptions> =>
|
||||
typeof plugin !== 'string' && plugin.plugin === '@nx/vite/plugin'
|
||||
);
|
||||
expect(vitePluginRegistrations.length).toBe(4);
|
||||
expect(vitePluginRegistrations[0].options.buildTargetName).toBe('build');
|
||||
expect(vitePluginRegistrations[0].options.serveTargetName).toBe('serve');
|
||||
expect(vitePluginRegistrations[0].include).toEqual([
|
||||
`${project1.root}/**/*`,
|
||||
`${project2.root}/**/*`,
|
||||
]);
|
||||
expect(vitePluginRegistrations[1].options.buildTargetName).toBe('build');
|
||||
expect(vitePluginRegistrations[1].options.serveTargetName).toBe(
|
||||
'vite-serve'
|
||||
);
|
||||
expect(vitePluginRegistrations[1].include).toEqual([
|
||||
`${project4.root}/**/*`,
|
||||
]);
|
||||
expect(vitePluginRegistrations[2].options.buildTargetName).toBe(
|
||||
'vite-build'
|
||||
);
|
||||
expect(vitePluginRegistrations[2].options.serveTargetName).toBe(
|
||||
'vite-serve'
|
||||
);
|
||||
expect(vitePluginRegistrations[2].include).toEqual([
|
||||
`${project3.root}/**/*`,
|
||||
]);
|
||||
expect(vitePluginRegistrations[3].options.buildTargetName).toBe(
|
||||
'vite-build'
|
||||
);
|
||||
expect(vitePluginRegistrations[3].options.serveTargetName).toBe('serve');
|
||||
expect(vitePluginRegistrations[3].include).toEqual([
|
||||
`${project5.root}/**/*`,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should keep Vite options in project.json', async () => {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { createProjectGraphAsync, formatFiles, type Tree } from '@nx/devkit';
|
||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { createNodesV2, VitePluginOptions } from '../../plugins/plugin';
|
||||
import { buildPostTargetTransformer } from './lib/build-post-target-transformer';
|
||||
import { servePostTargetTransformer } from './lib/serve-post-target-transformer';
|
||||
@ -15,81 +15,46 @@ interface Schema {
|
||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||
const projectGraph = await createProjectGraphAsync();
|
||||
const migrationLogs = new AggregatedLog();
|
||||
const migratedBuildProjects =
|
||||
await migrateExecutorToPlugin<VitePluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/vite:build',
|
||||
'@nx/vite/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: targetName,
|
||||
serveTargetName: 'serve',
|
||||
previewTargetName: 'preview',
|
||||
testTargetName: 'test',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
}),
|
||||
buildPostTargetTransformer,
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
const migratedServeProjects =
|
||||
await migrateExecutorToPlugin<VitePluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/vite:dev-server',
|
||||
'@nx/vite/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: 'build',
|
||||
serveTargetName: targetName,
|
||||
previewTargetName: 'preview',
|
||||
testTargetName: 'test',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
}),
|
||||
servePostTargetTransformer(migrationLogs),
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
const migratedPreviewProjects =
|
||||
await migrateExecutorToPlugin<VitePluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/vite:preview-server',
|
||||
'@nx/vite/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: 'build',
|
||||
serveTargetName: 'serve',
|
||||
previewTargetName: targetName,
|
||||
testTargetName: 'test',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
}),
|
||||
previewPostTargetTransformer(migrationLogs),
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
const migratedTestProjects = await migrateExecutorToPlugin<VitePluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/vite:test',
|
||||
'@nx/vite/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: 'build',
|
||||
serveTargetName: 'serve',
|
||||
previewTargetName: 'preview',
|
||||
testTargetName: targetName,
|
||||
serveStaticTargetName: 'serve-static',
|
||||
}),
|
||||
testPostTargetTransformer,
|
||||
createNodesV2,
|
||||
options.project
|
||||
);
|
||||
|
||||
const migratedProjects =
|
||||
migratedBuildProjects.size +
|
||||
migratedServeProjects.size +
|
||||
migratedPreviewProjects.size +
|
||||
migratedTestProjects.size;
|
||||
await migrateProjectExecutorsToPlugin<VitePluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/vite/plugin',
|
||||
createNodesV2,
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
serveTargetName: 'serve',
|
||||
previewTargetName: 'preview',
|
||||
testTargetName: 'test',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
},
|
||||
[
|
||||
{
|
||||
executors: ['@nx/vite:build'],
|
||||
postTargetTransformer: buildPostTargetTransformer,
|
||||
targetPluginOptionMapper: (target) => ({ buildTargetName: target }),
|
||||
},
|
||||
{
|
||||
executors: ['@nx/vite:dev-server'],
|
||||
postTargetTransformer: servePostTargetTransformer(migrationLogs),
|
||||
targetPluginOptionMapper: (target) => ({ serveTargetName: target }),
|
||||
},
|
||||
{
|
||||
executors: ['@nx/vite:preview-server'],
|
||||
postTargetTransformer: previewPostTargetTransformer(migrationLogs),
|
||||
targetPluginOptionMapper: (target) => ({ previewTargetName: target }),
|
||||
},
|
||||
{
|
||||
executors: ['@nx/vite:test'],
|
||||
postTargetTransformer: testPostTargetTransformer,
|
||||
targetPluginOptionMapper: (target) => ({ testTargetName: target }),
|
||||
},
|
||||
],
|
||||
options.project
|
||||
);
|
||||
|
||||
if (migratedProjects === 0) {
|
||||
if (migratedProjects.size === 0) {
|
||||
throw new Error('Could not find any targets to migrate.');
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import {
|
||||
joinPathFragments,
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
updateNxJson,
|
||||
updateProjectConfiguration,
|
||||
writeJson,
|
||||
type ExpandedPluginConfiguration,
|
||||
@ -14,6 +15,7 @@ import { TempFs } from '@nx/devkit/internal-testing-utils';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { join } from 'node:path';
|
||||
import { getRelativeProjectJsonSchemaPath } from 'nx/src/generators/utils/project-configuration';
|
||||
import type { WebpackPluginOptions } from '../../plugins/plugin';
|
||||
import { convertToInferred } from './convert-to-inferred';
|
||||
|
||||
let fs: TempFs;
|
||||
@ -377,6 +379,78 @@ describe('convert-to-inferred', () => {
|
||||
expect(updatedProject2.targets.build).toStrictEqual(project2BuildTarget);
|
||||
});
|
||||
|
||||
it('should remove "includes" from the plugin registration when all projects are included', async () => {
|
||||
const project1 = createProject(tree);
|
||||
writeWebpackConfig(tree, project1.root);
|
||||
const nxJson = readNxJson(tree);
|
||||
nxJson.plugins ??= [];
|
||||
nxJson.plugins.push({
|
||||
plugin: '@nx/webpack/plugin',
|
||||
options: {
|
||||
buildTargetName: 'build',
|
||||
previewTargetName: 'preview',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
serveTargetName: 'serve',
|
||||
},
|
||||
include: [`${project1.root}/**/*`],
|
||||
});
|
||||
updateNxJson(tree, nxJson);
|
||||
const project2 = createProject(tree, {
|
||||
appName: 'app2',
|
||||
appRoot: 'apps/app2',
|
||||
});
|
||||
writeWebpackConfig(tree, project2.root);
|
||||
|
||||
await convertToInferred(tree, { project: project2.name });
|
||||
|
||||
// nx.json modifications
|
||||
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||
const webpackPluginRegistrations = nxJsonPlugins.filter(
|
||||
(plugin): plugin is ExpandedPluginConfiguration<WebpackPluginOptions> =>
|
||||
typeof plugin !== 'string' && plugin.plugin === '@nx/webpack/plugin'
|
||||
);
|
||||
expect(webpackPluginRegistrations.length).toBe(1);
|
||||
expect(webpackPluginRegistrations[0].include).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not add to "includes" when existing matching registration does not have it set', async () => {
|
||||
const project1 = createProject(tree);
|
||||
writeWebpackConfig(tree, project1.root);
|
||||
const nxJson = readNxJson(tree);
|
||||
nxJson.plugins ??= [];
|
||||
nxJson.plugins.push({
|
||||
plugin: '@nx/webpack/plugin',
|
||||
options: {
|
||||
buildTargetName: 'build',
|
||||
previewTargetName: 'preview',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
serveTargetName: 'serve',
|
||||
},
|
||||
});
|
||||
updateNxJson(tree, nxJson);
|
||||
const project2 = createProject(tree, {
|
||||
appName: 'app2',
|
||||
appRoot: 'apps/app2',
|
||||
});
|
||||
writeWebpackConfig(tree, project2.root);
|
||||
const project3 = createProject(tree, {
|
||||
appName: 'app3',
|
||||
appRoot: 'apps/app3',
|
||||
});
|
||||
writeWebpackConfig(tree, project3.root);
|
||||
|
||||
await convertToInferred(tree, { project: project2.name });
|
||||
|
||||
// nx.json modifications
|
||||
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||
const webpackPluginRegistrations = nxJsonPlugins.filter(
|
||||
(plugin): plugin is ExpandedPluginConfiguration<WebpackPluginOptions> =>
|
||||
typeof plugin !== 'string' && plugin.plugin === '@nx/webpack/plugin'
|
||||
);
|
||||
expect(webpackPluginRegistrations.length).toBe(1);
|
||||
expect(webpackPluginRegistrations[0].include).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should move options to the webpack config file', async () => {
|
||||
const project = createProject(tree);
|
||||
writeWebpackConfig(tree, project.root);
|
||||
@ -753,11 +827,26 @@ describe('convert-to-inferred', () => {
|
||||
appName: 'app3',
|
||||
appRoot: 'apps/app3',
|
||||
buildTargetName: 'build-webpack',
|
||||
serveTargetName: 'serve-webpack',
|
||||
});
|
||||
writeWebpackConfig(tree, project3.root);
|
||||
const projectWithComposePlugins = createProject(tree, {
|
||||
const project4 = createProject(tree, {
|
||||
appName: 'app4',
|
||||
appRoot: 'apps/app4',
|
||||
buildTargetName: 'build',
|
||||
serveTargetName: 'serve-webpack',
|
||||
});
|
||||
writeWebpackConfig(tree, project4.root);
|
||||
const project5 = createProject(tree, {
|
||||
appName: 'app5',
|
||||
appRoot: 'apps/app5',
|
||||
buildTargetName: 'build-webpack',
|
||||
serveTargetName: 'serve',
|
||||
});
|
||||
writeWebpackConfig(tree, project5.root);
|
||||
const projectWithComposePlugins = createProject(tree, {
|
||||
appName: 'app6',
|
||||
appRoot: 'apps/app6',
|
||||
});
|
||||
const projectWithComposePluginsInitialTargets =
|
||||
projectWithComposePlugins.targets;
|
||||
@ -783,8 +872,8 @@ module.exports = composePlugins(
|
||||
initialProjectWithComposePluginsWebpackConfig
|
||||
);
|
||||
const projectWithNoNxAppWebpackPlugin = createProject(tree, {
|
||||
appName: 'app5',
|
||||
appRoot: 'apps/app5',
|
||||
appName: 'app7',
|
||||
appRoot: 'apps/app7',
|
||||
});
|
||||
const projectWithNoNxAppWebpackPluginInitialTargets =
|
||||
projectWithNoNxAppWebpackPlugin.targets;
|
||||
@ -829,6 +918,28 @@ module.exports = composePlugins(
|
||||
});
|
||||
const updatedProject3 = readProjectConfiguration(tree, project3.name);
|
||||
expect(updatedProject3.targets).toStrictEqual({
|
||||
'build-webpack': {
|
||||
configurations: { development: {}, production: {} },
|
||||
defaultConfiguration: 'production',
|
||||
},
|
||||
'serve-webpack': {
|
||||
configurations: { development: {}, production: {} },
|
||||
defaultConfiguration: 'development',
|
||||
},
|
||||
});
|
||||
const updatedProject4 = readProjectConfiguration(tree, project4.name);
|
||||
expect(updatedProject4.targets).toStrictEqual({
|
||||
build: {
|
||||
configurations: { development: {}, production: {} },
|
||||
defaultConfiguration: 'production',
|
||||
},
|
||||
'serve-webpack': {
|
||||
configurations: { development: {}, production: {} },
|
||||
defaultConfiguration: 'development',
|
||||
},
|
||||
});
|
||||
const updatedProject5 = readProjectConfiguration(tree, project5.name);
|
||||
expect(updatedProject5.targets).toStrictEqual({
|
||||
'build-webpack': {
|
||||
configurations: { development: {}, production: {} },
|
||||
defaultConfiguration: 'production',
|
||||
@ -882,6 +993,73 @@ module.exports = composePlugins(
|
||||
expect(updatedProjectWithNoNxAppWebpackPluginWebpackConfig).toBe(
|
||||
initialProjectWithNoNxAppWebpackPluginWebpackConfig
|
||||
);
|
||||
// nx.json modifications
|
||||
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||
const webpackPluginRegistrations = nxJsonPlugins.filter(
|
||||
(plugin): plugin is ExpandedPluginConfiguration<WebpackPluginOptions> =>
|
||||
typeof plugin !== 'string' && plugin.plugin === '@nx/webpack/plugin'
|
||||
);
|
||||
expect(webpackPluginRegistrations.length).toBe(4);
|
||||
expect(webpackPluginRegistrations[0].options.buildTargetName).toBe(
|
||||
'build'
|
||||
);
|
||||
expect(webpackPluginRegistrations[0].options.serveTargetName).toBe(
|
||||
'serve'
|
||||
);
|
||||
expect(webpackPluginRegistrations[0].include).toEqual([
|
||||
`${project1.root}/**/*`,
|
||||
`${project2.root}/**/*`,
|
||||
]);
|
||||
expect(webpackPluginRegistrations[1].options.buildTargetName).toBe(
|
||||
'build'
|
||||
);
|
||||
expect(webpackPluginRegistrations[1].options.serveTargetName).toBe(
|
||||
'serve-webpack'
|
||||
);
|
||||
expect(webpackPluginRegistrations[1].include).toEqual([
|
||||
`${project4.root}/**/*`,
|
||||
]);
|
||||
expect(webpackPluginRegistrations[2].options.buildTargetName).toBe(
|
||||
'build-webpack'
|
||||
);
|
||||
expect(webpackPluginRegistrations[2].options.serveTargetName).toBe(
|
||||
'serve-webpack'
|
||||
);
|
||||
expect(webpackPluginRegistrations[2].include).toEqual([
|
||||
`${project3.root}/**/*`,
|
||||
]);
|
||||
expect(webpackPluginRegistrations[3].options.buildTargetName).toBe(
|
||||
'build-webpack'
|
||||
);
|
||||
expect(webpackPluginRegistrations[3].options.serveTargetName).toBe(
|
||||
'serve'
|
||||
);
|
||||
expect(webpackPluginRegistrations[3].include).toEqual([
|
||||
`${project5.root}/**/*`,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should remove "includes" from the plugin registration when all projects are included', async () => {
|
||||
const project1 = createProject(tree);
|
||||
writeWebpackConfig(tree, project1.root);
|
||||
const project2 = createProject(tree, {
|
||||
appName: 'app2',
|
||||
appRoot: 'apps/app2',
|
||||
buildExecutor: '@nrwl/webpack:webpack',
|
||||
serveExecutor: '@nrwl/webpack:dev-server',
|
||||
});
|
||||
writeWebpackConfig(tree, project2.root);
|
||||
|
||||
await convertToInferred(tree, {});
|
||||
|
||||
// nx.json modifications
|
||||
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||
const webpackPluginRegistrations = nxJsonPlugins.filter(
|
||||
(plugin): plugin is ExpandedPluginConfiguration<WebpackPluginOptions> =>
|
||||
typeof plugin !== 'string' && plugin.plugin === '@nx/webpack/plugin'
|
||||
);
|
||||
expect(webpackPluginRegistrations.length).toBe(1);
|
||||
expect(webpackPluginRegistrations[0].include).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should keep the higher "memoryLimit" value in the build configuration', async () => {
|
||||
|
||||
@ -2,20 +2,20 @@ import {
|
||||
addDependenciesToPackageJson,
|
||||
createProjectGraphAsync,
|
||||
formatFiles,
|
||||
type ProjectConfiguration,
|
||||
runTasksInSerial,
|
||||
type ProjectConfiguration,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
|
||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
import * as ts from 'typescript';
|
||||
import { createNodesV2, type WebpackPluginOptions } from '../../plugins/plugin';
|
||||
import { webpackCliVersion } from '../../utils/versions';
|
||||
import {
|
||||
buildPostTargetTransformerFactory,
|
||||
type MigrationContext,
|
||||
servePostTargetTransformerFactory,
|
||||
type MigrationContext,
|
||||
} from './utils';
|
||||
|
||||
interface Schema {
|
||||
@ -31,85 +31,38 @@ export async function convertToInferred(tree: Tree, options: Schema) {
|
||||
workspaceRoot: tree.root,
|
||||
};
|
||||
|
||||
// build
|
||||
const migratedBuildProjects =
|
||||
await migrateExecutorToPlugin<WebpackPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/webpack:webpack',
|
||||
'@nx/webpack/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: targetName,
|
||||
previewTargetName: 'preview',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
serveTargetName: 'serve',
|
||||
}),
|
||||
buildPostTargetTransformerFactory(migrationContext),
|
||||
createNodesV2,
|
||||
options.project,
|
||||
{ skipProjectFilter: skipProjectFilterFactory(tree) }
|
||||
);
|
||||
const migratedBuildProjectsLegacy =
|
||||
await migrateExecutorToPlugin<WebpackPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nrwl/webpack:webpack',
|
||||
'@nx/webpack/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: targetName,
|
||||
previewTargetName: 'preview',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
serveTargetName: 'serve',
|
||||
}),
|
||||
buildPostTargetTransformerFactory(migrationContext),
|
||||
createNodesV2,
|
||||
options.project,
|
||||
{ skipProjectFilter: skipProjectFilterFactory(tree) }
|
||||
);
|
||||
|
||||
// serve
|
||||
const migratedServeProjects =
|
||||
await migrateExecutorToPlugin<WebpackPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/webpack:dev-server',
|
||||
'@nx/webpack/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: 'build',
|
||||
previewTargetName: 'preview',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
serveTargetName: targetName,
|
||||
}),
|
||||
servePostTargetTransformerFactory(migrationContext),
|
||||
createNodesV2,
|
||||
options.project,
|
||||
{ skipProjectFilter: skipProjectFilterFactory(tree) }
|
||||
);
|
||||
const migratedServeProjectsLegacy =
|
||||
await migrateExecutorToPlugin<WebpackPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nrwl/webpack:dev-server',
|
||||
'@nx/webpack/plugin',
|
||||
(targetName) => ({
|
||||
buildTargetName: 'build',
|
||||
previewTargetName: 'preview',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
serveTargetName: targetName,
|
||||
}),
|
||||
servePostTargetTransformerFactory(migrationContext),
|
||||
createNodesV2,
|
||||
options.project,
|
||||
{ skipProjectFilter: skipProjectFilterFactory(tree) }
|
||||
);
|
||||
|
||||
const migratedProjects =
|
||||
migratedBuildProjects.size +
|
||||
migratedBuildProjectsLegacy.size +
|
||||
migratedServeProjects.size +
|
||||
migratedServeProjectsLegacy.size;
|
||||
await migrateProjectExecutorsToPlugin<WebpackPluginOptions>(
|
||||
tree,
|
||||
projectGraph,
|
||||
'@nx/webpack/plugin',
|
||||
createNodesV2,
|
||||
{
|
||||
buildTargetName: 'build',
|
||||
previewTargetName: 'preview',
|
||||
serveStaticTargetName: 'serve-static',
|
||||
serveTargetName: 'serve',
|
||||
},
|
||||
[
|
||||
{
|
||||
executors: ['@nx/webpack:webpack', '@nrwl/webpack:webpack'],
|
||||
postTargetTransformer:
|
||||
buildPostTargetTransformerFactory(migrationContext),
|
||||
targetPluginOptionMapper: (target) => ({ buildTargetName: target }),
|
||||
skipProjectFilter: skipProjectFilterFactory(tree),
|
||||
},
|
||||
{
|
||||
executors: ['@nx/webpack:dev-server', '@nrwl/webpack:dev-server'],
|
||||
postTargetTransformer:
|
||||
servePostTargetTransformerFactory(migrationContext),
|
||||
targetPluginOptionMapper: (target) => ({ serveTargetName: target }),
|
||||
skipProjectFilter: skipProjectFilterFactory(tree),
|
||||
},
|
||||
],
|
||||
options.project
|
||||
);
|
||||
|
||||
if (migratedProjects === 0) {
|
||||
if (migratedProjects.size === 0) {
|
||||
throw new Error('Could not find any targets to migrate.');
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user