Skip to content
This repository has been archived by the owner on Mar 18, 2024. It is now read-only.

Fix Broken PMD Analysis #644

Merged
merged 3 commits into from
Aug 11, 2021
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
3 changes: 2 additions & 1 deletion packages/core/src/sfpowerkitwrappers/AnalyzeWithPMDImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default class AnalyzeWithPMDImpl extends SFDXCommand {
protected logger?: Logger,
protected logLevel?: LoggerLevel
) {
super(null, sourceDirectory,logger,logLevel);
super(null, null,logger,logLevel);
}

getSFDXCommand(): string {
Expand All @@ -28,6 +28,7 @@ export default class AnalyzeWithPMDImpl extends SFDXCommand {
if (this.format) command +=` -f ${this.format}`;
if (this.ouputPath) command+=` -o ${this.ouputPath}`;
if (this.version) command+=` --version ${this.version}`;
command+=` --no-failonviolation`
command +=` --loglevel ${LoggerLevel[SFPLogger.logLevel]}`;


Expand Down
294 changes: 172 additions & 122 deletions packages/sfpowerscripts-cli/src/commands/sfpowerscripts/analyze/pmd.ts
Original file line number Diff line number Diff line change
@@ -1,176 +1,226 @@
import { flags } from "@salesforce/command";
import SfpowerscriptsCommand from "../../../SfpowerscriptsCommand";
import { Messages } from "@salesforce/core";
import AnalyzeWithPMDImpl from "@dxatscale/sfpowerscripts.core/lib/sfpowerkitwrappers/AnalyzeWithPMDImpl";
import xml2js = require("xml2js");
import SFPLogger, { ConsoleLogger } from "@dxatscale/sfpowerscripts.core/lib/logger/SFPLogger";
const fs = require("fs");
import { flags } from '@salesforce/command';
import SfpowerscriptsCommand from '../../../SfpowerscriptsCommand';
import { Messages, SfdxError } from '@salesforce/core';
import AnalyzeWithPMDImpl from '@dxatscale/sfpowerscripts.core/lib/sfpowerkitwrappers/AnalyzeWithPMDImpl';
import xml2js = require('xml2js');
import {isNullOrUndefined} from 'util';
const fs = require('fs-extra');
const path = require('path');
import * as rimraf from "rimraf";

// Initialize Messages with the current plugin directory
Messages.importMessagesDirectory(__dirname);

// Load the specific messages for this file. Messages from @salesforce/command, @salesforce/core,
// or any library that is using the messages framework can also be loaded this way.
const messages = Messages.loadMessages(
"@dxatscale/sfpowerscripts",
"analyze_with_PMD"
);
const messages = Messages.loadMessages('@dxatscale/sfpowerscripts', 'analyze_with_PMD');

export default class AnalyzeWithPMD extends SfpowerscriptsCommand {
public static description = messages.getMessage("commandDescription");

public static description = messages.getMessage('commandDescription');

public static examples = [
`$ sfdx sfpowerscripts:analyze:pmd -b\n`,
`Output variable:`,
`sfpowerscripts_pmd_output_path`,
`<refname>_sfpowerscripts_pmd_output_path`,
`<refname>_sfpowerscripts_pmd_output_path`
];

protected static requiresProject = true;
protected static requiresUsername = false;
protected static requiresDevhubUsername = false;

protected static flagsConfig = {
sourcedir: flags.string({
description: messages.getMessage("sourceDirectoryFlagDescription"),
}),
ruleset: flags.string({
description: messages.getMessage("rulesetFlagDescription"),
options: ["sfpowerkit", "Custom"],
default: "sfpowerkit",
}),
rulesetpath: flags.string({
description: messages.getMessage("rulesetPathFlagDescription"),
}),
format: flags.string({
description: messages.getMessage("formatFlagDescription"),
options: [
"text",
"textcolor",
"csv",
"emacs",
"summaryhtml",
"html",
"xml",
"xslt",
"yahtml",
"vbhtml",
"textpad",
"sarif",
],
default: "text",
}),
outputpath: flags.string({
char: "o",
description: messages.getMessage("outputPathFlagDescription"),
}),
version: flags.string({
required: false,
default: "6.34.0",
description: messages.getMessage("versionFlagDescription"),
}),
istobreakbuild: flags.boolean({
char: "b",
deprecated: {
messageOverride:
"--istobreakbuild has been deprecated, the command will always break",
},
description: messages.getMessage("isToBreakBuildFlagDescription"),
}),
refname: flags.string({
description: messages.getMessage("refNameFlagDescription"),
}),
loglevel: flags.enum({
description: "logging level for this command invocation",
default: "info",
required: false,
options: [
"trace",
"debug",
"info",
"warn",
"error",
"fatal",
"TRACE",
"DEBUG",
"INFO",
"WARN",
"ERROR",
"FATAL",
],
}),
};

public async execute() {
sourcedir: flags.string({
description: messages.getMessage("sourceDirectoryFlagDescription"),
}),
ruleset: flags.string({
description: messages.getMessage("rulesetFlagDescription"),
options: ["sfpowerkit", "Custom"],
default: "sfpowerkit",
}),
rulesetpath: flags.string({
description: messages.getMessage("rulesetPathFlagDescription"),
}),
format: flags.string({
description: messages.getMessage("formatFlagDescription"),
options: [
"text",
"textcolor",
"csv",
"emacs",
"summaryhtml",
"html",
"xml",
"xslt",
"yahtml",
"vbhtml",
"textpad",
"sarif",
],
default: "text",
}),
outputpath: flags.string({
char: "o",
description: messages.getMessage("outputPathFlagDescription"),
}),
version: flags.string({
required: false,
default: "6.34.0",
description: messages.getMessage("versionFlagDescription"),
}),
istobreakbuild: flags.boolean({
char: "b",
deprecated: {
messageOverride:
"--istobreakbuild has been deprecated, the command will always break if there is critical errors",
},
description: messages.getMessage("isToBreakBuildFlagDescription"),
}),
refname: flags.string({
description: messages.getMessage("refNameFlagDescription"),
}),
loglevel: flags.enum({
description: "logging level for this command invocation",
default: "info",
required: false,
options: [
"trace",
"debug",
"info",
"warn",
"error",
"fatal",
"TRACE",
"DEBUG",
"INFO",
"WARN",
"ERROR",
"FATAL",
],
}),
};

public async execute(){
try {


// Setup Logging Directory
rimraf.sync("sfpowerscripts");
fs.mkdirpSync(".sfpowerscripts");



const source_directory: string = this.flags.sourcedir;
const ruleset: string = this.flags.ruleset;

let rulesetpath = "";

let rulesetpath=""
if (ruleset == "Custom") {
console.log("Custom Rulesets are temporaily disabled, Please check back in few days");
let rulesetpath = this.flags.rulesetpath;
console.log(rulesetpath);
}



const format: string = this.flags.format;
const outputPath: string = this.flags.outputpath;
const version: string = this.flags.version;

const isToBreakBuild = this.flags.istobreakbuild;

let result: [number, number, number] = [0, 0, 0];

let pmdImpl: AnalyzeWithPMDImpl = new AnalyzeWithPMDImpl(
source_directory,
rulesetpath,
format,
outputPath,
version,
new ConsoleLogger(),
SFPLogger.logLevel
version
);

let output = await pmdImpl.exec(false);
console.log(output);


if (!isNullOrUndefined(this.flags.refname)) {
if (!isNullOrUndefined(outputPath)) {
fs.writeFileSync('.env', `${this.flags.refname}_sfpowerscripts_pmd_output_path=${outputPath}\n`, {flag:'a'});
} else {
fs.writeFileSync('.env', `${this.flags.refname}_sfpowerscripts_pmd_output_path=${process.env.PWD}/pmd-output\n`, {flag:'a'});
}
} else {
if (!isNullOrUndefined(outputPath)) {
fs.writeFileSync('.env', `sfpowerscripts_pmd_output_path=${outputPath}\n`, {flag:'a'});
} else {
fs.writeFileSync('.env', `sfpowerscripts_pmd_output_path=${process.env.PWD}/pmd-output\n`, {flag:'a'});
}
}



//Do a one more pass, Temporary hack while this is fixed properly
let artifactFilePath = path.join(".sfpowerscripts","sf-pmd-output.xml");
pmdImpl = new AnalyzeWithPMDImpl(
source_directory,
rulesetpath,
"xml",
artifactFilePath,
version
);

await pmdImpl.exec(false);



if (fs.existsSync(artifactFilePath)) {
result = parseXmlReport(artifactFilePath);
}

if (isToBreakBuild && result[2] > 0)
throw new SfdxError(`Build Failed due to ${result[2]} critical defects found`);

} catch (err) {
console.log(err);
// Fail the task when an error occurs
process.exit(1);
}
}

private parseXmlReport(xmlReport: string): [number, number, number] {
let fileCount = 0;
let violationCount = 0;
let criticaldefects = 0;

let reportContent: string = fs.readFileSync(xmlReport, "utf-8");
xml2js.parseString(reportContent, (err, data) => {
// If the file is not XML, or is not from PMD, return immediately
if (!data || !data.pmd) {
console.debug(`Empty or unrecognized PMD xml report ${xmlReport}`);
return null;
}
function parseXmlReport(xmlReport: string): [number, number, number] {
let fileCount = 0;
let violationCount = 0;
let criticaldefects = 0;

if (!data.pmd.file || data.pmd.file.length === 0) {
// No files with violations, return now that it has been marked for upload
return null;
}


data.pmd.file.forEach((file: any) => {
if (file.violation) {
fileCount++;
violationCount += file.violation.length;
let reportContent: string = fs.readFileSync(xmlReport, "utf-8");
xml2js.parseString(reportContent, (err, data) => {
// If the file is not XML, or is not from PMD, return immediately
if (!data || !data.pmd) {
console.debug(`Empty or unrecognized PMD xml report ${xmlReport}`);
return null;
}

if (!data.pmd.file || data.pmd.file.length === 0) {
// No files with violations, return now that it has been marked for upload
return null;
}
});

for (let i = 0; i < data.pmd.file.length; i++) {
data.pmd.file[i].violation.forEach((element) => {
if (element["$"]["priority"] == 1) {
criticaldefects++;
data.pmd.file.forEach((file: any) => {
if (file.violation) {
fileCount++;
violationCount += file.violation.length;
}
});
}
});

return [violationCount, fileCount, criticaldefects];
}
for (let i = 0; i < data.pmd.file.length; i++) {
data.pmd.file[i].violation.forEach(element => {
if (element["$"]["priority"] == 1) {
criticaldefects++;
}
});
}
});

}
return [violationCount, fileCount, criticaldefects];
}
}
}