fix(core): reset should cleanup temporary nx-cloud files (#23316)

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

## Current Behavior
<!-- This is the behavior we have today -->
`nx reset` doesn't remove marker files used by nx cloud.
## Expected Behavior
`nx reset` removes marker files from nx cloud

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

Fixes #https://github.com/nrwl/nx/issues/23308
This commit is contained in:
Craigory Coppola 2024-07-24 15:39:14 -04:00 committed by GitHub
parent 467f343e3d
commit b7472fdd41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 80 additions and 19 deletions

View File

@ -55,6 +55,12 @@ Type: `boolean`
Clears the Nx cache directory. This will remove all local cache entries for tasks, but will not affect the remote cache. Clears the Nx cache directory. This will remove all local cache entries for tasks, but will not affect the remote cache.
### onlyCloud
Type: `boolean`
Resets the Nx Cloud client. NOTE: Does not clear the remote cache.
### onlyDaemon ### onlyDaemon
Type: `boolean` Type: `boolean`

View File

@ -55,6 +55,12 @@ Type: `boolean`
Clears the Nx cache directory. This will remove all local cache entries for tasks, but will not affect the remote cache. Clears the Nx cache directory. This will remove all local cache entries for tasks, but will not affect the remote cache.
### onlyCloud
Type: `boolean`
Resets the Nx Cloud client. NOTE: Does not clear the remote cache.
### onlyDaemon ### onlyDaemon
Type: `boolean` Type: `boolean`

View File

@ -1,14 +1,16 @@
#!/usr/bin/env node #!/usr/bin/env node
import { findAncestorNodeModules } from '../src/nx-cloud/resolution-helpers';
import { getCloudOptions } from '../src/nx-cloud/utilities/get-cloud-options'; import { getCloudOptions } from '../src/nx-cloud/utilities/get-cloud-options';
import { import {
NxCloudClientUnavailableError, NxCloudClientUnavailableError,
NxCloudEnterpriseOutdatedError, NxCloudEnterpriseOutdatedError,
verifyOrUpdateNxCloudClient,
} from '../src/nx-cloud/update-manager'; } from '../src/nx-cloud/update-manager';
import type { CloudTaskRunnerOptions } from '../src/nx-cloud/nx-cloud-tasks-runner-shell'; import type { CloudTaskRunnerOptions } from '../src/nx-cloud/nx-cloud-tasks-runner-shell';
import { output } from '../src/utils/output'; import { output } from '../src/utils/output';
import {
UnknownCommandError,
getCloudClient,
} from '../src/nx-cloud/utilities/client';
const command = process.argv[2]; const command = process.argv[2];
@ -16,31 +18,23 @@ const options = getCloudOptions();
Promise.resolve().then(async () => invokeCommandWithNxCloudClient(options)); Promise.resolve().then(async () => invokeCommandWithNxCloudClient(options));
async function invokeCommandWithNxCloudClient(options: CloudTaskRunnerOptions) { export async function invokeCommandWithNxCloudClient(
options: CloudTaskRunnerOptions
) {
try { try {
const { nxCloudClient } = await verifyOrUpdateNxCloudClient(options); const client = await getCloudClient(options);
client.invoke(command);
const paths = findAncestorNodeModules(__dirname, []); } catch (e: any) {
nxCloudClient.configureLightClientRequire()(paths); if (e instanceof UnknownCommandError) {
if (command in nxCloudClient.commands) {
nxCloudClient.commands[command]()
.then(() => process.exit(0))
.catch((e) => {
console.error(e);
process.exit(1);
});
} else {
output.error({ output.error({
title: `Unknown Command "${command}"`, title: `Unknown Command "${e.command}"`,
}); });
output.log({ output.log({
title: 'Available Commands:', title: 'Available Commands:',
bodyLines: Object.keys(nxCloudClient.commands).map((c) => `- ${c}`), bodyLines: e.availableCommands.map((c) => `- ${c}`),
}); });
process.exit(1); process.exit(1);
} }
} catch (e: any) {
const body = ['Cannot run commands from the `nx-cloud` CLI.']; const body = ['Cannot run commands from the `nx-cloud` CLI.'];
if (e instanceof NxCloudEnterpriseOutdatedError) { if (e instanceof NxCloudEnterpriseOutdatedError) {

View File

@ -4,6 +4,7 @@ export type ResetCommandOptions = {
onlyCache?: boolean; onlyCache?: boolean;
onlyDaemon?: boolean; onlyDaemon?: boolean;
onlyWorkspaceData?: boolean; onlyWorkspaceData?: boolean;
onlyCloud?: boolean;
}; };
export const yargsResetCommand: CommandModule< export const yargsResetCommand: CommandModule<
@ -26,6 +27,11 @@ export const yargsResetCommand: CommandModule<
'Stops the Nx Daemon, it will be restarted fresh when the next Nx command is run.', 'Stops the Nx Daemon, it will be restarted fresh when the next Nx command is run.',
type: 'boolean', type: 'boolean',
}) })
.option('onlyCloud', {
description:
'Resets the Nx Cloud client. NOTE: Does not clear the remote cache.',
type: 'boolean',
})
.option('onlyWorkspaceData', { .option('onlyWorkspaceData', {
description: description:
'Clears the workspace data directory. Used by Nx to store cached data about the current workspace (e.g. partial results, incremental data, etc)', 'Clears the workspace data directory. Used by Nx to store cached data about the current workspace (e.g. partial results, incremental data, etc)',

View File

@ -5,6 +5,9 @@ import { output } from '../../utils/output';
import { getNativeFileCacheLocation } from '../../native/native-file-cache-location'; import { getNativeFileCacheLocation } from '../../native/native-file-cache-location';
import { ResetCommandOptions } from './command-object'; import { ResetCommandOptions } from './command-object';
import { getCloudClient } from '../../nx-cloud/utilities/client';
import { getCloudOptions } from '../../nx-cloud/utilities/get-cloud-options';
// Wait at max 5 seconds before giving up on a failing operation. // Wait at max 5 seconds before giving up on a failing operation.
const INCREMENTAL_BACKOFF_MAX_DURATION = 5000; const INCREMENTAL_BACKOFF_MAX_DURATION = 5000;
@ -62,6 +65,9 @@ export async function resetHandler(args: ResetCommandOptions) {
errors.push('Failed to clean up the workspace data directory.'); errors.push('Failed to clean up the workspace data directory.');
} }
} }
if (all || args.onlyCloud) {
await resetCloudClient();
}
if (errors.length > 0) { if (errors.length > 0) {
output.error({ output.error({
title: 'Failed to reset the Nx workspace.', title: 'Failed to reset the Nx workspace.',
@ -79,6 +85,14 @@ function killDaemon() {
return daemonClient.stop(); return daemonClient.stop();
} }
async function resetCloudClient() {
// Remove nx cloud marker files. This helps if the use happens to run `nx-cloud start-ci-run` or
// similar commands on their local machine.
try {
(await getCloudClient(getCloudOptions())).invoke('cleanup');
} catch {}
}
function cleanupCacheEntries() { function cleanupCacheEntries() {
return incrementalBackoff( return incrementalBackoff(
INCREMENTAL_BACKOFF_FIRST_DELAY, INCREMENTAL_BACKOFF_FIRST_DELAY,

View File

@ -0,0 +1,35 @@
import { findAncestorNodeModules } from '../resolution-helpers';
import { verifyOrUpdateNxCloudClient } from '../update-manager';
import { CloudTaskRunnerOptions } from '../nx-cloud-tasks-runner-shell';
export class UnknownCommandError extends Error {
constructor(public command: string, public availableCommands: string[]) {
super(`Unknown Command "${command}"`);
}
}
export async function getCloudClient(options: CloudTaskRunnerOptions) {
const { nxCloudClient } = await verifyOrUpdateNxCloudClient(options);
const paths = findAncestorNodeModules(__dirname, []);
nxCloudClient.configureLightClientRequire()(paths);
return {
invoke: (command: string) => {
if (command in nxCloudClient.commands) {
nxCloudClient.commands[command]()
.then(() => process.exit(0))
.catch((e) => {
console.error(e);
process.exit(1);
});
} else {
throw new UnknownCommandError(
command,
Object.keys(nxCloudClient.commands)
);
}
},
availableCommands: Object.keys(nxCloudClient.commands),
};
}