Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CHANGE @W-17397505@ Added core version to certain outputs #172

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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 packages/code-analyzer-core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@salesforce/code-analyzer-core",
"description": "Core Package for the Salesforce Code Analyzer",
"version": "0.19.1",
"version": "0.20.0-SNAPSHOT",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure whether we wanted to do an 0.20.0 for this or an 0.19.2. I'm fine with either.

"author": "The Salesforce Code Analyzer Team",
"license": "BSD-3-Clause",
"homepage": "https://developer.salesforce.com/docs/platform/salesforce-code-analyzer/overview",
Expand Down
2 changes: 2 additions & 0 deletions packages/code-analyzer-core/src/output-format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export enum OutputFormat {
SARIF = "SARIF"
}

export const CODE_ANALYZER_CORE_NAME: string = 'code-analyzer';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If memory serves, this was the name we agreed on, and it means all our conventions for engine names (lowercase, skewer-case, etc).


export abstract class OutputFormatter {
abstract format(results: RunResults): string

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {CodeLocation, RunResults, Violation} from "../results";
import {OutputFormatter} from "../output-format";
import {OutputFormatter, CODE_ANALYZER_CORE_NAME} from "../output-format";
import {Rule, SeverityLevel} from "../rules";

export type JsonResultsOutput = {
Expand Down Expand Up @@ -64,7 +64,9 @@ export function toJsonResultsOutput(results: RunResults, sanitizeFcn: (text: str
}

function toJsonVersionObject(results: RunResults): JsonVersionOutput {
const versions: JsonVersionOutput = {};
const versions: JsonVersionOutput = {
[CODE_ANALYZER_CORE_NAME]: results.getCoreVersion()
};
const engineNames: string[] = results.getEngineNames();
for (const engineName of engineNames) {
versions[engineName] = results.getEngineRunResults(engineName).getEngineVersion();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {RunResults} from "../results";
import * as xmlbuilder from "xmlbuilder";
import {OutputFormatter} from "../output-format";
import {OutputFormatter, CODE_ANALYZER_CORE_NAME} from "../output-format";
import {JsonResultsOutput, toJsonResultsOutput} from "./json-output-format";

export class XmlOutputFormatter implements OutputFormatter {
Expand All @@ -19,6 +19,7 @@ export class XmlOutputFormatter implements OutputFormatter {
violationCountsNode.node('sev5').text(`${resultsOutput.violationCounts.sev5}`);

const versionsNode: xmlbuilder.XMLElement = resultsNode.node('versions');
versionsNode.node(CODE_ANALYZER_CORE_NAME).text(results.getCoreVersion());
const engineNames: string[] = results.getEngineNames();
for (const engineName of engineNames) {
versionsNode.node(engineName).text(results.getEngineRunResults(engineName).getEngineVersion());
Expand Down
14 changes: 13 additions & 1 deletion packages/code-analyzer-core/src/results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {getMessage} from "./messages";
import {Clock, RealClock, toAbsolutePath} from "./utils";
import {OutputFormat, OutputFormatter} from "./output-format";
import path from "node:path";
import fs from "node:fs";

export interface CodeLocation {
getFile(): string | undefined
Expand Down Expand Up @@ -32,6 +33,7 @@ export interface EngineRunResults {

export interface RunResults {
getRunDirectory(): string
getCoreVersion(): string
getViolationCount(): number
getViolationCountOfSeverity(severity: SeverityLevel): number
getViolations(): Violation[]
Expand Down Expand Up @@ -238,17 +240,27 @@ export class UnexpectedErrorEngineRunResults implements EngineRunResults {
export class RunResultsImpl implements RunResults {
private readonly clock: Clock;
private readonly runDir: string;
private coreVersion: string;
private readonly engineRunResultsMap: Map<string, EngineRunResults> = new Map();

constructor(clock: Clock = new RealClock(), runDir: string = process.cwd() + path.sep) {
this.clock = clock;
this.runDir = runDir;
}

getRunDirectory() {
getRunDirectory(): string {
return this.runDir;
}

getCoreVersion(): string {
if (!this.coreVersion) {
const pathToPackageJson: string = path.join(__dirname, '..', 'package.json');
const packageJson: { version: string } = JSON.parse(fs.readFileSync(pathToPackageJson, 'utf-8'));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using fs.readFileSync() here instead of a Promise because I wanted to keep the results formatting a synchronous process instead of introducing awaits everywhere.
We cache the result to make sure we only do the read once, so there shouldn't be a noticeable impact on performance.

this.coreVersion = packageJson.version;
}
return this.coreVersion;
}

getViolations(): Violation[] {
return Array.from(this.engineRunResultsMap.values()).flatMap(
engineRunResults => engineRunResults.getViolations());
Expand Down
3 changes: 3 additions & 0 deletions packages/code-analyzer-core/test/output-format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,10 @@ function getContentsOfExpectedOutputFile(expectedOutputFileName: string, escapeB
}
const encodedPathSepVar: string = encodeURI(path.sep);

const version: string = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8')).version;

return contents.replaceAll('{{PATHSEP}}', pathSepVar)
.replace("{{CORE_VERSION}}", version)
.replaceAll(`{{ENCODEDPATHSEP}}`, encodedPathSepVar)
.replaceAll('{{RUNDIR}}', runDirVar)
.replaceAll('{{ENCODEDRUNDIR}}', encodedRunDir)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
})();

// ==== START OF VIOLATIONS ====
const data = {"runDir":"{{ESCAPEDRUNDIR}}","violationCounts":{"total":6,"sev1":0,"sev2":1,"sev3":3,"sev4":2,"sev5":0},"versions":{"stubEngine1":"0.0.1","stubEngine2":"0.1.0","stubEngine3":"1.0.0"},"violations":[{"rule":"stub1RuleA","engine":"stubEngine1","severity":4,"tags":["Recommended","CodeStyle"],"primaryLocationIndex":0,"locations":[{"file":"test{{PATHSEP}}config.test.ts","startLine":3,"startColumn":6,"endLine":11,"endColumn":8}],"message":"SomeViolationMessage1","resources":["https://example.com/stub1RuleA"]},{"rule":"stub1RuleA","engine":"stubEngine1","severity":4,"tags":["Recommended","CodeStyle"],"primaryLocationIndex":0,"locations":[{"file":"test{{PATHSEP}}test-data{{PATHSEP}}sample-input-files{{PATHSEP}}subfolder with spaces{{PATHSEP}}some-target-file.ts","startLine":10,"startColumn":4,"endLine":11,"endColumn":2}],"message":"SomeViolationMessage1","resources":["https://example.com/stub1RuleA"]},{"rule":"stub1RuleC","engine":"stubEngine1","severity":3,"tags":["Recommended","Performance","Custom"],"primaryLocationIndex":0,"locations":[{"file":"test{{PATHSEP}}code-analyzer.test.ts","startLine":21,"startColumn":7,"endLine":25,"endColumn":4}],"message":"SomeViolationMessage2","resources":["https://example.com/stub1RuleC","https://example.com/aViolationSpecificUrl1","https://example.com/violationSpecificUrl2"]},{"rule":"stub1RuleE","engine":"stubEngine1","severity":3,"tags":["Performance"],"primaryLocationIndex":0,"locations":[{"file":"test{{PATHSEP}}code-analyzer.test.ts","startLine":56,"startColumn":4}],"message":"Some Violation that contains\na new line in `it` and &quot;various&quot; &#39;quotes&#39;. Also it has &lt;brackets&gt; that may need to be {escaped}.","resources":["https://example.com/stub1RuleE","https://example.com/stub1RuleE_2"]},{"rule":"stub2RuleC","engine":"stubEngine2","severity":2,"tags":["Recommended","BestPractice"],"primaryLocationIndex":2,"locations":[{"file":"test{{PATHSEP}}stubs.ts","startLine":4,"startColumn":13},{"file":"test{{PATHSEP}}test-helpers.ts","startLine":9,"startColumn":1},{"file":"test{{PATHSEP}}stubs.ts","startLine":76,"startColumn":8}],"message":"SomeViolationMessage3","resources":[]},{"rule":"stub3RuleA","engine":"stubEngine3","severity":3,"tags":["Recommended","ErrorProne"],"primaryLocationIndex":2,"locations":[{"file":"test{{PATHSEP}}stubs.ts","startLine":20,"startColumn":10,"endLine":22,"endColumn":25,"comment":"Comment at location 1"},{"file":"test{{PATHSEP}}test-helpers.ts","startLine":5,"startColumn":10,"comment":"Comment at location 2"},{"file":"test{{PATHSEP}}stubs.ts","startLine":90,"startColumn":1,"endLine":95,"endColumn":10}],"message":"SomeViolationMessage4","resources":[]}]};
const data = {"runDir":"{{ESCAPEDRUNDIR}}","violationCounts":{"total":6,"sev1":0,"sev2":1,"sev3":3,"sev4":2,"sev5":0},"versions":{"code-analyzer":"{{CORE_VERSION}}","stubEngine1":"0.0.1","stubEngine2":"0.1.0","stubEngine3":"1.0.0"},"violations":[{"rule":"stub1RuleA","engine":"stubEngine1","severity":4,"tags":["Recommended","CodeStyle"],"primaryLocationIndex":0,"locations":[{"file":"test{{PATHSEP}}config.test.ts","startLine":3,"startColumn":6,"endLine":11,"endColumn":8}],"message":"SomeViolationMessage1","resources":["https://example.com/stub1RuleA"]},{"rule":"stub1RuleA","engine":"stubEngine1","severity":4,"tags":["Recommended","CodeStyle"],"primaryLocationIndex":0,"locations":[{"file":"test{{PATHSEP}}test-data{{PATHSEP}}sample-input-files{{PATHSEP}}subfolder with spaces{{PATHSEP}}some-target-file.ts","startLine":10,"startColumn":4,"endLine":11,"endColumn":2}],"message":"SomeViolationMessage1","resources":["https://example.com/stub1RuleA"]},{"rule":"stub1RuleC","engine":"stubEngine1","severity":3,"tags":["Recommended","Performance","Custom"],"primaryLocationIndex":0,"locations":[{"file":"test{{PATHSEP}}code-analyzer.test.ts","startLine":21,"startColumn":7,"endLine":25,"endColumn":4}],"message":"SomeViolationMessage2","resources":["https://example.com/stub1RuleC","https://example.com/aViolationSpecificUrl1","https://example.com/violationSpecificUrl2"]},{"rule":"stub1RuleE","engine":"stubEngine1","severity":3,"tags":["Performance"],"primaryLocationIndex":0,"locations":[{"file":"test{{PATHSEP}}code-analyzer.test.ts","startLine":56,"startColumn":4}],"message":"Some Violation that contains\na new line in `it` and &quot;various&quot; &#39;quotes&#39;. Also it has &lt;brackets&gt; that may need to be {escaped}.","resources":["https://example.com/stub1RuleE","https://example.com/stub1RuleE_2"]},{"rule":"stub2RuleC","engine":"stubEngine2","severity":2,"tags":["Recommended","BestPractice"],"primaryLocationIndex":2,"locations":[{"file":"test{{PATHSEP}}stubs.ts","startLine":4,"startColumn":13},{"file":"test{{PATHSEP}}test-helpers.ts","startLine":9,"startColumn":1},{"file":"test{{PATHSEP}}stubs.ts","startLine":76,"startColumn":8}],"message":"SomeViolationMessage3","resources":[]},{"rule":"stub3RuleA","engine":"stubEngine3","severity":3,"tags":["Recommended","ErrorProne"],"primaryLocationIndex":2,"locations":[{"file":"test{{PATHSEP}}stubs.ts","startLine":20,"startColumn":10,"endLine":22,"endColumn":25,"comment":"Comment at location 1"},{"file":"test{{PATHSEP}}test-helpers.ts","startLine":5,"startColumn":10,"comment":"Comment at location 2"},{"file":"test{{PATHSEP}}stubs.ts","startLine":90,"startColumn":1,"endLine":95,"endColumn":10}],"message":"SomeViolationMessage4","resources":[]}]};
// ==== END OF VIOLATIONS ====

class Model {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"sev5": 0
},
"versions": {
"code-analyzer": "{{CORE_VERSION}}",
"stubEngine1": "0.0.1",
"stubEngine2": "0.1.0",
"stubEngine3": "1.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<sev5>0</sev5>
</violationCounts>
<versions>
<code-analyzer>{{CORE_VERSION}}</code-analyzer>
<stubEngine1>0.0.1</stubEngine1>
<stubEngine2>0.1.0</stubEngine2>
<stubEngine3>1.0.0</stubEngine3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
})();

// ==== START OF VIOLATIONS ====
const data = {"runDir":"{{ESCAPEDRUNDIR}}","violationCounts":{"total":1,"sev1":1,"sev2":0,"sev3":0,"sev4":0,"sev5":0},"versions":{"throwingEngine":"3.0.0"},"violations":[{"rule":"UnexpectedEngineError","engine":"throwingEngine","severity":1,"tags":[],"primaryLocationIndex":0,"locations":[{}],"message":"The engine with name &#39;throwingEngine&#39; threw an unexpected error: SomeErrorMessageFromThrowingEngine","resources":[]}]};
const data = {"runDir":"{{ESCAPEDRUNDIR}}","violationCounts":{"total":1,"sev1":1,"sev2":0,"sev3":0,"sev4":0,"sev5":0},"versions":{"code-analyzer":"{{CORE_VERSION}}","throwingEngine":"3.0.0"},"violations":[{"rule":"UnexpectedEngineError","engine":"throwingEngine","severity":1,"tags":[],"primaryLocationIndex":0,"locations":[{}],"message":"The engine with name &#39;throwingEngine&#39; threw an unexpected error: SomeErrorMessageFromThrowingEngine","resources":[]}]};
// ==== END OF VIOLATIONS ====

class Model {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"sev5": 0
},
"versions": {
"code-analyzer": "{{CORE_VERSION}}",
"throwingEngine": "3.0.0"
},
"violations": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<sev5>0</sev5>
</violationCounts>
<versions>
<code-analyzer>{{CORE_VERSION}}</code-analyzer>
<throwingEngine>3.0.0</throwingEngine>
</versions>
<violations>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
})();

// ==== START OF VIOLATIONS ====
const data = {"runDir":"{{ESCAPEDRUNDIR}}","violationCounts":{"total":0,"sev1":0,"sev2":0,"sev3":0,"sev4":0,"sev5":0},"versions":{},"violations":[]};
const data = {"runDir":"{{ESCAPEDRUNDIR}}","violationCounts":{"total":0,"sev1":0,"sev2":0,"sev3":0,"sev4":0,"sev5":0},"versions":{"code-analyzer":"{{CORE_VERSION}}"},"violations":[]};
// ==== END OF VIOLATIONS ====

class Model {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
"sev4": 0,
"sev5": 0
},
"versions": {},
"versions": {
"code-analyzer": "{{CORE_VERSION}}"
},
"violations": []
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
<sev4>0</sev4>
<sev5>0</sev5>
</violationCounts>
<versions></versions>
<versions>
<code-analyzer>{{CORE_VERSION}}</code-analyzer>
</versions>
<violations></violations>
</results>
Loading