Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SHA256.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ make sure that their SHA values match the values in the list below.
shasum -a 256 <location_of_the_downloaded_file>

3. Confirm that the SHA in your output matches the value in this list of SHAs.
8dbf73cb26d6dbc695b5d0fe0f901ab7cbf1fb834640713dfb717209c224474d ./extensions/sfdx-code-analyzer-vscode-1.5.1.vsix
fc2d37a4f1c59206be01f30ff9384ec202632b7bb8d95b4776c4d75469377ff4 ./extensions/sfdx-code-analyzer-vscode-1.6.0.vsix
4. Change the filename extension for the file that you downloaded from .zip to
.vsix.

Expand Down
332 changes: 166 additions & 166 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"color": "#ECECEC",
"theme": "light"
},
"version": "1.6.0",
"version": "1.6.1",
"publisher": "salesforce",
"license": "BSD-3-Clause",
"engines": {
Expand Down
24 changes: 13 additions & 11 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {CliCommandExecutor, CliCommandExecutorImpl} from "./lib/cli-commands";
import {getErrorMessage} from "./lib/utils";
import {FileHandler, FileHandlerImpl} from "./lib/fs-utils";
import {VscodeWorkspace, VscodeWorkspaceImpl, WindowManager, WindowManagerImpl} from "./lib/vscode-api";
import {Workspace} from "./lib/workspace";


// Object to hold the state of our extension for a specific activation context, to be returned by our activate function
Expand Down Expand Up @@ -85,13 +86,14 @@ export async function activate(context: vscode.ExtensionContext): Promise<SFCAEx
context.subscriptions.push(scanManager);

const windowManager: WindowManager = new WindowManagerImpl(outputChannel);
const vscodeWorkspace: VscodeWorkspace = new VscodeWorkspaceImpl();

const taskWithProgressRunner: TaskWithProgressRunner = new TaskWithProgressRunnerImpl();


const cliCommandExecutor: CliCommandExecutor = new CliCommandExecutorImpl(logger);
const vscodeWorkspace: VscodeWorkspace = new VscodeWorkspaceImpl();
const fileHandler: FileHandler = new FileHandlerImpl();
const codeAnalyzer: CodeAnalyzer = new CodeAnalyzerImpl(cliCommandExecutor, settingsManager, display, vscodeWorkspace, fileHandler);
const codeAnalyzer: CodeAnalyzer = new CodeAnalyzerImpl(cliCommandExecutor, settingsManager, display, fileHandler);
const dfaRunner: DfaRunner = new DfaRunner(context, codeAnalyzer, telemetryService, logger); // This thing is really old and clunky. It'll go away when we remove v4 stuff. But if we don't want to wait we could move all this into the v4-scanner.ts file
context.subscriptions.push(dfaRunner);

Expand Down Expand Up @@ -126,7 +128,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<SFCAEx
vscode.window.showWarningMessage(messages.noActiveEditor);
return;
}
return codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_ACTIVE_FILE, [document.fileName]);
const workspace: Workspace = await Workspace.fromTargetPaths([document.fileName], vscodeWorkspace, fileHandler);
return codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_ACTIVE_FILE, workspace);
});

// "Analyze On Open" and "Analyze on Save" functionality:
Expand All @@ -139,7 +142,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<SFCAEx
const isValidFileThatHasNotBeenScannedYet = isValidFile && !scanManager.haveAlreadyScannedFile(editor.document.fileName);
if (isValidFileThatHasNotBeenScannedYet) {
scanManager.addFileToAlreadyScannedFiles(editor.document.fileName);
await codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_ACTIVE_FILE, [editor.document.fileName]);
const workspace: Workspace = await Workspace.fromTargetPaths([editor.document.fileName], vscodeWorkspace, fileHandler);
await codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_ACTIVE_FILE, workspace);
}
});
onDidSaveTextDocument(async (document: vscode.TextDocument) => {
Expand All @@ -154,22 +158,20 @@ export async function activate(context: vscode.ExtensionContext): Promise<SFCAEx

if (settingsManager.getAnalyzeOnSave()) {
scanManager.addFileToAlreadyScannedFiles(document.fileName);
await codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_ACTIVE_FILE, [document.fileName]);
const workspace: Workspace = await Workspace.fromTargetPaths([document.fileName], vscodeWorkspace, fileHandler);
await codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_ACTIVE_FILE, workspace);
}
});

// COMMAND_RUN_ON_SELECTED: Invokable by 'explorer/context' menu always. Uses v4 instead of v5 when 'sfca.codeAnalyzerV4Enabled'.
registerCommand(Constants.COMMAND_RUN_ON_SELECTED, async (singleSelection: vscode.Uri, multiSelection?: vscode.Uri[]) => {
const selection: vscode.Uri[] = (multiSelection && multiSelection.length > 0) ? multiSelection : [singleSelection];
// TODO: We may wish to consider moving away from this target resolution, and just passing in files and folders
// as given to us. It's possible the current style could lead to overflowing the CLI when a folder has
// many files.
const selectedFiles: string[] = await targeting.getFilesFromSelection(selection);
if (selectedFiles.length == 0) { // I have not found a way to hit this, but we should check just in case
const workspace: Workspace = await Workspace.fromTargetPaths(selection.map(uri => uri.fsPath), vscodeWorkspace, fileHandler);
if (workspace.getRawTargetPaths().length == 0) { // I have not found a way to hit this, but we should check just in case
vscode.window.showWarningMessage(messages.targeting.error.noFileSelected);
return;
}
await codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_SELECTED, selectedFiles);
await codeAnalyzerRunAction.run(Constants.COMMAND_RUN_ON_SELECTED, workspace);
});


Expand Down
28 changes: 19 additions & 9 deletions src/lib/cli-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,30 @@ export class CliCommandExecutorImpl implements CliCommandExecutor {

async exec(command: string, args: string[], options: ExecOptions = {}): Promise<CommandOutput> {
return new Promise((resolve) => {
const childProcess: cp.ChildProcessWithoutNullStreams = cp.spawn(command, args, {
shell: process.platform.startsWith('win'), // Use shell on Windows machines
});

if (options.pidHandler) {
options.pidHandler(childProcess.pid);
}
const logLevel: vscode.LogLevel = options.logLevel === undefined ? vscode.LogLevel.Trace : options.logLevel;

const output: CommandOutput = {
stdout: '',
stderr: '',
exitCode: 0
};

let childProcess: cp.ChildProcessWithoutNullStreams;
try {
childProcess = cp.spawn(command, args, {
shell: process.platform.startsWith('win'), // Use shell on Windows machines
});
} catch (err) {
this.logger.logAtLevel(vscode.LogLevel.Error, `Failed to execute the following command:\n` +
indent(`${command} ${args.map(arg => arg.includes(' ') ? `"${arg}"` : arg).join(' ')}`) + `\n\n` +
'Error Thrown:\n' + indent(getErrorMessageWithStack(err)));
output.stderr = getErrorMessageWithStack(err);
output.exitCode = 127;
resolve(output);
}

if (options.pidHandler) {
options.pidHandler(childProcess.pid);
}
const logLevel: vscode.LogLevel = options.logLevel === undefined ? vscode.LogLevel.Trace : options.logLevel;
let combinedOut: string = '';

this.logger.logAtLevel(logLevel, `Executing with background process (${childProcess.pid}):\n` +
Expand Down
12 changes: 7 additions & 5 deletions src/lib/code-analyzer-run-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {Display} from "./display";
import {getErrorMessage, getErrorMessageWithStack} from "./utils";
import {ProgressReporter, TaskWithProgressRunner} from "./progress";
import {WindowManager} from "./vscode-api";
import {Workspace} from "./workspace";

export const UNINSTANTIABLE_ENGINE_RULE = 'UninstantiableEngineError';

Expand All @@ -35,9 +36,9 @@ export class CodeAnalyzerRunAction {
/**
* Runs the scanner against the specified file and displays the results.
* @param commandName The command being run
* @param filesToScan The files to run against
* @param workspace The workspace to run against
*/
run(commandName: string, filesToScan: string[]): Promise<void> {
run(commandName: string, workspace: Workspace): Promise<void> {
return this.taskWithProgressRunner.runTask(async (progressReporter: ProgressReporter) => {
const startTime: number = Date.now();

Expand All @@ -59,7 +60,7 @@ export class CodeAnalyzerRunAction {
increment: 20
});
this.logger.log(messages.info.scanningWith(await this.codeAnalyzer.getScannerName()));
const violations: Violation[] = await this.codeAnalyzer.scan(filesToScan);
const violations: Violation[] = await this.codeAnalyzer.scan(workspace);

progressReporter.reportProgress({
message: messages.scanProgressReport.processingResults,
Expand All @@ -78,9 +79,10 @@ export class CodeAnalyzerRunAction {
});

const diagnostics: CodeAnalyzerDiagnostic[] = violationsWithFileLocation.map(v => CodeAnalyzerDiagnostic.fromViolation(v));
this.diagnosticManager.clearDiagnosticsForFiles(filesToScan.map(f => vscode.Uri.file(f)));
const targetedFiles: string[] = await workspace.getTargetedFiles();
this.diagnosticManager.clearDiagnosticsForFiles(targetedFiles.map(f => vscode.Uri.file(f)));
this.diagnosticManager.addDiagnostics(diagnostics);
void this.displayResults(filesToScan.length, violationsWithFileLocation);
void this.displayResults(targetedFiles.length, violationsWithFileLocation);

this.telemetryService.sendCommandEvent(Constants.TELEM_SUCCESSFUL_STATIC_ANALYSIS, {
commandName: commandName,
Expand Down
12 changes: 5 additions & 7 deletions src/lib/code-analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
RECOMMENDED_MINIMUM_REQUIRED_CODE_ANALYZER_CLI_PLUGIN_VERSION
} from "./constants";
import {CliScannerStrategy} from "./scanner-strategies/scanner-strategy";
import {VscodeWorkspace, VscodeWorkspaceImpl} from "./vscode-api";
import {FileHandler, FileHandlerImpl} from "./fs-utils";
import {Workspace} from "./workspace";

export interface CodeAnalyzer extends CliScannerStrategy {
validateEnvironment(): Promise<void>;
Expand All @@ -22,7 +22,6 @@ export class CodeAnalyzerImpl implements CodeAnalyzer {
private readonly cliCommandExecutor: CliCommandExecutor;
private readonly settingsManager: SettingsManager;
private readonly display: Display;
private readonly vscodeWorkspace: VscodeWorkspace;
private readonly fileHandler: FileHandler

private cliIsInstalled: boolean = false;
Expand All @@ -31,11 +30,10 @@ export class CodeAnalyzerImpl implements CodeAnalyzer {
private codeAnalyzerV5?: CliScannerV5Strategy;

constructor(cliCommandExecutor: CliCommandExecutor, settingsManager: SettingsManager, display: Display,
vscodeWorkspace: VscodeWorkspace = new VscodeWorkspaceImpl(), fileHandler: FileHandler = new FileHandlerImpl()) {
fileHandler: FileHandler = new FileHandlerImpl()) {
this.cliCommandExecutor = cliCommandExecutor;
this.settingsManager = settingsManager;
this.display = display;
this.vscodeWorkspace = vscodeWorkspace;
this.fileHandler = fileHandler;
}

Expand Down Expand Up @@ -87,11 +85,11 @@ export class CodeAnalyzerImpl implements CodeAnalyzer {
this.display.displayWarning(messages.codeAnalyzer.usingOlderVersion(installedVersion.toString(), recommendedMinVersion.toString()) + '\n'
+ messages.codeAnalyzer.installLatestVersion);
}
this.codeAnalyzerV5 = new CliScannerV5Strategy(installedVersion, this.cliCommandExecutor, this.settingsManager, this.vscodeWorkspace, this.fileHandler);
this.codeAnalyzerV5 = new CliScannerV5Strategy(installedVersion, this.cliCommandExecutor, this.settingsManager, this.fileHandler);
}

async scan(filesToScan: string[]): Promise<Violation[]> {
return (await this.getDelegate()).scan(filesToScan);
async scan(workspace: Workspace): Promise<Violation[]> {
return (await this.getDelegate()).scan(workspace);
}

async getScannerName(): Promise<string> {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/scanner-strategies/scanner-strategy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {Violation} from '../diagnostics';
import {Workspace} from "../workspace";

export interface CliScannerStrategy {
scan(filesToScan: string[]): Promise<Violation[]>;
scan(workspace: Workspace): Promise<Violation[]>;

getScannerName(): Promise<string>;

Expand Down
9 changes: 5 additions & 4 deletions src/lib/scanner-strategies/v4-scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {SettingsManager} from "../settings";
import * as semver from 'semver';
import {CliCommandExecutor, CommandOutput} from "../cli-commands";
import {FileHandler} from "../fs-utils";
import {Workspace} from "../workspace";

export type BaseV4Violation = {
ruleName: string;
Expand Down Expand Up @@ -66,9 +67,9 @@ export class CliScannerV4Strategy implements CliScannerStrategy {
return Promise.resolve(`@salesforce/sfdx-scanner@${this.version.toString()} via CLI`);
}

public async scan(filesToScan: string[]): Promise<Violation[]> {
public async scan(workspace: Workspace): Promise<Violation[]> {
// Create the arg array.
const args: string[] = await this.createArgArray(filesToScan);
const args: string[] = await this.createArgArray(workspace);

// Invoke the scanner.
const executionResult: V4ExecutionResult = await this.invokeAnalyzer(args);
Expand All @@ -77,7 +78,7 @@ export class CliScannerV4Strategy implements CliScannerStrategy {
return this.processResults(executionResult);
}

private async createArgArray(targets: string[]): Promise<string[]> {
private async createArgArray(workspace: Workspace): Promise<string[]> {
const engines: string = this.settingsManager.getEnginesToRun();
const pmdCustomConfigFile: string | undefined = this.settingsManager.getPmdCustomConfigFile();
const rulesCategory: string | undefined = this.settingsManager.getRulesCategory();
Expand All @@ -89,7 +90,7 @@ export class CliScannerV4Strategy implements CliScannerStrategy {

const args: string[] = [
'scanner', 'run',
'--target', `${targets.join(',')}`,
'--target', `${workspace.getRawTargetPaths().join(',')}`,
`--engine`, engines,
`--json`
];
Expand Down
23 changes: 7 additions & 16 deletions src/lib/scanner-strategies/v5-scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as path from 'node:path';
import * as semver from 'semver';
import {SettingsManager} from "../settings";
import {CliCommandExecutor, CommandOutput} from "../cli-commands";
import {VscodeWorkspace} from "../vscode-api";
import {Workspace} from "../workspace";

type ResultsJson = {
runDir: string;
Expand All @@ -31,16 +31,14 @@ export class CliScannerV5Strategy implements CliScannerStrategy {
private readonly version: semver.SemVer;
private readonly cliCommandExecutor: CliCommandExecutor;
private readonly settingsManager: SettingsManager;
private readonly vscodeWorkspace: VscodeWorkspace;
private readonly fileHandler: FileHandler;

private ruleDescriptionMap?: Map<string, string>;

public constructor(version: semver.SemVer, cliCommandExecutor: CliCommandExecutor, settingsManager: SettingsManager, vscodeWorkspace: VscodeWorkspace, fileHandler: FileHandler) {
public constructor(version: semver.SemVer, cliCommandExecutor: CliCommandExecutor, settingsManager: SettingsManager, fileHandler: FileHandler) {
this.version = version;
this.cliCommandExecutor = cliCommandExecutor;
this.settingsManager = settingsManager;
this.vscodeWorkspace = vscodeWorkspace;
this.fileHandler = fileHandler;
}

Expand All @@ -63,25 +61,18 @@ export class CliScannerV5Strategy implements CliScannerStrategy {
return this.ruleDescriptionMap;
}

public async scan(filesToScan: string[]): Promise<Violation[]> {
public async scan(workspace: Workspace): Promise<Violation[]> {
const ruleSelector: string = this.settingsManager.getCodeAnalyzerRuleSelectors();
const configFile: string = this.settingsManager.getCodeAnalyzerConfigFile();

const args: string[] = ['code-analyzer', 'run'];

if (semver.gte(this.version, '5.0.0')) {
// Just in case a file is open in the editor that does not live in the current workspace, or if there
// is no workspace open at all, we still want to be able to run code analyzer without error, so we
// include the files to scan always along with any workspace folders.
const workspacePaths: string[] = [
...this.vscodeWorkspace.getWorkspaceFolders(),
...filesToScan
]
workspacePaths.forEach(p => args.push('-w', p));
filesToScan.forEach(p => args.push('-t', p));
workspace.getRawWorkspacePaths().forEach(p => args.push('-w', p));
workspace.getRawTargetPaths().forEach(p => args.push('-t', p));
} else {
// Before 5.0.0 the --target flag did not exist, so we just make the workspace equal to the files to scan
filesToScan.forEach(p => args.push('-w', p));
// Before 5.0.0 the --target flag did not exist, so we just make the workspace equal to the target paths
workspace.getRawTargetPaths().forEach(p => args.push('-w', p));
}

if (ruleSelector) {
Expand Down
Loading
Loading