Skip to content

Commit

Permalink
issue #217 (dxatscale#218)
Browse files Browse the repository at this point in the history
* issue #217

issue #217

exposting test result in csv or json format

* json output
  • Loading branch information
manisfdcsfdx authored Mar 6, 2020
1 parent 06fdc8d commit 3687576
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 14 deletions.
28 changes: 20 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -864,19 +864,31 @@ Gets the apex tests coverage of an org

```
USAGE
$ sfdx sfpowerkit:org:orgcoverage [-u <string>] [--apiversion <string>] [--json] [--loglevel
trace|debug|info|warn|error|fatal]
$ sfdx sfpowerkit:org:orgcoverage [-d <string>] [-f json|csv] [-u <string>] [--apiversion <string>] [--json] [--loglevel trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL]

OPTIONS
-u, --targetusername=targetusername username or alias for the target org;
--apiversion=apiversion override the api version used for api requests made by this command
--json format output as json
--loglevel=(trace|debug|info|warn|error|fatal) [default: warn] logging level for this command invocation
-d, --output=output The output dir where the output will be created
-f, --format=(json|csv) The format for the test result output, Possible values are json/csv
-u, --targetusername=targetusername username or alias for the target org; overrides default target org
--apiversion=apiversion override the api version used for api requests made by this command
--json format output as json
--loglevel=(trace|debug|info|warn|error|fatal|TRACE|DEBUG|INFO|WARN|ERROR|FATAL) [default: warn] logging level for this command invocation

EXAMPLE
$ sfdx sfpowerkit:org:orgcoverage -u myOrg@example.com
Successfully Retrieved the Apex Test Coverage of the org 00D0k000000DmdpEAC
coverage:85
sfdx sfpowerkit:org:orgcoverage -u myOrg@example.com -d testResult -f csv
sfdx sfpowerkit:org:orgcoverage -u myOrg@example.com -d testResult -f json


Successfully Retrieved the Apex Test Coverage of the org XXXX
coverage:85
ID NAME TYPE PERCENTAGE COMMENTS UNCOVERED LINES
─────── ────────────────── ──────── ────────── ─────────────────────────────────── ──────────────────
01pxxxx sampleController ApexClass 100%
01pxxxx sampletriggerHandler ApexClass 80% Looks fine but target more than 85% 62;76;77;
01pxxxx sampleHelper ApexClass 72% Action required 62;76;77;78;98;130;131
01qxxxx sampleTrigger ApexTrigger 100%
Output testResult/output.csv is generated successfully
```

_See code: [src\commands\sfpowerkit\org\orgcoverage.ts](https://github.com/Accenture/sfpowerkit/blob/master/src/commands/sfpowerkit/org/orgcoverage.ts)_
Expand Down
4 changes: 3 additions & 1 deletion messages/org_coverage.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"commandDescription": "Gets the apex test coverage details of an org"
"commandDescription": "Gets the apex test coverage details of an org",
"outputFolderDescription": " The output dir where the output will be created",
"formatFlagDescription": " The format for the test result output, Possible values are json/csv"
}
129 changes: 124 additions & 5 deletions src/commands/sfpowerkit/org/orgcoverage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { core, flags, SfdxCommand, Result } from "@salesforce/command";
import {
core,
flags,
FlagsConfig,
SfdxCommand,
Result
} from "@salesforce/command";
import { SfdxError } from "@salesforce/core";
import { AnyJson } from "@salesforce/ts-types";
import fs = require("fs-extra");
import * as path from "path";
import FileUtils from "../../../utils/fileutils";
import request = require("request-promise-native");
import rimraf = require("rimraf");
const querystring = require("querystring");
Expand All @@ -16,18 +25,49 @@ export default class OrgCoverage extends SfdxCommand {
public static description = messages.getMessage("commandDescription");

public static examples = [
`$ sfdx sfpowerkit:org:orgcoverage -u [email protected]
`$ sfdx sfpowerkit:org:orgcoverage -u [email protected]
sfdx sfpowerkit:org:orgcoverage -u [email protected] -d testResult -f csv
sfdx sfpowerkit:org:orgcoverage -u [email protected] -d testResult -f json
Successfully Retrieved the Apex Test Coverage of the org XXXX
coverage:85
ID NAME TYPE PERCENTAGE COMMENTS UNCOVERED LINES
─────── ────────────────── ──────── ────────── ─────────────────────────────────── ──────────────────
01pxxxx sampleController ApexClass 100%
01pxxxx sampletriggerHandler ApexClass 80% Looks fine but target more than 85% 62;76;77;
01pxxxx sampleHelper ApexClass 72% Action required 62;76;77;78;98;130;131
01qxxxx sampleTrigger ApexTrigger 100%
Output testResult/output.csv is generated successfully
`
];

protected static flagsConfig: FlagsConfig = {
output: flags.string({
char: "d",
description: messages.getMessage("outputFolderDescription"),
required: false
}),
format: flags.enum({
required: false,
char: "f",
description: messages.getMessage("formatFlagDescription"),
options: ["json", "csv"]
})
};

// Comment this out if your command does not require an org username
protected static requiresUsername = true;

public async run(): Promise<AnyJson> {
rimraf.sync("temp_sfpowerkit");

if (this.flags.output && !this.flags.format) {
throw new SfdxError("format is required to generate the output");
} else if (this.flags.format && !this.flags.output) {
throw new SfdxError("output path is required to generate the output");
}

await this.org.refreshAuth();

const conn = this.org.getConnection();
Expand All @@ -47,7 +87,12 @@ export default class OrgCoverage extends SfdxCommand {
);
this.ux.log(`coverage:${apexcoverage.coverage}`);

return { coverage: apexcoverage.coverage };
const classCoverage = await this.getApexCoverageByDetails(
conn,
this.flags.output
);

return { coverage: apexcoverage.coverage, classCoverage: classCoverage };
}

public async getApexCoverage(conn: core.Connection) {
Expand All @@ -57,8 +102,6 @@ export default class OrgCoverage extends SfdxCommand {

var query_uri = `${conn.instanceUrl}/services/data/v${this.flags.apiversion}/tooling/query?q=${encoded_querystring}`;

//this.ux.log(`Query URI ${query_uri}`);

const coverage_score_query_result = await request({
method: "get",
url: query_uri,
Expand All @@ -71,6 +114,82 @@ export default class OrgCoverage extends SfdxCommand {
// this.ux.logJson(health_score_query_result);
return coverage_score_query_result.records[0].PercentCovered;
}
public async getApexCoverageByDetails(
conn: core.Connection,
outputDir: string
) {
let query =
"SELECT ApexClassOrTriggerId, ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered, coverage FROM ApexCodeCoverageAggregate ORDER BY ApexClassOrTrigger.Name";

const results = (await conn.tooling.query(query)) as any;
const output = [];
if (results.size > 0) {
results.records.forEach(element => {
let percentage =
element.NumLinesCovered === 0
? 0
: Math.round(
(element.NumLinesCovered /
(element.NumLinesCovered + element.NumLinesUncovered)) *
100
);
output.push({
id: element.ApexClassOrTriggerId,
name: element.ApexClassOrTrigger.Name,
type: element.ApexClassOrTrigger.attributes.url.split("/")[6],
percentage: `${percentage}%`,
comments:
percentage < 75
? "Action required"
: percentage < 85 && percentage >= 75
? "Looks fine but target more than 85%"
: "",
uncoveredLines: element.Coverage.uncoveredLines.join(";")
});
});

this.ux.table(output, [
"id",
"name",
"type",
"percentage",
"comments",
"uncoveredLines"
]);

if (this.flags.format && this.flags.format === "json") {
rimraf.sync(outputDir);
await this.generateJsonOutput(output, outputDir);
} else if (this.flags.format && this.flags.format === "csv") {
rimraf.sync(outputDir);
await this.generateCSVOutput(output, outputDir);
}
}
return output;
}
public async generateJsonOutput(testResult: AnyJson, outputDir: string) {
let outputJsonPath = `${outputDir}/output.json`;
let dir = path.parse(outputJsonPath).dir;
if (!fs.existsSync(dir)) {
FileUtils.mkDirByPathSync(dir);
}
fs.writeFileSync(outputJsonPath, JSON.stringify(testResult));
this.ux.log(`Output ${outputDir}/output.json is generated successfully`);
}
public async generateCSVOutput(testResult: any[], outputDir: string) {
let outputcsvPath = `${outputDir}/output.csv`;
let dir = path.parse(outputcsvPath).dir;
if (!fs.existsSync(dir)) {
FileUtils.mkDirByPathSync(dir);
}
let newLine = "\r\n";
let output = "ID,NAME,TYPE,PERCENTAGE,COMMENTS,UNCOVERED LINES" + newLine;
testResult.forEach(element => {
output = `${output}${element.id},${element.name},${element.type},${element.percentage},${element.comments},${element.uncoveredLines}${newLine}`;
});
fs.writeFileSync(outputcsvPath, output);
this.ux.log(`Output ${outputDir}/output.csv is generated successfully`);
}
}

export class ApexCoverage {
Expand Down

0 comments on commit 3687576

Please sign in to comment.