Skip to content

Commit

Permalink
fix: consider dev/prod mode in more scenarios (#1457)
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKless authored Dec 28, 2022
1 parent cafa427 commit 5e8e25c
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
ProgressLocation,
window,
} from 'vscode';
import { OAuthService } from './oauth.service';
import { AuthConfig, OAuthService } from './oauth.service';
import { SecretSessionStore } from './secret-session-store';

export const AUTH_NAME = 'Nx Cloud';
Expand All @@ -28,7 +28,7 @@ export class NxCloudAuthenticationProvider
private _secretSessionStore: SecretSessionStore;
private _oAuthService: OAuthService;

constructor(readonly context: ExtensionContext, config: 'prod' | 'dev') {
constructor(readonly context: ExtensionContext, config: AuthConfig) {
this._secretSessionStore = new SecretSessionStore(context);
this._oAuthService = new OAuthService(context, config);

Expand Down
36 changes: 14 additions & 22 deletions libs/vscode/nx-cloud-view/src/lib/auth/oauth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,18 @@ import {
window,
} from 'vscode';

const staging_config = {
clientId: '11Zte67xGtfrGQhRVlz9zM8Fq0LvZYwe',
audience: 'https://api.staging.nrwl.io/',
domain: 'https://auth.staging.nx.app/login',
};

const prod_config = {
clientId: 'm6PYBsCK1t2DTKnbE30n029C22fqtTMm',
audience: 'https://api.nrwl.io/',
domain: 'https://nrwl.auth0.com/login',
export type AuthConfig = {
clientId: string;
audience: string;
domain: string;
};

export class OAuthService {
private _oAuthConfig: { clientId: string; audience: string; domain: string };
private _codeExchangePromise: Promise<string | undefined> | undefined;
private _stateId: string | undefined;
private _uriHandler = new UriEventHandler();

constructor(private context: ExtensionContext, config: 'prod' | 'dev') {
this._oAuthConfig = config === 'prod' ? prod_config : staging_config;
constructor(private context: ExtensionContext, private config: AuthConfig) {
window.registerUriHandler(this._uriHandler);
}
get redirectUri() {
Expand Down Expand Up @@ -80,15 +72,15 @@ export class OAuthService {

const searchParams = new URLSearchParams([
['response_type', 'code'],
['client_id', this._oAuthConfig.clientId],
['client_id', this.config.clientId],
['redirect_uri', this.redirectUri],
['state', this._stateId],
['scope', scopeString],
['audience', this._oAuthConfig.audience],
['audience', this.config.audience],
]);

const uri = Uri.parse(
`${this._oAuthConfig.domain}/authorize?${searchParams.toString()}`
`${this.config.domain}/authorize?${searchParams.toString()}`
);
await env.openExternal(uri);

Expand Down Expand Up @@ -129,15 +121,15 @@ export class OAuthService {
): Promise<{ access_token: string; refresh_token: string } | undefined> {
const searchParams = new URLSearchParams([
['grant_type', 'authorization_code'],
['client_id', this._oAuthConfig.clientId],
['client_id', this.config.clientId],
['code', authCode],
['redirect_uri', this.redirectUri],
['audience', this._oAuthConfig.audience],
['audience', this.config.audience],
]);
try {
return await xhr({
type: 'POST',
url: `${this._oAuthConfig.domain}/oauth/token`,
url: `${this.config.domain}/oauth/token`,
data: searchParams.toString(),
headers: { 'content-type': 'application/x-www-form-urlencoded' },
}).then((r) => {
Expand All @@ -151,7 +143,7 @@ export class OAuthService {
async getUserInfo(token: string) {
try {
const response = await xhr({
url: `${this._oAuthConfig.domain}/userinfo`,
url: `${this.config.domain}/userinfo`,
headers: {
Authorization: `Bearer ${token}`,
},
Expand Down Expand Up @@ -188,14 +180,14 @@ export class OAuthService {
const searchParams = new URLSearchParams([
['grant_type', 'refresh_token'],
['refresh_token', refreshToken],
['client_id', this._oAuthConfig.clientId],
['client_id', this.config.clientId],
['redirect_uri', this.redirectUri],
['scope', scopes.join(' ')],
]);
try {
return await xhr({
type: 'POST',
url: `${this._oAuthConfig.domain}/oauth/token`,
url: `${this.config.domain}/oauth/token`,
data: searchParams.toString(),
headers: {
'content-type': 'application/x-www-form-urlencoded',
Expand Down
29 changes: 29 additions & 0 deletions libs/vscode/nx-cloud-view/src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export type CloudConfig = {
authConfig: {
clientId: string;
audience: string;
domain: string;
};
endpoint: string;
appUrl: string;
};

export const stagingConfig = {
authConfig: {
clientId: '11Zte67xGtfrGQhRVlz9zM8Fq0LvZYwe',
audience: 'https://api.staging.nrwl.io/',
domain: 'https://auth.staging.nx.app/login',
},
endpoint: 'https://staging.nx.app/api',
appUrl: 'http://staging.nx.app',
};

export const prodConfig = {
authConfig: {
clientId: 'm6PYBsCK1t2DTKnbE30n029C22fqtTMm',
audience: 'https://api.nrwl.io/',
domain: 'https://auth.nx.app/login',
},
endpoint: 'https://cloud.nx.app/api',
appUrl: 'https://cloud.nx.app',
};
33 changes: 30 additions & 3 deletions libs/vscode/nx-cloud-view/src/lib/init-nx-cloud-onboarding-view.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { getNxCloudRunnerOptions } from '@nx-console/vscode/nx-workspace';
import { commands, ExtensionContext, window } from 'vscode';
import { NxCloudAuthenticationProvider } from './auth/nx-cloud-authentication-provider';
import { CloudConfig, prodConfig, stagingConfig } from './config';
import { REFRESH_COMMAND } from './nx-cloud-service/commands';
import { NxCloudService } from './nx-cloud-service/nx-cloud-service';
import { NxCloudWebviewProvider } from './nx-cloud-webview-provider';

export function initNxCloudOnboardingView(
export async function initNxCloudOnboardingView(
context: ExtensionContext,
production: boolean
) {
const config = production ? 'prod' : 'dev';
const config = await determineProdOrStagingConfig(production);

const nxCloudService = new NxCloudService(config);
const nxCloudWebviewProvider = new NxCloudWebviewProvider(
context.extensionUri,
Expand All @@ -18,7 +21,7 @@ export function initNxCloudOnboardingView(

const nxCloudAuthenticationProvider = new NxCloudAuthenticationProvider(
context,
config
config.authConfig
);

context.subscriptions.push(
Expand All @@ -30,3 +33,27 @@ export function initNxCloudOnboardingView(
})
);
}

/**
* Determines which endpoint to use for API calls and auth
* it's set to staging in dev mode and prod in production mode by default
* if the cloud runner is used, we will use that (as long as it matches either the staging or prod endpoint)
* */
async function determineProdOrStagingConfig(
productionEnv: boolean
): Promise<CloudConfig> {
const nxCloudRunnerOptions = await getNxCloudRunnerOptions();

// if we're using the cloud runner but no URL is defined, it means an implicit prod endpoint
const nxCloudRunnerUrl = nxCloudRunnerOptions
? nxCloudRunnerOptions.url ?? prodConfig.appUrl
: '';

if (nxCloudRunnerUrl === stagingConfig.appUrl) {
return stagingConfig;
}
if (nxCloudRunnerUrl === prodConfig.appUrl) {
return prodConfig;
}
return productionEnv ? prodConfig : stagingConfig;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,8 @@ import {
VCSIntegrationStatusResponse,
} from './models';

const stagingEndpoint = 'https://staging.nx.app/api';
const prodEndpoint = 'https://cloud.nx.app/api';

export class NxCloudApiService {
endpoint: string;

constructor(private config: 'prod' | 'dev') {
this.endpoint = config === 'dev' ? stagingEndpoint : prodEndpoint;
}
constructor(private endpoint: string) {}
async claimCloudWorkspace(
orgId: string
): Promise<ConnectWorkspaceUsingTokenResponse> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { getPackageManagerCommand } from '@nrwl/devkit';
import { WorkspaceConfigurationStore } from '@nx-console/vscode/configuration';
import { EXECUTE_ARBITRARY_COMMAND } from '@nx-console/vscode/nx-commands-view';
import { getNxWorkspace } from '@nx-console/vscode/nx-workspace';
import {
getNxCloudRunnerOptions,
getNxWorkspace,
} from '@nx-console/vscode/nx-workspace';
import {
getTelemetry,
getWorkspacePath,
Expand All @@ -26,6 +29,7 @@ import {
tasks,
window,
} from 'vscode';
import { CloudConfig, prodConfig, stagingConfig } from '../config';
import {
CLAIM_COMMAND,
INSPECT_RUN_COMMAND,
Expand Down Expand Up @@ -97,9 +101,9 @@ export type WebviewState = Pick<
export class NxCloudService extends StateBaseService<InternalState> {
private nxCloudApiService: NxCloudApiService;

constructor(config: 'prod' | 'dev') {
constructor(private config: CloudConfig) {
super(initialInternalState);
this.nxCloudApiService = new NxCloudApiService(config);
this.nxCloudApiService = new NxCloudApiService(config.endpoint);

this.listenForNxJsonChanges();
this.listenForWorkspaceDetails();
Expand Down Expand Up @@ -209,6 +213,14 @@ export class NxCloudService extends StateBaseService<InternalState> {
'latest'
);

const cloudRunnerUrl =
this.config.appUrl === stagingConfig.appUrl
? stagingConfig.appUrl
: undefined;
const env = cloudRunnerUrl
? { ...process.env, NX_CLOUD_API: this.config.appUrl }
: process.env;

window.withProgress(
{
location: ProgressLocation.Notification,
Expand All @@ -229,7 +241,7 @@ export class NxCloudService extends StateBaseService<InternalState> {
`${
getPackageManagerCommand().exec
} nx g @nrwl/nx-cloud:init`,
{ cwd: getWorkspacePath() }
{ cwd: getWorkspacePath(), env }
).then(() => resolve(true));
})
.catch((e) => {
Expand All @@ -254,7 +266,7 @@ export class NxCloudService extends StateBaseService<InternalState> {
? 'connect'
: 'connect-to-nx-cloud',
],
{ cwd: getWorkspacePath(), shell: true }
{ cwd: getWorkspacePath(), env, shell: true }
);

commandProcess.stdout.setEncoding('utf8');
Expand Down Expand Up @@ -394,8 +406,7 @@ export class NxCloudService extends StateBaseService<InternalState> {
}

private async openRunDetails(runLinkId: string) {
const url = await this.getNxCloudBaseUrl();

const url = await this.getCloudRunnerUrl();
commands.executeCommand(
'vscode.open',
`${url}/runs/${runLinkId}?utm_source=nxconsole`
Expand All @@ -412,7 +423,7 @@ export class NxCloudService extends StateBaseService<InternalState> {
}
const orgId = this.state.cloudWorkspaceOrgId;
const workspaceId = this.state.cloudWorkspaceId;
const baseUrl = await this.getNxCloudBaseUrl();
const baseUrl = await this.getCloudRunnerUrl();

const link = `${baseUrl}/orgs/${orgId}/workspaces/${workspaceId}/set-up-vcs-integration?utm_source=nxconsole`;

Expand Down Expand Up @@ -657,20 +668,9 @@ export class NxCloudService extends StateBaseService<InternalState> {
);
}

private async getNxCloudBaseUrl(): Promise<string | undefined> {
const nxConfig = (await getNxWorkspace()).workspace;

if (!nxConfig.tasksRunnerOptions) {
return;
}
const nxCloudTaskRunner = Object.values(nxConfig.tasksRunnerOptions).find(
(r) => r.runner == '@nrwl/nx-cloud'
);

// remove trailing slash
return (nxCloudTaskRunner?.options?.url ?? 'https://cloud.nx.app').replace(
/\/$/,
''
);
private async getCloudRunnerUrl(): Promise<string> {
return (
(await getNxCloudRunnerOptions())?.url ?? prodConfig.appUrl
).replace(/\/$/, '');
}
}
16 changes: 15 additions & 1 deletion libs/vscode/nx-workspace/src/lib/get-nx-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function getNxWorkspace(reset?: boolean): Promise<NxWorkspace> {
return sendRequest(NxWorkspaceRequest, { reset });
}

// shortcut to reduce repeated destructuring all over the codebase
// shortcuts to reduce repeated destructuring all over the codebase
export async function getNxWorkspaceProjects(reset?: boolean): Promise<{
[projectName: string]: ProjectConfiguration;
}> {
Expand All @@ -16,3 +16,17 @@ export async function getNxWorkspaceProjects(reset?: boolean): Promise<{
} = await getNxWorkspace(reset);
return projects;
}

export async function getNxCloudRunnerOptions(): Promise<
{ accessToken: string; url?: string } | undefined
> {
const nxConfig = (await getNxWorkspace()).workspace;

if (!nxConfig.tasksRunnerOptions) {
return;
}
const nxCloudTaskRunner = Object.values(nxConfig.tasksRunnerOptions).find(
(r) => r.runner == '@nrwl/nx-cloud'
);
return nxCloudTaskRunner?.options;
}

0 comments on commit 5e8e25c

Please sign in to comment.