feat(core): allow disabling registered task sync generators (#27638)

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

There's no way to disable sync generators registered in inferred tasks
by a Crystal plugin.

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

There should be a way to disable sync generators registered in inferred
tasks by a Crystal plugin.

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

Fixes #
This commit is contained in:
Leosvel Pérez Espinosa 2024-08-28 16:31:30 +02:00 committed by GitHub
parent a0dc0f1710
commit 97fa7f16f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 99 additions and 24 deletions

View File

@ -282,6 +282,13 @@
"applyChanges": { "applyChanges": {
"type": "boolean", "type": "boolean",
"description": "Whether to automatically apply sync generator changes when running tasks. If not set, the user will be prompted. If set to `true`, the user will not be prompted and the changes will be applied. If set to `false`, the user will not be prompted and the changes will not be applied." "description": "Whether to automatically apply sync generator changes when running tasks. If not set, the user will be prompted. If set to `true`, the user will not be prompted and the changes will be applied. If set to `false`, the user will not be prompted and the changes will not be applied."
},
"disabledTaskSyncGenerators": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of registered task sync generators to disable."
} }
}, },
"additionalProperties": false "additionalProperties": false

View File

@ -1,4 +1,5 @@
import * as ora from 'ora'; import * as ora from 'ora';
import { readNxJson } from '../../config/nx-json';
import { createProjectGraphAsync } from '../../project-graph/project-graph'; import { createProjectGraphAsync } from '../../project-graph/project-graph';
import { output } from '../../utils/output'; import { output } from '../../utils/output';
import { handleErrors } from '../../utils/params'; import { handleErrors } from '../../utils/params';
@ -18,9 +19,22 @@ interface SyncOptions extends SyncArgs {
export function syncHandler(options: SyncOptions): Promise<number> { export function syncHandler(options: SyncOptions): Promise<number> {
return handleErrors(options.verbose, async () => { return handleErrors(options.verbose, async () => {
const projectGraph = await createProjectGraphAsync(); const projectGraph = await createProjectGraphAsync();
const nxJson = readNxJson();
const syncGenerators = await collectAllRegisteredSyncGenerators( const syncGenerators = await collectAllRegisteredSyncGenerators(
projectGraph projectGraph,
nxJson
); );
if (!syncGenerators.length) {
output.success({
title: options.check
? 'The workspace is up to date'
: 'The workspace is already up to date',
bodyLines: ['There are no sync generators to run.'],
});
return 0;
}
const results = await getSyncGeneratorChanges(syncGenerators); const results = await getSyncGeneratorChanges(syncGenerators);
if (!results.length) { if (!results.length) {

View File

@ -321,11 +321,16 @@ export interface NxSyncConfiguration {
/** /**
* Whether to automatically apply sync generator changes when running tasks. * Whether to automatically apply sync generator changes when running tasks.
* If not set, the user will be prompted. * If not set, the user will be prompted in interactive mode.
* If set to `true`, the user will not be prompted and the changes will be applied. * If set to `true`, the user will not be prompted and the changes will be applied.
* If set to `false`, the user will not be prompted and the changes will not be applied. * If set to `false`, the user will not be prompted and the changes will not be applied.
*/ */
applyChanges?: boolean; applyChanges?: boolean;
/**
* List of registered task sync generators to disable.
*/
disabledTaskSyncGenerators?: string[];
} }
/** /**

View File

@ -5,8 +5,8 @@ import { FsTree } from '../../generators/tree';
import { hashArray } from '../../hasher/file-hasher'; import { hashArray } from '../../hasher/file-hasher';
import { readProjectsConfigurationFromProjectGraph } from '../../project-graph/project-graph'; import { readProjectsConfigurationFromProjectGraph } from '../../project-graph/project-graph';
import { import {
collectEnabledTaskSyncGeneratorsFromProjectGraph,
collectRegisteredGlobalSyncGenerators, collectRegisteredGlobalSyncGenerators,
collectRegisteredTaskSyncGenerators,
flushSyncGeneratorChanges, flushSyncGeneratorChanges,
runSyncGenerator, runSyncGenerator,
type SyncGeneratorChangesResult, type SyncGeneratorChangesResult,
@ -28,6 +28,7 @@ let registeredSyncGenerators: Set<string> | undefined;
let scheduledTimeoutId: NodeJS.Timeout | undefined; let scheduledTimeoutId: NodeJS.Timeout | undefined;
let storedProjectGraphHash: string | undefined; let storedProjectGraphHash: string | undefined;
let storedNxJsonHash: string | undefined; let storedNxJsonHash: string | undefined;
let storedDisabledTaskSyncGeneratorsHash: string | undefined;
const log = (...messageParts: unknown[]) => { const log = (...messageParts: unknown[]) => {
serverLogger.log('[SYNC]:', ...messageParts); serverLogger.log('[SYNC]:', ...messageParts);
@ -146,6 +147,12 @@ export function collectAndScheduleSyncGenerators(
// a change imply we need to re-run all the generators // a change imply we need to re-run all the generators
// make sure to schedule all the collected generators // make sure to schedule all the collected generators
scheduledGenerators.clear(); scheduledGenerators.clear();
if (!registeredSyncGenerators.size) {
// there are no generators to run
return;
}
for (const generator of registeredSyncGenerators) { for (const generator of registeredSyncGenerators) {
scheduledGenerators.add(generator); scheduledGenerators.add(generator);
} }
@ -193,16 +200,23 @@ export async function getCachedRegisteredSyncGenerators(): Promise<string[]> {
} }
function collectAllRegisteredSyncGenerators(projectGraph: ProjectGraph): void { function collectAllRegisteredSyncGenerators(projectGraph: ProjectGraph): void {
const nxJson = readNxJson();
const projectGraphHash = hashProjectGraph(projectGraph); const projectGraphHash = hashProjectGraph(projectGraph);
if (storedProjectGraphHash !== projectGraphHash) { const disabledTaskSyncGeneratorsHash = hashArray(
nxJson.sync?.disabledTaskSyncGenerators?.sort() ?? []
);
if (
projectGraphHash !== storedProjectGraphHash ||
disabledTaskSyncGeneratorsHash !== storedDisabledTaskSyncGeneratorsHash
) {
storedProjectGraphHash = projectGraphHash; storedProjectGraphHash = projectGraphHash;
storedDisabledTaskSyncGeneratorsHash = disabledTaskSyncGeneratorsHash;
registeredTaskSyncGenerators = registeredTaskSyncGenerators =
collectRegisteredTaskSyncGenerators(projectGraph); collectEnabledTaskSyncGeneratorsFromProjectGraph(projectGraph, nxJson);
} else { } else {
log('project graph hash is the same, not collecting task sync generators'); log('project graph hash is the same, not collecting task sync generators');
} }
const nxJson = readNxJson();
const nxJsonHash = hashArray(nxJson.sync?.globalGenerators?.sort() ?? []); const nxJsonHash = hashArray(nxJson.sync?.globalGenerators?.sort() ?? []);
if (storedNxJsonHash !== nxJsonHash) { if (storedNxJsonHash !== nxJsonHash) {
storedNxJsonHash = nxJsonHash; storedNxJsonHash = nxJsonHash;

View File

@ -21,6 +21,7 @@ import { isNxCloudUsed } from '../utils/nx-cloud-utils';
import { output } from '../utils/output'; import { output } from '../utils/output';
import { handleErrors } from '../utils/params'; import { handleErrors } from '../utils/params';
import { import {
collectEnabledTaskSyncGeneratorsFromTaskGraph,
flushSyncGeneratorChanges, flushSyncGeneratorChanges,
getSyncGeneratorChanges, getSyncGeneratorChanges,
syncGeneratorResultsToMessageLines, syncGeneratorResultsToMessageLines,
@ -233,18 +234,11 @@ async function ensureWorkspaceIsInSyncAndGetGraphs(
); );
// collect unique syncGenerators from the tasks // collect unique syncGenerators from the tasks
const uniqueSyncGenerators = new Set<string>(); const uniqueSyncGenerators = collectEnabledTaskSyncGeneratorsFromTaskGraph(
for (const { target } of Object.values(taskGraph.tasks)) { taskGraph,
const { syncGenerators } = projectGraph,
projectGraph.nodes[target.project].data.targets[target.target]; nxJson
if (!syncGenerators) { );
continue;
}
for (const generator of syncGenerators) {
uniqueSyncGenerators.add(generator);
}
}
if (!uniqueSyncGenerators.size) { if (!uniqueSyncGenerators.size) {
// There are no sync generators registered in the tasks to run // There are no sync generators registered in the tasks to run

View File

@ -2,8 +2,9 @@ import { performance } from 'perf_hooks';
import { parseGeneratorString } from '../command-line/generate/generate'; import { parseGeneratorString } from '../command-line/generate/generate';
import { getGeneratorInformation } from '../command-line/generate/generator-utils'; import { getGeneratorInformation } from '../command-line/generate/generator-utils';
import type { GeneratorCallback } from '../config/misc-interfaces'; import type { GeneratorCallback } from '../config/misc-interfaces';
import { readNxJson } from '../config/nx-json'; import { readNxJson, type NxJsonConfiguration } from '../config/nx-json';
import type { ProjectGraph } from '../config/project-graph'; import type { ProjectGraph } from '../config/project-graph';
import type { TaskGraph } from '../config/task-graph';
import type { ProjectConfiguration } from '../config/workspace-json-project-json'; import type { ProjectConfiguration } from '../config/workspace-json-project-json';
import { daemonClient } from '../daemon/client/client'; import { daemonClient } from '../daemon/client/client';
import { isOnDaemon } from '../daemon/is-on-daemon'; import { isOnDaemon } from '../daemon/is-on-daemon';
@ -72,11 +73,12 @@ export async function flushSyncGeneratorChanges(
} }
export async function collectAllRegisteredSyncGenerators( export async function collectAllRegisteredSyncGenerators(
projectGraph: ProjectGraph projectGraph: ProjectGraph,
nxJson: NxJsonConfiguration
): Promise<string[]> { ): Promise<string[]> {
if (!daemonClient.enabled()) { if (!daemonClient.enabled()) {
return [ return [
...collectRegisteredTaskSyncGenerators(projectGraph), ...collectEnabledTaskSyncGeneratorsFromProjectGraph(projectGraph, nxJson),
...collectRegisteredGlobalSyncGenerators(), ...collectRegisteredGlobalSyncGenerators(),
]; ];
} }
@ -122,10 +124,14 @@ export async function runSyncGenerator(
}; };
} }
export function collectRegisteredTaskSyncGenerators( export function collectEnabledTaskSyncGeneratorsFromProjectGraph(
projectGraph: ProjectGraph projectGraph: ProjectGraph,
nxJson: NxJsonConfiguration
): Set<string> { ): Set<string> {
const taskSyncGenerators = new Set<string>(); const taskSyncGenerators = new Set<string>();
const disabledTaskSyncGenerators = new Set(
nxJson.sync?.disabledTaskSyncGenerators ?? []
);
for (const { for (const {
data: { targets }, data: { targets },
@ -135,11 +141,46 @@ export function collectRegisteredTaskSyncGenerators(
} }
for (const target of Object.values(targets)) { for (const target of Object.values(targets)) {
if (!target.syncGenerators) { if (!target.syncGenerators?.length) {
continue; continue;
} }
for (const generator of target.syncGenerators) { for (const generator of target.syncGenerators) {
if (
!disabledTaskSyncGenerators.has(generator) &&
!taskSyncGenerators.has(generator)
) {
taskSyncGenerators.add(generator);
}
}
}
}
return taskSyncGenerators;
}
export function collectEnabledTaskSyncGeneratorsFromTaskGraph(
taskGraph: TaskGraph,
projectGraph: ProjectGraph,
nxJson: NxJsonConfiguration
): Set<string> {
const taskSyncGenerators = new Set<string>();
const disabledTaskSyncGenerators = new Set(
nxJson.sync?.disabledTaskSyncGenerators ?? []
);
for (const { target } of Object.values(taskGraph.tasks)) {
const { syncGenerators } =
projectGraph.nodes[target.project].data.targets[target.target];
if (!syncGenerators?.length) {
continue;
}
for (const generator of syncGenerators) {
if (
!disabledTaskSyncGenerators.has(generator) &&
!taskSyncGenerators.has(generator)
) {
taskSyncGenerators.add(generator); taskSyncGenerators.add(generator);
} }
} }