feat(core)!: remove legacy cache flag from nx.json (#30787)

This commit is contained in:
Craigory Coppola 2025-04-29 10:39:36 -04:00 committed by GitHub
parent 4cca2ba062
commit c8d89e2f2a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 441 additions and 168 deletions

View File

@ -0,0 +1,22 @@
# Type alias: Migration
Ƭ **Migration**: (`tree`: [`Tree`](../../devkit/documents/Tree)) => `void` \| `Promise`\<`void`\> \| `string`[] \| `Promise`\<`string`[]\>
Represents a migration that is executed when running `nx migrate`.
Returning a string[] from the migration function will be interpreted as
a list of next steps to be displayed to the user.
#### Type declaration
▸ (`tree`): `void` \| `Promise`\<`void`\> \| `string`[] \| `Promise`\<`string`[]\>
##### Parameters
| Name | Type |
| :----- | :------------------------------------ |
| `tree` | [`Tree`](../../devkit/documents/Tree) |
##### Returns
`void` \| `Promise`\<`void`\> \| `string`[] \| `Promise`\<`string`[]\>

View File

@ -45,7 +45,6 @@ Nx.json configuration
- [tui](../../devkit/documents/NxJsonConfiguration#tui): Object - [tui](../../devkit/documents/NxJsonConfiguration#tui): Object
- [useDaemonProcess](../../devkit/documents/NxJsonConfiguration#usedaemonprocess): boolean - [useDaemonProcess](../../devkit/documents/NxJsonConfiguration#usedaemonprocess): boolean
- [useInferencePlugins](../../devkit/documents/NxJsonConfiguration#useinferenceplugins): boolean - [useInferencePlugins](../../devkit/documents/NxJsonConfiguration#useinferenceplugins): boolean
- [useLegacyCache](../../devkit/documents/NxJsonConfiguration#uselegacycache): boolean
- [workspaceLayout](../../devkit/documents/NxJsonConfiguration#workspacelayout): Object - [workspaceLayout](../../devkit/documents/NxJsonConfiguration#workspacelayout): Object
## Properties ## Properties
@ -321,14 +320,6 @@ Set this to false to disable adding inference plugins when generating new projec
--- ---
### useLegacyCache
`Optional` **useLegacyCache**: `boolean`
Use the legacy file system cache instead of the db cache
---
### workspaceLayout ### workspaceLayout
`Optional` **workspaceLayout**: `Object` `Optional` **workspaceLayout**: `Object`

View File

@ -84,6 +84,7 @@ It only uses language primitives and immutable objects
- [Hasher](../../devkit/documents/Hasher) - [Hasher](../../devkit/documents/Hasher)
- [ImplicitDependency](../../devkit/documents/ImplicitDependency) - [ImplicitDependency](../../devkit/documents/ImplicitDependency)
- [ImplicitDependencyEntry](../../devkit/documents/ImplicitDependencyEntry) - [ImplicitDependencyEntry](../../devkit/documents/ImplicitDependencyEntry)
- [Migration](../../devkit/documents/Migration)
- [NxPlugin](../../devkit/documents/NxPlugin) - [NxPlugin](../../devkit/documents/NxPlugin)
- [NxPluginV2](../../devkit/documents/NxPluginV2) - [NxPluginV2](../../devkit/documents/NxPluginV2)
- [PackageManager](../../devkit/documents/PackageManager) - [PackageManager](../../devkit/documents/PackageManager)

View File

@ -44,7 +44,6 @@ use ProjectsConfigurations or NxJsonConfiguration
- [tui](../../devkit/documents/Workspace#tui): Object - [tui](../../devkit/documents/Workspace#tui): Object
- [useDaemonProcess](../../devkit/documents/Workspace#usedaemonprocess): boolean - [useDaemonProcess](../../devkit/documents/Workspace#usedaemonprocess): boolean
- [useInferencePlugins](../../devkit/documents/Workspace#useinferenceplugins): boolean - [useInferencePlugins](../../devkit/documents/Workspace#useinferenceplugins): boolean
- [useLegacyCache](../../devkit/documents/Workspace#uselegacycache): boolean
- [version](../../devkit/documents/Workspace#version): number - [version](../../devkit/documents/Workspace#version): number
- [workspaceLayout](../../devkit/documents/Workspace#workspacelayout): Object - [workspaceLayout](../../devkit/documents/Workspace#workspacelayout): Object
@ -441,18 +440,6 @@ Set this to false to disable adding inference plugins when generating new projec
--- ---
### useLegacyCache
`Optional` **useLegacyCache**: `boolean`
Use the legacy file system cache instead of the db cache
#### Inherited from
[NxJsonConfiguration](../../devkit/documents/NxJsonConfiguration).[useLegacyCache](../../devkit/documents/NxJsonConfiguration#uselegacycache)
---
### version ### version
**version**: `number` **version**: `number`

View File

@ -3364,6 +3364,26 @@
} }
}, },
"migrations": { "migrations": {
"/nx-api/nx/migrations/remove-legacy-cache": {
"description": "Removes the legacy cache configuration from nx.json",
"file": "generated/packages/nx/migrations/remove-legacy-cache.json",
"hidden": false,
"name": "remove-legacy-cache",
"version": "21.0.0-beta.8",
"originalFilePath": "/packages/nx",
"path": "/nx-api/nx/migrations/remove-legacy-cache",
"type": "migration"
},
"/nx-api/nx/migrations/remove-custom-tasks-runner": {
"description": "Removes the legacy cache configuration from nx.json",
"file": "generated/packages/nx/migrations/remove-custom-tasks-runner.json",
"hidden": false,
"name": "remove-custom-tasks-runner",
"version": "21.0.0-beta.8",
"originalFilePath": "/packages/nx",
"path": "/nx-api/nx/migrations/remove-custom-tasks-runner",
"type": "migration"
},
"/nx-api/nx/migrations/release-version-config-changes": { "/nx-api/nx/migrations/release-version-config-changes": {
"description": "Updates release version config based on the breaking changes in Nx v21", "description": "Updates release version config based on the breaking changes in Nx v21",
"file": "generated/packages/nx/migrations/release-version-config-changes.json", "file": "generated/packages/nx/migrations/release-version-config-changes.json",

View File

@ -3340,6 +3340,26 @@
} }
], ],
"migrations": [ "migrations": [
{
"description": "Removes the legacy cache configuration from nx.json",
"file": "generated/packages/nx/migrations/remove-legacy-cache.json",
"hidden": false,
"name": "remove-legacy-cache",
"version": "21.0.0-beta.8",
"originalFilePath": "/packages/nx",
"path": "nx/migrations/remove-legacy-cache",
"type": "migration"
},
{
"description": "Removes the legacy cache configuration from nx.json",
"file": "generated/packages/nx/migrations/remove-custom-tasks-runner.json",
"hidden": false,
"name": "remove-custom-tasks-runner",
"version": "21.0.0-beta.8",
"originalFilePath": "/packages/nx",
"path": "nx/migrations/remove-custom-tasks-runner",
"type": "migration"
},
{ {
"description": "Updates release version config based on the breaking changes in Nx v21", "description": "Updates release version config based on the breaking changes in Nx v21",
"file": "generated/packages/nx/migrations/release-version-config-changes.json", "file": "generated/packages/nx/migrations/release-version-config-changes.json",

View File

@ -84,6 +84,7 @@ It only uses language primitives and immutable objects
- [Hasher](../../devkit/documents/Hasher) - [Hasher](../../devkit/documents/Hasher)
- [ImplicitDependency](../../devkit/documents/ImplicitDependency) - [ImplicitDependency](../../devkit/documents/ImplicitDependency)
- [ImplicitDependencyEntry](../../devkit/documents/ImplicitDependencyEntry) - [ImplicitDependencyEntry](../../devkit/documents/ImplicitDependencyEntry)
- [Migration](../../devkit/documents/Migration)
- [NxPlugin](../../devkit/documents/NxPlugin) - [NxPlugin](../../devkit/documents/NxPlugin)
- [NxPluginV2](../../devkit/documents/NxPluginV2) - [NxPluginV2](../../devkit/documents/NxPluginV2)
- [PackageManager](../../devkit/documents/PackageManager) - [PackageManager](../../devkit/documents/PackageManager)

View File

@ -0,0 +1,12 @@
{
"name": "remove-custom-tasks-runner",
"version": "21.0.0-beta.8",
"description": "Removes the legacy cache configuration from nx.json",
"implementation": "/packages/nx/src/migrations/update-21-0-0/remove-custom-tasks-runner.ts",
"aliases": [],
"hidden": false,
"path": "/packages/nx",
"schema": null,
"type": "migration",
"examplesFile": "#### Remove Custom Tasks Runners\n\nRemoves `tasksRunnerOptions` entries from `nx.json` that contain custom tasks runners. In Nx 21, custom tasks runners are no longer functional. See /deprecated/custom-tasks-runner for more information.\n\n#### Sample Code Changes\n\nRemoves custom task runner configuration from `nx.json`.\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"targetDefaults\": {},\n \"tasksRunnerOptions\": {\n \"default\": {\n \"runner\": \"custom-task-runner\"\n }\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"targetDefaults\": {}\n}\n```\n\n{% /tab %}\n{% /tabs %}\n"
}

View File

@ -0,0 +1,12 @@
{
"name": "remove-legacy-cache",
"version": "21.0.0-beta.8",
"description": "Removes the legacy cache configuration from nx.json",
"implementation": "/packages/nx/src/migrations/update-21-0-0/remove-legacy-cache.ts",
"aliases": [],
"hidden": false,
"path": "/packages/nx",
"schema": null,
"type": "migration",
"examplesFile": "#### Use Legacy Cache\n\nRemoves `useLegacyCache` from `nx.json` as it is no longer functional in Nx 21\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"targetDefaults\": {},\n \"useLegacyCache\": true\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"targetDefaults\": {}\n}\n```\n\n{% /tab %}\n{% /tabs %}\n"
}

View File

@ -33,6 +33,16 @@
"version": "21.0.0-beta.1", "version": "21.0.0-beta.1",
"description": "Updates release version config based on the breaking changes in Nx v21", "description": "Updates release version config based on the breaking changes in Nx v21",
"implementation": "./src/migrations/update-21-0-0/release-version-config-changes" "implementation": "./src/migrations/update-21-0-0/release-version-config-changes"
},
"remove-legacy-cache": {
"version": "21.0.0-beta.8",
"description": "Removes the legacy cache configuration from nx.json",
"implementation": "./src/migrations/update-21-0-0/remove-legacy-cache"
},
"remove-custom-tasks-runner": {
"version": "21.0.0-beta.8",
"description": "Removes the legacy cache configuration from nx.json",
"implementation": "./src/migrations/update-21-0-0/remove-custom-tasks-runner"
} }
} }
} }

View File

@ -135,15 +135,16 @@ export async function runSingleMigration(
// 2. Bundled into Console, so the version is fixed to what we build Console with. // 2. Bundled into Console, so the version is fixed to what we build Console with.
const updatedMigrateModule = await import('./migrate.js'); const updatedMigrateModule = await import('./migrate.js');
const fileChanges = await updatedMigrateModule.runNxOrAngularMigration( const { changes: fileChanges } =
workspacePath, await updatedMigrateModule.runNxOrAngularMigration(
migration, workspacePath,
false, migration,
configuration.createCommits, false,
configuration.commitPrefix || 'chore: [nx migration] ', configuration.createCommits,
undefined, configuration.commitPrefix || 'chore: [nx migration] ',
true undefined,
); true
);
const gitRefAfter = execSync('git rev-parse HEAD', { const gitRefAfter = execSync('git rev-parse HEAD', {
cwd: workspacePath, cwd: workspacePath,

View File

@ -1474,11 +1474,11 @@ export async function executeMigrations(
logger.info(`- ${m.package}: ${m.name} (${m.description})`) logger.info(`- ${m.package}: ${m.name} (${m.description})`)
); );
logger.info(`---------------------------------------------------------\n`); logger.info(`---------------------------------------------------------\n`);
const allNextSteps: string[] = [];
for (const m of sortedMigrations) { for (const m of sortedMigrations) {
logger.info(`Running migration ${m.package}: ${m.name}`); logger.info(`Running migration ${m.package}: ${m.name}`);
try { try {
const changes = await runNxOrAngularMigration( const { changes, nextSteps } = await runNxOrAngularMigration(
root, root,
m, m,
isVerbose, isVerbose,
@ -1486,6 +1486,7 @@ export async function executeMigrations(
commitPrefix, commitPrefix,
() => changedDepInstaller.installDepsIfChanged() () => changedDepInstaller.installDepsIfChanged()
); );
allNextSteps.push(...nextSteps);
if (changes.length === 0) { if (changes.length === 0) {
migrationsWithNoChanges.push(m); migrationsWithNoChanges.push(m);
} }
@ -1502,7 +1503,7 @@ export async function executeMigrations(
changedDepInstaller.installDepsIfChanged(); changedDepInstaller.installDepsIfChanged();
} }
return migrationsWithNoChanges; return { migrationsWithNoChanges, nextSteps: allNextSteps };
} }
class ChangedDepInstaller { class ChangedDepInstaller {
@ -1533,7 +1534,7 @@ export async function runNxOrAngularMigration(
commitPrefix: string, commitPrefix: string,
installDepsIfChanged?: () => void, installDepsIfChanged?: () => void,
handleInstallDeps = false handleInstallDeps = false
): Promise<FileChange[]> { ): Promise<{ changes: FileChange[]; nextSteps: string[] }> {
if (!installDepsIfChanged) { if (!installDepsIfChanged) {
const changedDepInstaller = new ChangedDepInstaller(root); const changedDepInstaller = new ChangedDepInstaller(root);
installDepsIfChanged = () => changedDepInstaller.installDepsIfChanged(); installDepsIfChanged = () => changedDepInstaller.installDepsIfChanged();
@ -1543,19 +1544,20 @@ export async function runNxOrAngularMigration(
root root
); );
let changes: FileChange[] = []; let changes: FileChange[] = [];
let nextSteps: string[] = [];
if (!isAngularMigration(collection, migration.name)) { if (!isAngularMigration(collection, migration.name)) {
changes = await runNxMigration( ({ nextSteps, changes } = await runNxMigration(
root, root,
collectionPath, collectionPath,
collection, collection,
migration.name migration.name
); ));
logger.info(`Ran ${migration.name} from ${migration.package}`); logger.info(`Ran ${migration.name} from ${migration.package}`);
logger.info(` ${migration.description}\n`); logger.info(` ${migration.description}\n`);
if (changes.length < 1) { if (changes.length < 1) {
logger.info(`No changes were made\n`); logger.info(`No changes were made\n`);
return []; return { changes, nextSteps };
} }
logger.info('Changes:'); logger.info('Changes:');
@ -1576,7 +1578,7 @@ export async function runNxOrAngularMigration(
logger.info(` ${migration.description}\n`); logger.info(` ${migration.description}\n`);
if (!madeChanges) { if (!madeChanges) {
logger.info(`No changes were made\n`); logger.info(`No changes were made\n`);
return []; return { changes, nextSteps };
} }
logger.info('Changes:'); logger.info('Changes:');
@ -1608,7 +1610,7 @@ export async function runNxOrAngularMigration(
installDepsIfChanged(); installDepsIfChanged();
} }
return changes; return { changes, nextSteps };
} }
async function runMigrations( async function runMigrations(
@ -1662,7 +1664,7 @@ async function runMigrations(
version: string; version: string;
}[] = readJsonFile(join(root, opts.runMigrations)).migrations; }[] = readJsonFile(join(root, opts.runMigrations)).migrations;
const migrationsWithNoChanges = await executeMigrations( const { migrationsWithNoChanges, nextSteps } = await executeMigrations(
root, root,
migrations, migrations,
isVerbose, isVerbose,
@ -1679,6 +1681,12 @@ async function runMigrations(
title: `No changes were made from running '${opts.runMigrations}'. This workspace is up to date!`, title: `No changes were made from running '${opts.runMigrations}'. This workspace is up to date!`,
}); });
} }
if (nextSteps.length > 0) {
output.log({
title: `Some migrations have additional information, see below.`,
bodyLines: nextSteps.map((line) => `- ${line}`),
});
}
} }
function getStringifiedPackageJsonDeps(root: string): string { function getStringifiedPackageJsonDeps(root: string): string {
@ -1712,11 +1720,18 @@ async function runNxMigration(
process.env.NX_VERBOSE_LOGGING === 'true', process.env.NX_VERBOSE_LOGGING === 'true',
`migration ${collection.name}:${name}` `migration ${collection.name}:${name}`
); );
await fn(host, {}); let nextSteps = await fn(host, {});
// This accounts for migrations that mistakenly return a generator callback
// from a migration. We've never executed these, so its not a breaking change that
// we don't call them now... but currently shipping a migration with one wouldn't break
// the migrate flow, so we are being cautious.
if (!isStringArray(nextSteps)) {
nextSteps = [];
}
host.lock(); host.lock();
const changes = host.listChanges(); const changes = host.listChanges();
flushChanges(root, changes); flushChanges(root, changes);
return changes; return { changes, nextSteps };
} }
export async function migrate( export async function migrate(
@ -1905,3 +1920,10 @@ const getNgCompatLayer = (() => {
return _ngCliAdapter; return _ngCliAdapter;
}; };
})(); })();
function isStringArray(value: unknown): value is string[] {
if (!Array.isArray(value)) {
return false;
}
return value.every((v) => typeof v === 'string');
}

View File

@ -25,7 +25,7 @@ export async function repair(
); );
const migrations = [...nxMigrations, ...extraMigrations]; const migrations = [...nxMigrations, ...extraMigrations];
const migrationsThatMadeNoChanges = await executeMigrations( const { migrationsWithNoChanges, nextSteps } = await executeMigrations(
process.cwd(), process.cwd(),
migrations, migrations,
args.verbose, args.verbose,
@ -33,7 +33,7 @@ export async function repair(
'' ''
); );
if (migrationsThatMadeNoChanges.length < migrations.length) { if (migrationsWithNoChanges.length < migrations.length) {
output.success({ output.success({
title: `Successfully repaired your configuration. This workspace is up to date!`, title: `Successfully repaired your configuration. This workspace is up to date!`,
}); });
@ -42,5 +42,11 @@ export async function repair(
title: `No changes were necessary. This workspace is up to date!`, title: `No changes were necessary. This workspace is up to date!`,
}); });
} }
if (nextSteps.length) {
output.log({
title: 'Some repairs have additional information, see below.',
bodyLines: nextSteps.map((line) => ` - ${line}`),
});
}
}); });
} }

View File

@ -303,7 +303,7 @@ export async function getReportData(): Promise<ReportData> {
} }
} }
let cache = dbCacheEnabled(nxJson) let cache = dbCacheEnabled()
? { ? {
max: max:
nxJson.maxCacheSize !== undefined nxJson.maxCacheSize !== undefined

View File

@ -7,7 +7,8 @@ import {
} from './workspace-json-project-json'; } from './workspace-json-project-json';
import type { NxJsonConfiguration } from './nx-json'; import type { NxJsonConfiguration } from './nx-json';
import { Schema } from '../utils/params'; import type { Schema } from '../utils/params';
import type { Tree } from '../generators/tree';
/** /**
* A callback function that is executed after changes are made to the file system * A callback function that is executed after changes are made to the file system
*/ */
@ -66,6 +67,16 @@ export type PackageJsonUpdates = {
}; };
}; };
/**
* Represents a migration that is executed when running `nx migrate`.
*
* Returning a string[] from the migration function will be interpreted as
* a list of next steps to be displayed to the user.
*/
export type Migration = (
tree: Tree
) => void | Promise<void> | string[] | Promise<string[]>;
export interface MigrationsJsonEntry { export interface MigrationsJsonEntry {
version: string; version: string;
description?: string; description?: string;

View File

@ -651,11 +651,6 @@ export interface NxJsonConfiguration<T = '*' | string[]> {
*/ */
sync?: NxSyncConfiguration; sync?: NxSyncConfiguration;
/**
* Use the legacy file system cache instead of the db cache
*/
useLegacyCache?: boolean;
/** /**
* Sets the maximum size of the local cache. Accepts a number followed by a unit (e.g. 100MB). Accepted units are B, KB, MB, and GB. * Sets the maximum size of the local cache. Accepts a number followed by a unit (e.g. 100MB). Accepted units are B, KB, MB, and GB.
*/ */

View File

@ -26,6 +26,7 @@ export type {
*/ */
export type { export type {
Generator, Generator,
Migration,
GeneratorCallback, GeneratorCallback,
PromiseExecutor, PromiseExecutor,
AsyncIteratorExecutor, AsyncIteratorExecutor,

View File

@ -14,7 +14,9 @@ export default async function update(tree: Tree) {
if ((nxJson as any).enableDbCache) { if ((nxJson as any).enableDbCache) {
delete (nxJson as any).enableDbCache; delete (nxJson as any).enableDbCache;
} else { } else {
nxJson.useLegacyCache = true; (
nxJson as NxJsonConfiguration & { useLegacyCache: boolean }
).useLegacyCache = true;
} }
updateNxJson(tree, nxJson); updateNxJson(tree, nxJson);

View File

@ -0,0 +1,33 @@
#### Remove Custom Tasks Runners
Removes `tasksRunnerOptions` entries from `nx.json` that contain custom tasks runners. In Nx 21, custom tasks runners are no longer functional. See /deprecated/custom-tasks-runner for more information.
#### Sample Code Changes
Removes custom task runner configuration from `nx.json`.
{% tabs %}
{% tab label="Before" %}
```json {% fileName="nx.json" %}
{
"targetDefaults": {},
"tasksRunnerOptions": {
"default": {
"runner": "custom-task-runner"
}
}
}
```
{% /tab %}
{% tab label="After" %}
```json {% fileName="nx.json" %}
{
"targetDefaults": {}
}
```
{% /tab %}
{% /tabs %}

View File

@ -0,0 +1,140 @@
import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace';
import { Tree } from '../../generators/tree';
import update from './remove-custom-tasks-runner';
import { readNxJson, updateNxJson } from '../../generators/utils/nx-json';
describe('remove custom tasks runners', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
it('should remove all tasks runners that contain a custom runner', async () => {
updateNxJson(tree, {
tasksRunnerOptions: {
default: {
runner: 'nx-cloud',
options: {
cacheableOperations: ['build', 'lint'],
},
},
other: {
runner: 'some-other-runner',
options: {
cacheableOperations: ['test'],
},
},
custom: {
runner: 'custom-runner',
options: {
cacheableOperations: ['build', 'lint'],
},
},
},
});
await update(tree);
expect(readNxJson(tree)).toMatchInlineSnapshot(`
{
"tasksRunnerOptions": {
"default": {
"options": {
"cacheableOperations": [
"build",
"lint",
],
},
"runner": "nx-cloud",
},
},
}
`);
});
it('should remove whole tasksRunnerOptions if all runners are removed', async () => {
updateNxJson(tree, {
tasksRunnerOptions: {
default: {
runner: 'custom-runner',
options: {
cacheableOperations: ['build', 'lint'],
},
},
},
});
await update(tree);
expect(readNxJson(tree)).toMatchInlineSnapshot(`{}`);
});
it('should provide a link to the migration guide for nx-aws-cache', async () => {
updateNxJson(tree, {
tasksRunnerOptions: {
default: {
runner: '@nx-aws-cache/nx-aws-cache',
options: {
cacheableOperations: ['build', 'lint'],
},
},
},
});
const nextSteps = await update(tree);
expect(nextSteps).toMatchInlineSnapshot(`
[
"Nx 21 removed support for custom task runners. For more information, please check: https://nx.dev/deprecated/custom-tasks-runner#migrating-from-nxawsplugin",
]
`);
});
it('should not remove tasks runner if it is not custom', async () => {
updateNxJson(tree, {
tasksRunnerOptions: {
default: {
runner: 'nx-cloud',
options: {
cacheableOperations: ['build', 'lint'],
},
},
},
});
const nextSteps = await update(tree);
expect(readNxJson(tree)).toMatchInlineSnapshot(`
{
"tasksRunnerOptions": {
"default": {
"options": {
"cacheableOperations": [
"build",
"lint",
],
},
"runner": "nx-cloud",
},
},
}
`);
expect(nextSteps).toHaveLength(0);
});
it('should provide a link to the migration guide for other custom runners', async () => {
updateNxJson(tree, {
tasksRunnerOptions: {
default: {
runner: 'custom-runner',
options: {
cacheableOperations: ['build', 'lint'],
},
},
},
});
const nextSteps = await update(tree);
expect(nextSteps).toMatchInlineSnapshot(`
[
"Nx 21 removed support for custom task runners. For more information, please check: https://nx.dev/deprecated/custom-tasks-runner",
]
`);
expect(readNxJson(tree)).toMatchInlineSnapshot(`{}`);
});
});

View File

@ -0,0 +1,47 @@
import { Tree } from '../../generators/tree';
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
import { readNxJson, updateNxJson } from '../../generators/utils/nx-json';
import { NxJsonConfiguration } from '../../config/nx-json';
function isCustomRunnerPath(modulePath: string) {
return !['nx-cloud', '@nrwl/nx-cloud', 'nx/tasks-runners/default'].includes(
modulePath
);
}
export default async function update(tree: Tree) {
const nxJson = readNxJson(tree) as NxJsonConfiguration;
if (!nxJson?.tasksRunnerOptions) {
return;
}
const nextSteps: string[] = [];
for (const key in nxJson.tasksRunnerOptions) {
const runner = nxJson.tasksRunnerOptions[key].runner;
if (runner && isCustomRunnerPath(runner)) {
let nextStepText =
'Nx 21 removed support for custom task runners. For more information, please check: ';
if (runner === '@nx-aws-cache/nx-aws-cache') {
nextStepText +=
'https://nx.dev/deprecated/custom-tasks-runner#migrating-from-nxawsplugin';
} else {
nextStepText += 'https://nx.dev/deprecated/custom-tasks-runner';
}
if (nextSteps.length === 0) {
nextSteps.push(nextStepText);
}
delete nxJson.tasksRunnerOptions[key];
}
}
if (Object.keys(nxJson.tasksRunnerOptions).length === 0) {
delete nxJson.tasksRunnerOptions;
}
updateNxJson(tree, nxJson);
await formatChangedFilesWithPrettierIfAvailable(tree);
return nextSteps;
}

View File

@ -0,0 +1,27 @@
#### Use Legacy Cache
Removes `useLegacyCache` from `nx.json` as it is no longer functional in Nx 21
#### Sample Code Changes
{% tabs %}
{% tab label="Before" %}
```json {% fileName="nx.json" %}
{
"targetDefaults": {},
"useLegacyCache": true
}
```
{% /tab %}
{% tab label="After" %}
```json {% fileName="nx.json" %}
{
"targetDefaults": {}
}
```
{% /tab %}
{% /tabs %}

View File

@ -0,0 +1,21 @@
import { Tree } from '../../generators/tree';
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
import { readNxJson, updateNxJson } from '../../generators/utils/nx-json';
import { NxJsonConfiguration } from '../../config/nx-json';
export default async function update(tree: Tree) {
const nxJson = readNxJson(tree) as NxJsonConfiguration;
if (!nxJson) {
return;
}
// If workspaces had `useLegacyCache` we can just delete the property as the property is not functional in nx v21
if ((nxJson as any).useLegacyCache) {
delete (nxJson as any).useLegacyCache;
}
updateNxJson(tree, nxJson);
await formatChangedFilesWithPrettierIfAvailable(tree);
}

View File

@ -37,32 +37,7 @@ export type CachedResult = {
export type TaskWithCachedResult = { task: Task; cachedResult: CachedResult }; export type TaskWithCachedResult = { task: Task; cachedResult: CachedResult };
// This function is called once during tasks runner initialization. It checks if the db cache is enabled and logs a warning if it is not. // This function is called once during tasks runner initialization. It checks if the db cache is enabled and logs a warning if it is not.
export function dbCacheEnabled(nxJson: NxJsonConfiguration = readNxJson()) { export function dbCacheEnabled() {
// If the user has explicitly disabled the db cache, we can warn...
if (
nxJson.useLegacyCache ||
process.env.NX_DISABLE_DB === 'true' ||
process.env.NX_DB_CACHE === 'false'
) {
let readMoreLink = 'https://nx.dev/deprecated/legacy-cache';
if (
nxJson.tasksRunnerOptions?.default?.runner &&
!['nx-cloud', 'nx/tasks-runners/default', '@nrwl/nx-cloud'].includes(
nxJson.tasksRunnerOptions.default.runner
)
) {
readMoreLink += '#tasksrunneroptions';
} else if (
process.env.NX_REJECT_UNKNOWN_LOCAL_CACHE === '0' ||
process.env.NX_REJECT_UNKNOWN_LOCAL_CACHE === 'false'
) {
readMoreLink += '#nxrejectunknownlocalcache';
}
logger.warn(
`Nx is configured to use the legacy cache. This cache will be removed in Nx 21. Read more at ${readMoreLink}.`
);
return false;
}
// ...but if on wasm and the the db cache isnt supported we shouldn't warn // ...but if on wasm and the the db cache isnt supported we shouldn't warn
if (IS_WASM) { if (IS_WASM) {
return false; return false;
@ -85,7 +60,7 @@ export function dbCacheEnabled(nxJson: NxJsonConfiguration = readNxJson()) {
// Do not change the order of these arguments as this function is used by nx cloud // Do not change the order of these arguments as this function is used by nx cloud
export function getCache(options: DefaultTasksRunnerOptions): DbCache | Cache { export function getCache(options: DefaultTasksRunnerOptions): DbCache | Cache {
const nxJson = readNxJson(); const nxJson = readNxJson();
return dbCacheEnabled(nxJson) return dbCacheEnabled()
? new DbCache({ ? new DbCache({
// Remove this in Nx 21 // Remove this in Nx 21
nxCloudRemoteCache: isNxCloudUsed(nxJson) ? options.remoteCache : null, nxCloudRemoteCache: isNxCloudUsed(nxJson) ? options.remoteCache : null,

View File

@ -15,66 +15,6 @@ describe('getRunner', () => {
mockRunner = jest.fn(); mockRunner = jest.fn();
}); });
it('gets a custom task runner', () => {
jest.mock('custom-runner', () => mockRunner, {
virtual: true,
});
nxJson.tasksRunnerOptions = {
custom: {
runner: 'custom-runner',
},
};
const { tasksRunner, runnerOptions } = getRunner(
{ runner: 'custom' },
nxJson
);
expect(tasksRunner).toEqual(mockRunner);
});
it('gets a custom task runner with options', () => {
jest.mock('custom-runner2', () => mockRunner, {
virtual: true,
});
nxJson.tasksRunnerOptions = {
custom: {
runner: 'custom-runner2',
options: {
runnerOption: 'runner-option',
},
},
};
const { tasksRunner, runnerOptions } = getRunner(
{ runner: 'custom' },
nxJson
);
expect(tasksRunner).toBe(mockRunner);
expect(runnerOptions).toEqual({
runner: 'custom',
runnerOption: 'runner-option',
});
});
it('gets a custom defined default task runner', () => {
jest.mock('custom-default-runner', () => mockRunner, {
virtual: true,
});
nxJson.tasksRunnerOptions = {
default: {
runner: 'custom-default-runner',
},
};
const { tasksRunner } = getRunner({}, nxJson);
expect(tasksRunner).toEqual(mockRunner);
});
it('uses default runner when no tasksRunnerOptions are present', () => { it('uses default runner when no tasksRunnerOptions are present', () => {
jest.mock(join(__dirname, './default-tasks-runner.ts'), () => mockRunner); jest.mock(join(__dirname, './default-tasks-runner.ts'), () => mockRunner);

View File

@ -1064,15 +1064,6 @@ export function getRunner(
const modulePath: string = getTasksRunnerPath(runner, nxJson); const modulePath: string = getTasksRunnerPath(runner, nxJson);
try { try {
if (isCustomRunnerPath(modulePath)) {
output.warn({
title: `Custom task runners will be replaced by a new API starting with Nx 21.`,
bodyLines: [
`For more information, see https://nx.dev/deprecated/custom-tasks-runner`,
],
});
}
const tasksRunner = loadTasksRunner(modulePath); const tasksRunner = loadTasksRunner(modulePath);
return { return {
@ -1095,20 +1086,14 @@ function getTasksRunnerPath(
runner: string, runner: string,
nxJson: NxJsonConfiguration<string[] | '*'> nxJson: NxJsonConfiguration<string[] | '*'>
) { ) {
let modulePath: string = nxJson.tasksRunnerOptions?.[runner]?.runner;
if (modulePath) {
if (isRelativePath(modulePath)) {
return join(workspaceRoot, modulePath);
}
return modulePath;
}
const isCloudRunner = const isCloudRunner =
// No tasksRunnerOptions for given --runner // No tasksRunnerOptions for given --runner
nxJson.nxCloudAccessToken || nxJson.nxCloudAccessToken ||
// No runner prop in tasks runner options, check if access token is set. // No runner prop in tasks runner options, check if access token is set.
nxJson.tasksRunnerOptions?.[runner]?.options?.accessToken || nxJson.tasksRunnerOptions?.[runner]?.options?.accessToken ||
['nx-cloud', '@nrwl/nx-cloud'].includes(
nxJson.tasksRunnerOptions?.[runner]?.runner
) ||
// Cloud access token specified in env var. // Cloud access token specified in env var.
process.env.NX_CLOUD_ACCESS_TOKEN || process.env.NX_CLOUD_ACCESS_TOKEN ||
// Nx Cloud ID specified in nxJson // Nx Cloud ID specified in nxJson
@ -1177,12 +1162,3 @@ export function getRunnerOptions(
return result; return result;
} }
function isCustomRunnerPath(modulePath: string) {
return ![
'nx-cloud',
'@nrwl/nx-cloud',
'nx/tasks-runners/default',
defaultTasksRunnerPath,
].includes(modulePath);
}

View File

@ -290,7 +290,7 @@ export class TaskOrchestrator {
// No output files to restore // No output files to restore
!!outputs.length && !!outputs.length &&
// Remote caches are restored to output dirs when applied and using db cache // Remote caches are restored to output dirs when applied and using db cache
(!cachedResult.remote || !dbCacheEnabled(this.nxJson)) && (!cachedResult.remote || !dbCacheEnabled()) &&
// Output files have not been touched since last run // Output files have not been touched since last run
(await this.shouldCopyOutputsFromCache(outputs, task.hash)); (await this.shouldCopyOutputsFromCache(outputs, task.hash));
if (shouldCopyOutputsFromCache) { if (shouldCopyOutputsFromCache) {