Skip to content

Commit

Permalink
FIX (Extension) @W-16733527@ Additional telemetry for apex guru (#139)
Browse files Browse the repository at this point in the history
  • Loading branch information
jag-j authored Sep 30, 2024
1 parent 1d0869d commit bb6e7ff
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 13 deletions.
9 changes: 8 additions & 1 deletion src/apexguru/apex-guru-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ export async function runApexGuruOnFile(selection: vscode.Uri, runInfo: RunInfo)
new DiagnosticManager().displayDiagnostics([selection.fsPath], [ruleResult], diagnosticCollection);
TelemetryService.sendCommandEvent(Constants.TELEM_SUCCESSFUL_APEX_GURU_FILE_ANALYSIS, {
executedCommand: commandName,
duration: (Date.now() - startTime).toString()
duration: (Date.now() - startTime).toString(),
violationsCount: ruleResult.violations.length.toString(),
violationsWithSuggestedCodeCount: getViolationsWithSuggestions(ruleResult).toString()
});
void vscode.window.showInformationMessage(messages.apexGuru.finishedScan(ruleResult.violations.length));
});
Expand All @@ -68,6 +70,11 @@ export async function runApexGuruOnFile(selection: vscode.Uri, runInfo: RunInfo)
}
}

export function getViolationsWithSuggestions(ruleResult: RuleResult): number {
// Filter violations that have a non-empty suggestedCode and get count
return ruleResult.violations.filter(violation => (violation as ApexGuruViolation).suggestedCode?.trim() !== '').length;
}

export async function pollAndGetApexGuruResponse(connection: Connection, requestId: string, maxWaitTimeInSeconds: number, retryIntervalInMillis: number): Promise<ApexGuruQueryResponse> {
let queryResponse: ApexGuruQueryResponse;
let lastErrorMessage = '';
Expand Down
11 changes: 10 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,16 @@ export async function activate(context: vscode.ExtensionContext): Promise<vscode
outputChannel: outputChannel
});
});
context.subscriptions.push(runApexGuruOnSelectedFile, runApexGuruOnCurrentFile);
const insertApexGuruSuggestions = vscode.commands.registerCommand(Constants.COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS, async (document: vscode.TextDocument, position: vscode.Position, suggestedCode: string) => {
const edit = new vscode.WorkspaceEdit();
edit.insert(document.uri, position, suggestedCode);
await vscode.workspace.applyEdit(edit);
TelemetryService.sendCommandEvent(Constants.TELEM_SUCCESSFUL_APEX_GURU_FILE_ANALYSIS, {
executedCommand: Constants.COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS,
lines: suggestedCode.split('\n').length.toString()
});
})
context.subscriptions.push(runApexGuruOnSelectedFile, runApexGuruOnCurrentFile, insertApexGuruSuggestions);
}

if (SettingsManager.getSfgeDeltaRunsEnabled()) {
Expand Down
1 change: 1 addition & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const COMMAND_REMOVE_DIAGNOSTICS_ON_SELECTED_FILE = 'sfca.removeDiagnosti
export const COMMAND_DIAGNOSTICS_IN_RANGE = 'sfca.removeDiagnosticsInRange';
export const COMMAND_RUN_APEX_GURU_ON_FILE = 'sfca.runApexGuruAnalysisOnSelectedFile';
export const COMMAND_RUN_APEX_GURU_ON_ACTIVE_FILE = 'sfca.runApexGuruAnalysisOnCurrentFile';
export const COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS = 'sfca.includeApexGuruSuggestions';

// telemetry event keys
export const TELEM_SUCCESSFUL_STATIC_ANALYSIS = 'sfdx__codeanalyzer_static_run_complete';
Expand Down
12 changes: 6 additions & 6 deletions src/lib/fixer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,14 @@ export class _ApexGuruFixGenerator extends FixGenerator {

const action = new vscode.CodeAction(messages.fixer.fixWithApexGuruSuggestions, vscode.CodeActionKind.QuickFix);
action.diagnostics = [this.diagnostic];

const edit = new vscode.WorkspaceEdit();
const range = this.diagnostic.range; // Assuming the range is the location of the existing code in the document
const diagnosticStartLine = new vscode.Position(range.start.line, range.start.character);
edit.insert(document.uri, diagnosticStartLine, suggestedCode + '\n');

// Assign the edit to the action
action.edit = edit;

action.command = {
title: 'Apply ApexGuru Fix',
command: Constants.COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS,
arguments: [document, diagnosticStartLine, suggestedCode + '\n']
}

return action;
}
Expand Down
136 changes: 136 additions & 0 deletions src/test/suite/apexguru/apex-guru-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,4 +371,140 @@ suite('Apex Guru Test Suite', () => {
expect(connectionStub.request.callCount).to.be.greaterThan(0);
});
});
suite('#getViolationsWithSuggestions', () => {
test('Returns 0 when there are no violations', () => {
// ===== SETUP =====
const ruleResult: RuleResult = {
engine: 'fake_engine',
fileName: 'test.cls',
violations: []
};
// ===== TEST =====
const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult);
// ===== ASSERTIONS =====
expect(result).to.equal(0);
});

test('Returns 0 when there are violations but no suggestions', () => {
// ===== SETUP =====
const ruleResult: RuleResult = {
engine: 'fake_engine',
fileName: 'test.cls',
violations: [
{
ruleName: 'BestPractices',
message: 'Avoid using System.debug',
severity: 1,
category: 'BestPractices',
line: 10,
column: 1,
currentCode: 'System.debug();',
suggestedCode: '', // No suggested code
url: 'TestFile.cls'
} as ApexGuruViolation
]
};
// ===== TEST =====
const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult);
// ===== ASSERTIONS =====
expect(result).to.equal(0);
});

test('Returns correct count when there are violations with suggestions', () => {
// ===== SETUP =====
const ruleResult: RuleResult = {
engine: 'fake_engine',
fileName: 'test.cls',
violations: [
{
ruleName: 'BestPractices',
message: 'Avoid using System.debug',
severity: 1,
category: 'BestPractices',
line: 10,
column: 1,
currentCode: 'System.debug();',
suggestedCode: 'System.out.println("Hello World");',
url: 'TestFile.cls'
} as ApexGuruViolation
]
};
// ===== TEST =====
const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult);
// ===== ASSERTIONS =====
expect(result).to.equal(1);
});

test('Returns correct count when multiple violations have suggestions', () => {
// ===== SETUP =====
const ruleResult: RuleResult = {
engine: 'fake_engine',
fileName: 'test.cls',
violations: [
{
ruleName: 'BestPractices',
message: 'Avoid using System.debug',
severity: 1,
category: 'BestPractices',
line: 10,
column: 1,
currentCode: 'System.debug();',
suggestedCode: 'System.out.println("Hello World");',
url: 'TestFile.cls'
} as ApexGuruViolation,
{
ruleName: 'CodeQuality',
message: 'Improve variable naming',
severity: 1,
category: 'CodeQuality',
line: 12,
column: 2,
currentCode: 'int x;',
suggestedCode: 'int userCount;',
url: 'TestFile.cls'
} as ApexGuruViolation
]
};
// ===== TEST =====
const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult);
// ===== ASSERTIONS =====
expect(result).to.equal(2);
});

test('Ignores violations without suggestedCode', () => {
// ===== SETUP =====
const ruleResult: RuleResult = {
engine: 'fake_engine',
fileName: 'test.cls',
violations: [
{
ruleName: 'BestPractices',
message: 'Avoid using System.debug',
severity: 1,
category: 'BestPractices',
line: 10,
column: 1,
currentCode: 'System.debug();',
suggestedCode: 'System.out.println("Hello World");',
url: 'TestFile.cls'
} as ApexGuruViolation,
{
ruleName: 'CodeQuality',
message: 'Improve variable naming',
severity: 1,
category: 'CodeQuality',
line: 12,
column: 2,
currentCode: 'int x;',
suggestedCode: '', // No suggestion for this violation
url: 'TestFile.cls'
} as ApexGuruViolation
]
};
// ===== TEST =====
const result = ApexGuruFunctions.getViolationsWithSuggestions(ruleResult);
// ===== ASSERTIONS =====
expect(result).to.equal(1);
});
});
});
8 changes: 3 additions & 5 deletions src/test/suite/fixer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import * as vscode from 'vscode';
import {expect} from 'chai';
import path = require('path');
import * as Constants from '../../lib/constants';
import {_NoOpFixGenerator, _PmdFixGenerator, _ApexGuruFixGenerator} from '../../lib/fixer';

suite('fixer.ts', () => {
Expand Down Expand Up @@ -529,9 +530,7 @@ suite('fixer.ts', () => {

// Validate results.
expect(fixes).to.have.lengthOf(1, 'One fix should be offered');
const fix = fixes[0].edit.get(fileUri)[0];
expect(fix.newText).to.equal('apex guru suggested code\n', 'The suppression code should match the suggestion');
expect(fix.range.start.line).to.equal(7, 'The suppression should be added at the diagnostic line');
expect(fixes[0].command.command).to.equal(Constants.COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS);
});

test('Should not generate a suppression fix if line is already processed', async () => {
Expand Down Expand Up @@ -604,8 +603,7 @@ suite('fixer.ts', () => {
const fix = fixGenerator.generateApexGuruSuppresssion(doc);

// Validate results.
expect(fix.edit.get(fileUri)[0].newText).to.equal('apex guru suggested code\n', 'The suppression code should match the suggestion');
expect(fix.edit.get(fileUri)[0].range.start.line).to.equal(7, 'The suppression should be added at the diagnostic line');
expect(fix.command.command).to.equal(Constants.COMMAND_INCLUDE_APEX_GURU_SUGGESTIONS);
});
});
});
Expand Down

0 comments on commit bb6e7ff

Please sign in to comment.