Skip to content

Commit

Permalink
fix: added replay debugging to ApexLibraryExecuteExecutor (#3758)
Browse files Browse the repository at this point in the history
* fix: added replay debugging to ApexLibraryExecuteExecutor

* fix: moved TraceFlags from commands to helpers

* fix: moved TraceFlags from commands to helpers

* fix: added isDebugging parameter to forceApexExecute()
  • Loading branch information
jeffb-sfdc authored Jan 19, 2022
1 parent 7d3a3a5 commit a720c18
Show file tree
Hide file tree
Showing 14 changed files with 260 additions and 38 deletions.
1 change: 0 additions & 1 deletion packages/salesforcedx-utils-vscode/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,3 @@ import { NotificationService } from './notificationService';
export const notificationService = NotificationService.getInstance();
export { NotificationService };
export { ProgressNotification } from './progressNotification';
export { TraceFlags } from './traceFlags';
1 change: 1 addition & 0 deletions packages/salesforcedx-utils-vscode/src/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export {
getTestResultsFolder,
getRelativeProjectPath
} from './paths';
export { TraceFlags } from './traceFlags';
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export class TraceFlags {
throw new Error(nls.localize('error_no_default_username'));
}

const userId = (await this.getUserIdOrThrow(username)).Id;
const userRecord = await this.getUserIdOrThrow(username);
const userId = userRecord.Id;
const traceFlag = await this.getTraceFlagForUser(userId);
if (traceFlag) {
// update existing debug level and trace flag
Expand Down Expand Up @@ -165,7 +166,7 @@ export class TraceFlags {
const userQuery = `SELECT id FROM User WHERE username='${username}'`;
const userResult = await this.connection.query<UserRecord>(userQuery);

if (userResult.totalSize === 0) {
if (!userResult.totalSize || userResult.totalSize === 0) {
throw new Error(nls.localize('trace_flags_unknown_user'));
}
return userResult.records[0];
Expand Down
2 changes: 1 addition & 1 deletion packages/salesforcedx-utils-vscode/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export {
LibraryCommandletExecutor
} from './commands/commandletExecutors';
export { SfdxCommandlet } from './commands/sfdxCommandlet';
export { TraceFlags } from './commands/traceFlags';
export { TraceFlags } from './helpers/traceFlags';
export { ConfigSource, ConfigUtil } from './config/configUtil';
export { OrgInfo, WorkspaceContextUtil, getLogDirPath } from './context/workspaceContextUtil';
export {
Expand Down
4 changes: 3 additions & 1 deletion packages/salesforcedx-utils-vscode/src/messages/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,7 @@ export const messages = {
predicates_no_folder_opened_text:
'No folder opened. Open a Salesforce DX project in VS Code.',
predicates_no_sfdx_project_found_text:
'No sfdx-project.json found in the root directory of your open project. Open a Salesforce DX project in VS Code.'
'No sfdx-project.json found in the root directory of your open project. Open a Salesforce DX project in VS Code.',
trace_flags_unknown_user: 'Unknown user',
trace_flags_failed_to_create_debug_level: 'Failed to create a debug level'
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import { expect } from 'chai';
import * as proxyquire from 'proxyquire';
import { createSandbox, SinonSandbox, SinonStub } from 'sinon';
import { nls } from '../../../src/messages';
import { vscodeStub } from './mocks';
import { vscodeStub } from '../commands/mocks';

const { TraceFlags } = proxyquire.noCallThru()(
'../../../src/commands',
'../../../src/helpers',
{
vscode: vscodeStub
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import {
getRootWorkspacePath,
LibraryCommandletExecutor
} from '@salesforce/salesforcedx-utils-vscode/out/src';
import { notificationService, TraceFlags } from '@salesforce/salesforcedx-utils-vscode/out/src/commands';
import { getTestResultsFolder } from '@salesforce/salesforcedx-utils-vscode/out/src/helpers';
import { notificationService } from '@salesforce/salesforcedx-utils-vscode/out/src/commands';
import { getTestResultsFolder, TraceFlags } from '@salesforce/salesforcedx-utils-vscode/out/src/helpers';
import { ContinueResponse } from '@salesforce/salesforcedx-utils-vscode/out/src/types';
import * as path from 'path';
import { workspace } from 'vscode';
Expand Down
11 changes: 11 additions & 0 deletions packages/salesforcedx-vscode-apex-replay-debugger/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ function registerCommands(): vscode.Disposable {
return launchFromLogFile(logFile);
}
);

const launchFromLogFilePathCmd = vscode.commands.registerCommand(
'sfdx.launch.replay.debugger.logfile.path',
logFilePath => {
if (logFilePath) {
launchFromLogFile(logFilePath, true);
}
}
);

const launchFromLastLogFileCmd = vscode.commands.registerCommand(
'sfdx.launch.replay.debugger.last.logfile',
lastLogFileUri => {
Expand All @@ -105,6 +115,7 @@ function registerCommands(): vscode.Disposable {
return vscode.Disposable.from(
promptForLogCmd,
launchFromLogFileCmd,
launchFromLogFilePathCmd,
launchFromLastLogFileCmd,
sfdxCreateCheckpointsCmd,
sfdxToggleCheckpointCmd
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ export const messages = {
unable_to_retrieve_org_info: 'Unable to retrieve OrgInfo',
error_no_default_username:
'No default org is set. Run "SFDX: Create a Default Scratch Org" or "SFDX: Authorize an Org" to set one.',
trace_flags_unknown_user: 'Unknown user',
trace_flags_failed_to_create_debug_level: 'Failed to create a debug level',
debug_test_exec_name: 'Debug Test(s)',
debug_test_no_results_found: 'No test results found',
debug_test_no_debug_log: 'No debug log associated with test results',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import { LogService, TestService } from '@salesforce/apex-node';
import { TestLevel, TestResult } from '@salesforce/apex-node/lib/src/tests/types';
import { AuthInfo, ConfigAggregator, Connection } from '@salesforce/core';
import { MockTestOrgData, testSetup } from '@salesforce/core/lib/testSetup';
import { notificationService, TraceFlags } from '@salesforce/salesforcedx-utils-vscode/out/src/commands';
import { notificationService } from '@salesforce/salesforcedx-utils-vscode/out/src/commands';
import { TraceFlags } from '@salesforce/salesforcedx-utils-vscode/out/src/helpers';
import * as utils from '@salesforce/salesforcedx-utils-vscode/out/src/index';
import { ContinueResponse } from '@salesforce/salesforcedx-utils-vscode/out/src/types';
import { expect } from 'chai';
Expand Down Expand Up @@ -65,7 +66,8 @@ describe('Quick launch apex tests', () => {
.withArgs('defaultusername')
.returns(testData.username);
notificationServiceStub = sb.stub(notificationService, 'showErrorMessage');
sb.stub(workspaceContext, 'getConnection').returns(mockConnection);
sb.stub(workspaceContext, 'getConnection')
.returns(mockConnection);
testServiceStub = sb
.stub(TestService.prototype, 'runTestSynchronous')
.resolves({ tests: [{ apexLogId: APEX_LOG_ID }] } as TestResult);
Expand Down
1 change: 1 addition & 0 deletions packages/salesforcedx-vscode-apex/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
},
"devDependencies": {
"@salesforce/salesforcedx-test-utils-vscode": "53.13.1",
"@salesforce/ts-sinon": "1.2.2",
"@types/chai": "^4.0.0",
"@types/mkdirp": "0.5.2",
"@types/mocha": "^5",
Expand Down
90 changes: 85 additions & 5 deletions packages/salesforcedx-vscode-apex/src/commands/forceApexExecute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,37 @@ import {
ExecuteAnonymousResponse,
ExecuteService
} from '@salesforce/apex-node';
import { Connection } from '@salesforce/core';
import {
getLogDirPath,
hasRootWorkspace,
LibraryCommandletExecutor,
SfdxCommandlet,
SfdxWorkspaceChecker
} from '@salesforce/salesforcedx-utils-vscode/out/src';
import { notificationService } from '@salesforce/salesforcedx-utils-vscode/out/src/commands';
import {
getYYYYMMddHHmmssDateFormat
} from '@salesforce/salesforcedx-utils-vscode/out/src/date';
import { TraceFlags } from '@salesforce/salesforcedx-utils-vscode/out/src/helpers';
import {
CancelResponse,
ContinueResponse,
ParametersGatherer
} from '@salesforce/salesforcedx-utils-vscode/out/src/types';
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import { channelService, OUTPUT_CHANNEL } from '../channels';
import { workspaceContext } from '../context';
import { nls } from '../messages';

interface ApexExecuteParameters {
apexCode?: string;
fileName?: string;
selection?: vscode.Range;
}

export class AnonApexGatherer
implements ParametersGatherer<ApexExecuteParameters> {
public async gather(): Promise<
Expand Down Expand Up @@ -71,18 +82,28 @@ export class ApexLibraryExecuteExecutor extends LibraryCommandletExecutor<
'apex-errors'
);

constructor() {
private isDebugging: boolean;

constructor(isDebugging: boolean) {
super(
nls.localize('apex_execute_text'),
'force_apex_execute_library',
OUTPUT_CHANNEL
);

this.isDebugging = isDebugging;
}

public async run(
response: ContinueResponse<ApexExecuteParameters>
): Promise<boolean> {
const connection = await workspaceContext.getConnection();
if (this.isDebugging) {
if (!(await this.setUpTraceFlags(connection))) {
return false;
}
}

const executeService = new ExecuteService(connection);
const { apexCode, fileName: apexFilePath, selection } = response.data;

Expand All @@ -91,15 +112,72 @@ export class ApexLibraryExecuteExecutor extends LibraryCommandletExecutor<
apexCode
});

this.processResult(result, apexFilePath, selection);

if (this.isDebugging) {
return await this.launchReplayDebugger(result.logs);
}

return true;
}

private async setUpTraceFlags(connection: Connection): Promise<boolean> {
const traceFlags = new TraceFlags(connection);
if (!(await traceFlags.ensureTraceFlags())) {
return false;
}

return true;
}

private processResult(
result: ExecuteAnonymousResponse,
apexFilePath: string | undefined,
selection: any
) {
this.outputResult(result);

const editor = vscode.window.activeTextEditor;
const document = editor!.document;
const filePath = apexFilePath ?? document.uri.fsPath;

this.handleDiagnostics(result, filePath, selection);
}

private async launchReplayDebugger(
logs?: string | undefined
): Promise<boolean> {
const logFilePath = this.getLogFilePath();
if (!this.saveLogFile(logFilePath, logs)) {
return false;
}

await vscode.commands.executeCommand(
'sfdx.launch.replay.debugger.logfile.path',
logFilePath
);

return true;
}

private getLogFilePath(): string {
const outputDir = getLogDirPath();
const now = new Date();
const localDateFormatted = getYYYYMMddHHmmssDateFormat(now);
const logFilePath = path.join(outputDir, `${localDateFormatted}.log`);

return logFilePath;
}

private saveLogFile(
logFilePath: string,
logs?: string): boolean {
if (!logFilePath || !logs) {
return false;
}

fs.writeFileSync(logFilePath, logs);

return result.success;
return true;
}

private outputResult(response: ExecuteAnonymousResponse): void {
Expand Down Expand Up @@ -182,11 +260,13 @@ export class ApexLibraryExecuteExecutor extends LibraryCommandletExecutor<
}
}

export async function forceApexExecute() {
export async function forceApexExecute(
isDebugging: boolean
) {
const commandlet = new SfdxCommandlet(
new SfdxWorkspaceChecker(),
new AnonApexGatherer(),
new ApexLibraryExecuteExecutor()
new ApexLibraryExecuteExecutor(isDebugging)
);

await commandlet.run();
Expand Down
8 changes: 3 additions & 5 deletions packages/salesforcedx-vscode-apex/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ function registerCommands(
);
const forceApexAnonRunDelegateCmd = vscode.commands.registerCommand(
'sfdx.force.apex.anon.run.delegate',
forceApexExecute
() => forceApexExecute(false)
);
const forceApexLogGetCmd = vscode.commands.registerCommand(
'sfdx.force.apex.log.get',
Expand Down Expand Up @@ -207,13 +207,11 @@ function registerCommands(
);
const forceApexExecuteDocumentCmd = vscode.commands.registerCommand(
'sfdx.force.apex.execute.document',
forceApexExecute,
false
() => forceApexExecute(false)
);
const forceApexExecuteSelectionCmd = vscode.commands.registerCommand(
'sfdx.force.apex.execute.selection',
forceApexExecute,
true
() => forceApexExecute(false)
);
return vscode.Disposable.from(
forceApexDebugClassRunDelegateCmd,
Expand Down
Loading

0 comments on commit a720c18

Please sign in to comment.