From 101a2c2cd8dfe2540380e3439a56ad545941b4ab Mon Sep 17 00:00:00 2001 From: Jag Jayaprakash Date: Fri, 27 Sep 2024 08:03:08 -0700 Subject: [PATCH 1/2] FIX (Extension) @W-16733527@ Additional telemetry for apex guru --- src/apexguru/apex-guru-service.ts | 9 +- src/extension.ts | 11 +- src/lib/constants.ts | 1 + src/lib/fixer.ts | 12 +- .../suite/apexguru/apex-guru-service.test.ts | 136 ++++++++++++++++++ src/test/suite/fixer.test.ts | 8 +- 6 files changed, 164 insertions(+), 13 deletions(-) diff --git a/src/apexguru/apex-guru-service.ts b/src/apexguru/apex-guru-service.ts index 4553c4a..8f82e81 100644 --- a/src/apexguru/apex-guru-service.ts +++ b/src/apexguru/apex-guru-service.ts @@ -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(), + violationsWithSuggestedCode: getViolationsWithSuggestions(ruleResult).toString() }); void vscode.window.showInformationMessage(messages.apexGuru.finishedScan(ruleResult.violations.length)); }); @@ -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 { let queryResponse: ApexGuruQueryResponse; let lastErrorMessage = ''; diff --git a/src/extension.ts b/src/extension.ts index 31fcf78..7dc3cca 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -143,7 +143,16 @@ export async function activate(context: vscode.ExtensionContext): Promise { + 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()) { diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 6dc6977..6d94694 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -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'; diff --git a/src/lib/fixer.ts b/src/lib/fixer.ts index bf00e09..c15b287 100644 --- a/src/lib/fixer.ts +++ b/src/lib/fixer.ts @@ -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; } diff --git a/src/test/suite/apexguru/apex-guru-service.test.ts b/src/test/suite/apexguru/apex-guru-service.test.ts index f27a873..792abc0 100644 --- a/src/test/suite/apexguru/apex-guru-service.test.ts +++ b/src/test/suite/apexguru/apex-guru-service.test.ts @@ -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); + }); + }); }); diff --git a/src/test/suite/fixer.test.ts b/src/test/suite/fixer.test.ts index f962f05..8262aee 100644 --- a/src/test/suite/fixer.test.ts +++ b/src/test/suite/fixer.test.ts @@ -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', () => { @@ -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 () => { @@ -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); }); }); }); From 2c630e6db5d291ca7a7b385bfb4cd709e8ae7828 Mon Sep 17 00:00:00 2001 From: Jag Jayaprakash Date: Fri, 27 Sep 2024 10:31:59 -0700 Subject: [PATCH 2/2] FIX (Extension) @W-16733527@ Additional telemetry for apex guru - address review comments --- src/apexguru/apex-guru-service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apexguru/apex-guru-service.ts b/src/apexguru/apex-guru-service.ts index 8f82e81..8f63641 100644 --- a/src/apexguru/apex-guru-service.ts +++ b/src/apexguru/apex-guru-service.ts @@ -59,7 +59,7 @@ export async function runApexGuruOnFile(selection: vscode.Uri, runInfo: RunInfo) executedCommand: commandName, duration: (Date.now() - startTime).toString(), violationsCount: ruleResult.violations.length.toString(), - violationsWithSuggestedCode: getViolationsWithSuggestions(ruleResult).toString() + violationsWithSuggestedCodeCount: getViolationsWithSuggestions(ruleResult).toString() }); void vscode.window.showInformationMessage(messages.apexGuru.finishedScan(ruleResult.violations.length)); });