diff --git a/docs/generated/cli/login.md b/docs/generated/cli/login.md new file mode 100644 index 0000000000..628e9e7f2a --- /dev/null +++ b/docs/generated/cli/login.md @@ -0,0 +1,42 @@ +--- +title: 'login - CLI command' +description: 'Login to Nx Cloud' +--- + +# login + +Login to Nx Cloud + +## Usage + +```shell +nx login [nxCloudUrl] +``` + +Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`. + +## Options + +### help + +Type: `boolean` + +Show help + +### nxCloudUrl + +Type: `string` + +The Nx Cloud URL of the instance you are trying to connect to. If no positional argument is provided, this command will connect to https://cloud.nx.app. + +### verbose + +Type: `boolean` + +Prints additional information about the commands (e.g., stack traces) + +### version + +Type: `boolean` + +Show version number diff --git a/docs/generated/cli/logout.md b/docs/generated/cli/logout.md new file mode 100644 index 0000000000..1c6bec6d68 --- /dev/null +++ b/docs/generated/cli/logout.md @@ -0,0 +1,36 @@ +--- +title: 'logout - CLI command' +description: 'Logout from Nx Cloud' +--- + +# logout + +Logout from Nx Cloud + +## Usage + +```shell +nx logout +``` + +Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`. + +## Options + +### help + +Type: `boolean` + +Show help + +### verbose + +Type: `boolean` + +Prints additional information about the commands (e.g., stack traces) + +### version + +Type: `boolean` + +Show version number diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index 6fc7630270..68cd1389e8 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -8712,6 +8712,22 @@ "isExternal": false, "children": [], "disableCollapsible": false + }, + { + "name": "login", + "path": "/nx-api/nx/documents/login", + "id": "login", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "logout", + "path": "/nx-api/nx/documents/logout", + "id": "logout", + "isExternal": false, + "children": [], + "disableCollapsible": false } ], "isExternal": false, diff --git a/docs/generated/manifests/nx-api.json b/docs/generated/manifests/nx-api.json index f6db8ce949..7634ba456a 100644 --- a/docs/generated/manifests/nx-api.json +++ b/docs/generated/manifests/nx-api.json @@ -1967,6 +1967,28 @@ "path": "/nx-api/nx/documents/add", "tags": [], "originalFilePath": "generated/cli/add" + }, + "/nx-api/nx/documents/login": { + "id": "login", + "name": "login", + "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.", + "file": "generated/packages/nx/documents/login", + "itemList": [], + "isExternal": false, + "path": "/nx-api/nx/documents/login", + "tags": [], + "originalFilePath": "generated/cli/login" + }, + "/nx-api/nx/documents/logout": { + "id": "logout", + "name": "logout", + "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.", + "file": "generated/packages/nx/documents/logout", + "itemList": [], + "isExternal": false, + "path": "/nx-api/nx/documents/logout", + "tags": [], + "originalFilePath": "generated/cli/logout" } }, "root": "/packages/nx", diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index ef779f9643..61e869d0fa 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -1946,6 +1946,28 @@ "path": "nx/documents/add", "tags": [], "originalFilePath": "generated/cli/add" + }, + { + "id": "login", + "name": "login", + "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.", + "file": "generated/packages/nx/documents/login", + "itemList": [], + "isExternal": false, + "path": "nx/documents/login", + "tags": [], + "originalFilePath": "generated/cli/login" + }, + { + "id": "logout", + "name": "logout", + "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.", + "file": "generated/packages/nx/documents/logout", + "itemList": [], + "isExternal": false, + "path": "nx/documents/logout", + "tags": [], + "originalFilePath": "generated/cli/logout" } ], "executors": [ diff --git a/docs/generated/packages/nx/documents/login.md b/docs/generated/packages/nx/documents/login.md new file mode 100644 index 0000000000..628e9e7f2a --- /dev/null +++ b/docs/generated/packages/nx/documents/login.md @@ -0,0 +1,42 @@ +--- +title: 'login - CLI command' +description: 'Login to Nx Cloud' +--- + +# login + +Login to Nx Cloud + +## Usage + +```shell +nx login [nxCloudUrl] +``` + +Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`. + +## Options + +### help + +Type: `boolean` + +Show help + +### nxCloudUrl + +Type: `string` + +The Nx Cloud URL of the instance you are trying to connect to. If no positional argument is provided, this command will connect to https://cloud.nx.app. + +### verbose + +Type: `boolean` + +Prints additional information about the commands (e.g., stack traces) + +### version + +Type: `boolean` + +Show version number diff --git a/docs/generated/packages/nx/documents/logout.md b/docs/generated/packages/nx/documents/logout.md new file mode 100644 index 0000000000..1c6bec6d68 --- /dev/null +++ b/docs/generated/packages/nx/documents/logout.md @@ -0,0 +1,36 @@ +--- +title: 'logout - CLI command' +description: 'Logout from Nx Cloud' +--- + +# logout + +Logout from Nx Cloud + +## Usage + +```shell +nx logout +``` + +Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`, `yarn nx`, or `pnpm nx`. + +## Options + +### help + +Type: `boolean` + +Show help + +### verbose + +Type: `boolean` + +Prints additional information about the commands (e.g., stack traces) + +### version + +Type: `boolean` + +Show version number diff --git a/docs/map.json b/docs/map.json index 4619f93e97..d0c5f2df84 100644 --- a/docs/map.json +++ b/docs/map.json @@ -2112,6 +2112,16 @@ "name": "add", "id": "add", "file": "generated/cli/add" + }, + { + "name": "login", + "id": "login", + "file": "generated/cli/login" + }, + { + "name": "logout", + "id": "logout", + "file": "generated/cli/logout" } ] }, diff --git a/docs/shared/reference/sitemap.md b/docs/shared/reference/sitemap.md index 1975ffde2d..29704e8fa6 100644 --- a/docs/shared/reference/sitemap.md +++ b/docs/shared/reference/sitemap.md @@ -558,6 +558,8 @@ - [view-logs](/nx-api/nx/documents/view-logs) - [release](/nx-api/nx/documents/release) - [add](/nx-api/nx/documents/add) + - [login](/nx-api/nx/documents/login) + - [logout](/nx-api/nx/documents/logout) - [executors](/nx-api/nx/executors) - [noop](/nx-api/nx/executors/noop) - [run-commands](/nx-api/nx/executors/run-commands) diff --git a/packages/nx/src/command-line/connect/connect-to-nx-cloud.ts b/packages/nx/src/command-line/connect/connect-to-nx-cloud.ts index 054c9c467f..a1c37c3947 100644 --- a/packages/nx/src/command-line/connect/connect-to-nx-cloud.ts +++ b/packages/nx/src/command-line/connect/connect-to-nx-cloud.ts @@ -80,10 +80,12 @@ export async function connectToNxCloudCommand( if (isNxCloudUsed(nxJson)) { const token = - process.env.NX_CLOUD_ACCESS_TOKEN || nxJson.nxCloudAccessToken; + process.env.NX_CLOUD_ACCESS_TOKEN || + nxJson.nxCloudAccessToken || + nxJson.nxCloudId; if (!token) { throw new Error( - `Unable to authenticate. Either define accessToken in nx.json or set the NX_CLOUD_ACCESS_TOKEN env variable.` + `Unable to authenticate. If you are connecting to Nx Cloud locally, set Nx Cloud ID in nx.json. If you are connecting in a CI context, either define accessToken in nx.json or set the NX_CLOUD_ACCESS_TOKEN env variable.` ); } const connectCloudUrl = await createNxCloudOnboardingURL( @@ -93,10 +95,9 @@ export async function connectToNxCloudCommand( output.log({ title: '✔ This workspace already has Nx Cloud set up', bodyLines: [ - 'If you have not done so already, connect your workspace to your Nx Cloud account:', - `- Connect with Nx Cloud at: - - ${connectCloudUrl}`, + 'If you have not done so already, connect your workspace to your Nx Cloud account with the following URL:', + '', + `${connectCloudUrl}`, ], }); diff --git a/packages/nx/src/command-line/login/command-object.ts b/packages/nx/src/command-line/login/command-object.ts new file mode 100644 index 0000000000..9d8ad15c83 --- /dev/null +++ b/packages/nx/src/command-line/login/command-object.ts @@ -0,0 +1,19 @@ +import { CommandModule } from 'yargs'; +import { withVerbose } from '../../command-line/yargs-utils/shared-options'; + +export const yargsLoginCommand: CommandModule = { + command: 'login [nxCloudUrl]', + describe: 'Login to Nx Cloud', + builder: (yargs) => + withVerbose( + yargs.positional('nxCloudUrl', { + describe: + 'The Nx Cloud URL of the instance you are trying to connect to. If no positional argument is provided, this command will connect to https://cloud.nx.app.', + type: 'string', + required: false, + }) + ), + handler: async (args: any) => { + process.exit(await (await import('./login')).loginHandler(args)); + }, +}; diff --git a/packages/nx/src/command-line/login/login.ts b/packages/nx/src/command-line/login/login.ts new file mode 100644 index 0000000000..9404f9a867 --- /dev/null +++ b/packages/nx/src/command-line/login/login.ts @@ -0,0 +1,20 @@ +import { verifyOrUpdateNxCloudClient } from '../../nx-cloud/update-manager'; +import { getCloudOptions } from '../../nx-cloud/utilities/get-cloud-options'; +import { handleErrors } from '../../utils/params'; + +export interface LoginArgs { + nxCloudUrl?: string; + verbose?: boolean; +} + +export function loginHandler(args: LoginArgs): Promise { + if (args.nxCloudUrl) { + process.env.NX_CLOUD_API = args.nxCloudUrl; + } + + return handleErrors(args.verbose, async () => { + const nxCloudClient = (await verifyOrUpdateNxCloudClient(getCloudOptions())) + .nxCloudClient; + await nxCloudClient.commands.login(); + }); +} diff --git a/packages/nx/src/command-line/logout/command-object.ts b/packages/nx/src/command-line/logout/command-object.ts new file mode 100644 index 0000000000..840fae0842 --- /dev/null +++ b/packages/nx/src/command-line/logout/command-object.ts @@ -0,0 +1,11 @@ +import { CommandModule } from 'yargs'; +import { withVerbose } from '../../command-line/yargs-utils/shared-options'; + +export const yargsLogoutCommand: CommandModule = { + command: 'logout', + describe: 'Logout from Nx Cloud', + builder: (yargs) => withVerbose(yargs), + handler: async (args: any) => { + process.exit(await (await import('./logout')).logoutHandler(args)); + }, +}; diff --git a/packages/nx/src/command-line/logout/logout.ts b/packages/nx/src/command-line/logout/logout.ts new file mode 100644 index 0000000000..685fb9b57e --- /dev/null +++ b/packages/nx/src/command-line/logout/logout.ts @@ -0,0 +1,15 @@ +import { verifyOrUpdateNxCloudClient } from '../../nx-cloud/update-manager'; +import { getCloudOptions } from '../../nx-cloud/utilities/get-cloud-options'; +import { handleErrors } from '../../utils/params'; + +export interface LogoutArgs { + verbose?: boolean; +} + +export function logoutHandler(args: LogoutArgs): Promise { + return handleErrors(args.verbose, async () => { + const nxCloudClient = (await verifyOrUpdateNxCloudClient(getCloudOptions())) + .nxCloudClient; + await nxCloudClient.commands.logout(); + }); +} diff --git a/packages/nx/src/command-line/nx-commands.ts b/packages/nx/src/command-line/nx-commands.ts index c5d57ead8a..f9524f2e37 100644 --- a/packages/nx/src/command-line/nx-commands.ts +++ b/packages/nx/src/command-line/nx-commands.ts @@ -37,6 +37,8 @@ import { yargsWatchCommand } from './watch/command-object'; import { yargsResetCommand } from './reset/command-object'; import { yargsReleaseCommand } from './release/command-object'; import { yargsAddCommand } from './add/command-object'; +import { yargsLoginCommand } from './login/command-object'; +import { yargsLogoutCommand } from './logout/command-object'; import { yargsPrintAffectedCommand, yargsAffectedGraphCommand, @@ -94,6 +96,8 @@ export const commandsObject = yargs .command(yargsViewLogsCommand) .command(yargsWatchCommand) .command(yargsNxInfixCommand) + .command(yargsLoginCommand) + .command(yargsLogoutCommand) .scriptName('nx') .help() // NOTE: we handle --version in nx.ts, this just tells yargs that the option exists diff --git a/packages/nx/src/nx-cloud/utilities/axios.ts b/packages/nx/src/nx-cloud/utilities/axios.ts index 5d7c0f3b24..7954ca2822 100644 --- a/packages/nx/src/nx-cloud/utilities/axios.ts +++ b/packages/nx/src/nx-cloud/utilities/axios.ts @@ -18,15 +18,9 @@ export function createApiAxiosInstance(options: CloudTaskRunnerOptions) { // TODO(lourw): Update message with NxCloudId once it is supported if (!accessToken && !nxCloudId) { - if (process.env.NX_ENABLE_LOGIN === 'true' && !nxCloudId) { - throw new Error( - `Unable to authenticate. Please connect your workspace to Nx Cloud to define a valid Nx Cloud Id. If you are in a CI context, please set the NX_CLOUD_ACCESS_TOKEN environment variable or define an access token in your nx.json.` - ); - } else { - throw new Error( - `Unable to authenticate. Either define accessToken in nx.json or set the NX_CLOUD_ACCESS_TOKEN env variable. If you do not want to use Nx Cloud for this command, either set NX_NO_CLOUD=true, or pass the --no-cloud flag.` - ); - } + throw new Error( + `Unable to authenticate. If you are connecting to Nx Cloud locally, set an Nx Cloud ID in your nx.json with "nx connect". If you are in a CI context, please set the NX_CLOUD_ACCESS_TOKEN environment variable or define an access token in your nx.json.` + ); } if (options.customProxyConfigPath) { diff --git a/packages/nx/src/tasks-runner/run-command.ts b/packages/nx/src/tasks-runner/run-command.ts index 82de15ef9f..f6c774b754 100644 --- a/packages/nx/src/tasks-runner/run-command.ts +++ b/packages/nx/src/tasks-runner/run-command.ts @@ -671,7 +671,7 @@ function getTasksRunnerPath( nxJson.tasksRunnerOptions?.[runner]?.options?.accessToken || // Cloud access token specified in env var. process.env.NX_CLOUD_ACCESS_TOKEN || - // Nx Cloud Id specified in nxJson + // Nx Cloud ID specified in nxJson nxJson.nxCloudId; return isCloudRunner ? 'nx-cloud' : require.resolve('./default-tasks-runner');