Skip to content

Commit

Permalink
Auth via up9 website
Browse files Browse the repository at this point in the history
TRA-3958 user login
  • Loading branch information
RamiBerm authored Nov 28, 2021
2 parents 6ddf139 + c68fb08 commit dc8f019
Show file tree
Hide file tree
Showing 19 changed files with 683 additions and 283 deletions.
378 changes: 365 additions & 13 deletions package-lock.json

Large diffs are not rendered by default.

31 changes: 17 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"icon": "images/logo128x128.png",
"activationEvents": [
"onCommand:up9.openTestsBrowser",
"onCommand:up9.runTest"
"onCommand:up9.runTest",
"onCommand:up9.testAuth"
],
"main": "./out/extension.js",
"contributes": {
Expand All @@ -29,6 +30,10 @@
{
"command": "up9.runTest",
"title": "UP9: Run Test Code With UP9"
},
{
"command": "up9.webAuth",
"title": "UP9: Web Authentication"
}
],
"menus": {
Expand All @@ -43,6 +48,10 @@
{
"command": "up9.runTest",
"when": "false"
},
{
"command": "up9.webAuth",
"when": "false"
}
]
},
Expand All @@ -51,18 +60,10 @@
"title": "UP9 Extension Configuration",
"order": 1,
"properties": {
"up9.authEnv": {
"type": "string",
"description": "UP9 auth url (must begin with http:// or https://)",
"default": "https://auth.up9.app"
},
"up9.clientId": {
"type": "string",
"description": "Client ID"
},
"up9.clientSecret": {
"up9.env": {
"type": "string",
"description": "Client Secret"
"description": "UP9 API Hostname",
"default": "stg.testr.io"
},
"up9.defaultWorkspace": {
"type": "string",
Expand All @@ -76,7 +77,7 @@
"setup-browser": "cd src/webview && npm install && cd ../../",
"vscode:prepublish": "npm run compile",
"compile": "cd src/webview && npm run build && cd ../../ && tsc -p ./ && cp ./src/webview/dist/index.html ./out/",
"test-compile": "tsc -p ./",
"compile-no-gui": "tsc -p ./",
"pretest": "mkdir -p ./out/tests/integration/resources/ && cp -r ./src/tests/integration/resources/* ./out/tests/integration/resources/",
"test": "node ./out/tests/integration/runIntegrationTests.js"
},
Expand All @@ -97,6 +98,8 @@
"webpack-cli": "^4.9.1"
},
"dependencies": {
"axios": "^0.24.0"
"axios": "^0.24.0",
"client-oauth2": "^4.3.3",
"open": "^8.4.0"
}
}
49 changes: 25 additions & 24 deletions src/commands/runInCloud.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
import { getDefaultWorkspace, indentString, readUP9CredsFromConfig } from "../utils";
import { getDefaultWorkspace, indentString } from "../utils";
import * as vscode from 'vscode';
import { UP9Auth } from "../providers/up9Auth";
import { UP9ApiProvider } from "../providers/up9Api";
import { startAuthCommandName } from "../extension";

const openUP9SettingsDialogOption = "Open UP9 Settings";
const openUP9SettingsDialogOption = 'Open UP9 Settings';
const openUP9SignInDialogOption = 'Sign In To UP9';

export const terminalLineDelimeter = '\r\n';

export class CloudRunner {
private context: vscode.ExtensionContext;
private _up9Auth: UP9Auth;

// used for tests as there is no way to get terminal contents via vscode api
private onTerminalEmitCallback: (terminalMessage: string) => void;
private _onTerminalEmitCallback: (terminalMessage: string) => void;

public constructor(context: vscode.ExtensionContext, onTerminalEmit?: (terminalMessage: string) => void) {
this.context = context;
this.onTerminalEmitCallback = onTerminalEmit;
public constructor(up9Auth: UP9Auth, onTerminalEmit?: (terminalMessage: string) => void) {
this._up9Auth = up9Auth;
this._onTerminalEmitCallback = onTerminalEmit;
}

public startTestRun = (code: string): Promise<void> => {
return new Promise<any>(async (resolve, reject) => {
const up9Auth = await this.getStoredUP9Auth(this.context);
let token: string;
if (!up9Auth) {
this.showSettingsError('UP9 authentication hasn\'t been configured yet, please configure the up9 extension in vscode configuration');
return reject(Error("up9 auth not configured"));

if (!(await this._up9Auth.isAuthenticated())) {
this.showAuthenticationError('You must sign in to UP9 first');
return;
}

try {
token = await up9Auth.getToken();
token = await this._up9Auth.getToken();
} catch (error) {
console.error(error);
this.showSettingsError('UP9 authentication failed, check console for more details or check up9 extension configuration for errors');
Expand All @@ -43,7 +46,7 @@ export class CloudRunner {

//TODO: reuse the same terminal (will require having only 1 simultaneous test run)
const terminalOutputter = this.createAndShowTerminal("Running test through UP9...\n\r");
const up9Api = new UP9ApiProvider(up9Auth.getEnv());
const up9Api = new UP9ApiProvider(this._up9Auth.getEnv());
try {
const res = await up9Api.testRunSingle(defaultWorkspace, indentString(code, 4), token);
if (!res.testLog) {
Expand Down Expand Up @@ -87,15 +90,6 @@ export class CloudRunner {

return statusTerminalEmitter;
}


private getStoredUP9Auth = async (context: vscode.ExtensionContext): Promise<UP9Auth> => {
const storedAuthCredentials = await readUP9CredsFromConfig();
if (storedAuthCredentials) {
return new UP9Auth(storedAuthCredentials.up9Env, storedAuthCredentials.clientId, storedAuthCredentials.clientSecret);
}
return null;
}

private getLogOutputForRCA = (rca: any): string => {
let logOutput = "";
Expand Down Expand Up @@ -132,12 +126,19 @@ export class CloudRunner {
}
}

private showAuthenticationError = async (message: string): Promise<void> => {
const res = await vscode.window.showErrorMessage(message, openUP9SignInDialogOption);
if (res === openUP9SignInDialogOption) {
vscode.commands.executeCommand(startAuthCommandName);
}
}

private processTerminalOutputAndPrint = (text: string, terminalEmitter: vscode.EventEmitter<string>) => {
const formattedMessage = text.replace(/\n/g, terminalLineDelimeter);
terminalEmitter.fire(formattedMessage);

if (this.onTerminalEmitCallback) {
this.onTerminalEmitCallback(formattedMessage);
if (this._onTerminalEmitCallback) {
this._onTerminalEmitCallback(formattedMessage);
}
}
}
7 changes: 4 additions & 3 deletions src/consts.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
export const up9ConfigSectionName = "up9";
export const envConfigKey = "authEnv";
export const clientIdConfigKey = "clientId";
export const clientSecretConfigKey = "clientSecret";
export const envConfigKey = "env";
export const defaultWorkspaceConfigKey = "defaultWorkspace";

export const internalExtensionName = "up9.up9";
export const internalRunTestCommandName = "up9.runTest";

export const authGlobalStorageKey = "up9.auth.data";
export const authEnvStorageKey = "up9.auth.env";
24 changes: 16 additions & 8 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
import * as vscode from 'vscode';
import { CloudRunner } from './commands/runInCloud';
import { envConfigKey } from './consts';
import {
UP9Panel
} from './panel';
import { UP9Auth } from './providers/up9Auth';
import { readConfigValue } from './utils';

var http = require('http');

const testBrowserCommandName = 'up9.openTestsBrowser';
const runTestInCloudCommandName = 'up9.runTest';
export const startAuthCommandName = 'up9.webAuth';

function onShowTestBrowserCommand(context: vscode.ExtensionContext): void {
UP9Panel.createOrShow(context)
}

// onTerminalEmit is used by tests to intercept terminal contents, theres no way to directly get terminal contents otherwise sadly
export async function onRunCodeInCloudCommand(context: vscode.ExtensionContext, onTerminalEmit?: (terminalMessage: string) => void): Promise<void> {
const cloudRunner = new CloudRunner(context, onTerminalEmit);
export async function onRunCodeInCloudCommand(up9Auth: UP9Auth, onTerminalEmit?: (terminalMessage: string) => void): Promise<void> {
const cloudRunner = new CloudRunner(up9Auth, onTerminalEmit);
await cloudRunner.startTestRun(vscode.window.activeTextEditor.document.getText());
}

export function activate(context: vscode.ExtensionContext) {
const openTestBrowserCommand = vscode.commands.registerCommand(testBrowserCommandName, () => onShowTestBrowserCommand(context));
const runCodeInCloudCommand = vscode.commands.registerCommand(runTestInCloudCommandName, () => onRunCodeInCloudCommand(context));
export async function activate(context: vscode.ExtensionContext): Promise<vscode.ExtensionContext> {
const up9Env = await readConfigValue(envConfigKey);
const up9Auth = await UP9Auth.getInstance(up9Env, context);

const openTestBrowserCommand = vscode.commands.registerCommand(testBrowserCommandName, () => UP9Panel.createOrShow(context, up9Auth));
const runCodeInCloudCommand = vscode.commands.registerCommand(runTestInCloudCommandName, () => onRunCodeInCloudCommand(up9Auth));
const startAuthCommand = vscode.commands.registerCommand(startAuthCommandName, () => up9Auth.startNewAuthentication());

context.subscriptions.push(openTestBrowserCommand);
context.subscriptions.push(runCodeInCloudCommand);
context.subscriptions.push(startAuthCommand);

// return the context so its usable by tests
return context;
Expand Down
3 changes: 1 addition & 2 deletions src/models/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ export enum MessageCommandType {
ApiRequest = "apiRequest",
ApiResponse = "apiResponse",
AuthError = "authError",
AuthSuccess = "authSuccess",
SavedData = "savedData"
AuthSuccess = "authSuccess"
}

export enum ApiMessageType {
Expand Down
2 changes: 1 addition & 1 deletion src/models/up9.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ export interface Endpoint {
path: string;
service: string;
uuid: string;
}
}
16 changes: 6 additions & 10 deletions src/panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as vscode from 'vscode';
import * as fs from 'fs';
import * as path from 'path';
import { UP9WebviewCommunicator } from './providers/webviewCommunicator';
import { UP9Auth } from './providers/up9Auth';
import { MessageCommandType } from './models/internal';

const panelId = "up9BrowserPanel";
const panelTitle = "UP9 Code Browser";
Expand All @@ -18,7 +20,7 @@ export class UP9Panel {
private readonly _webviewCommunicator: UP9WebviewCommunicator;
private _disposables: vscode.Disposable[] = [];

public static createOrShow(context: vscode.ExtensionContext) {
public static createOrShow(context: vscode.ExtensionContext, up9Auth: UP9Auth) {
// If we already have a panel, show it.
if (UP9Panel.currentPanel) {
UP9Panel.currentPanel._panel.reveal(panelColumn);
Expand All @@ -36,17 +38,13 @@ export class UP9Panel {
}
);

UP9Panel.currentPanel = new UP9Panel(panel, context);
UP9Panel.currentPanel = new UP9Panel(panel, context, up9Auth);
}

public static revive(panel: vscode.WebviewPanel, context: vscode.ExtensionContext) {
UP9Panel.currentPanel = new UP9Panel(panel, context);
}

private constructor(panel: vscode.WebviewPanel, context: vscode.ExtensionContext) {
private constructor(panel: vscode.WebviewPanel, context: vscode.ExtensionContext, up9Auth: UP9Auth) {
this._panel = panel;
this._context = context;
this._webviewCommunicator = new UP9WebviewCommunicator(this._panel);
this._webviewCommunicator = new UP9WebviewCommunicator(this._panel, up9Auth);

// Set the webview's initial html content
this._panel.webview.html = this._getHtmlForWebview();
Expand All @@ -73,8 +71,6 @@ export class UP9Panel {

// Handle messages from the webview
this._webviewCommunicator.registerOnMessageListeners(this._disposables);
// Load stored auth credentials in configuration into web view
this._webviewCommunicator.syncStoredCredentialsToWebView();
}

public dispose() {
Expand Down
12 changes: 6 additions & 6 deletions src/providers/up9Api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,26 @@ import { Workspace, TestResponse, Endpoint } from '../models/up9';
import {raiseForBadResponse} from'../utils';

export class UP9ApiProvider {
private readonly up9Env: string
private readonly _trccUrl: string

constructor(up9Env: string) {
this.up9Env = up9Env.replace('auth.', 'trcc.'); //TODO: refactor this
this._trccUrl = `https://trcc.${up9Env}`;
}

public getWorkspaces = async (token: string): Promise<string[]> => {
const response = await axios.get<Workspace[]>(`${this.up9Env}/models/`, {headers: {'Authorization': `Bearer ${token}`}})
const response = await axios.get<Workspace[]>(`${this._trccUrl}/models/`, {headers: {'Authorization': `Bearer ${token}`}})
raiseForBadResponse(response);
return response.data.map(workspace => workspace.modelId);
}

public getWorkspaceEndpoints = async (workspaceId: string, token: string): Promise<Endpoint[]> => {
const response = await axios.get<Endpoint[]>(`${this.up9Env}/models/${workspaceId}/lastResults/all/endpoints`, {headers: {'Authorization': `Bearer ${token}`}})
const response = await axios.get<Endpoint[]>(`${this._trccUrl}/models/${workspaceId}/lastResults/all/endpoints`, {headers: {'Authorization': `Bearer ${token}`}})
raiseForBadResponse(response);
return response.data;
}

public getTestsForSpan = async(workspaceId: string, spanGuid: string, token: string): Promise<TestResponse> => {
const url = `${this.up9Env}/models/${workspaceId}/lastResults/all/tests?base64Code=false&addTestData=true`;
const url = `${this._trccUrl}/models/${workspaceId}/lastResults/all/tests?base64Code=false&addTestData=true`;
console.log('url ', url);
const body = {spanGuids: [spanGuid]};
console.log('body', body);
Expand All @@ -33,7 +33,7 @@ export class UP9ApiProvider {

public testRunSingle = async(workspaceId: string, testCode: string, token: string) => {
const serializedCode = `data:text/plain;base64,${Buffer.from(testCode).toString('base64')}`;
const response = await axios.post<any>(`${this.up9Env}/agents/runSingleTest`, {model: workspaceId, code: serializedCode}, {headers: {'Authorization': `Bearer ${token}`}});
const response = await axios.post<any>(`${this._trccUrl}/agents/runSingleTest`, {model: workspaceId, code: serializedCode}, {headers: {'Authorization': `Bearer ${token}`}});
raiseForBadResponse(response);
return response.data;
}
Expand Down
Loading

0 comments on commit dc8f019

Please sign in to comment.