Skip to content

Commit 60f0f93

Browse files
author
Nitin Gurram
authored
Merge pull request #2855 from Microsoft/users/nigurr/FixAntCC-105
Fix Code coverage issue with Ant build tool
2 parents 5c0ad26 + 60bc474 commit 60f0f93

File tree

10 files changed

+450
-219
lines changed

10 files changed

+450
-219
lines changed

Tasks/ANT/anttask.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ function readJavaHomeFromRegistry(jdkVersion: string, arch: string): string {
108108
return javaHome;
109109
}
110110

111+
111112
async function doWork() {
112113

113114
function execEnableCodeCoverage(): Q.Promise<string> {
@@ -134,9 +135,13 @@ async function doWork() {
134135
reportDirectory = path.join(buildRootPath, reportDirectoryName);
135136
var reportBuildFileName = "CCReportBuildA4D283EG.xml";
136137
reportBuildFile = path.join(buildRootPath, reportBuildFileName);
137-
var summaryFileName = "coverage.xml";
138-
summaryFile = path.join(buildRootPath, reportDirectoryName);
139-
summaryFile = path.join(summaryFile, summaryFileName);
138+
var summaryFileName = "";
139+
if (ccTool.toLowerCase() == "jacoco") {
140+
summaryFileName = "summary.xml";
141+
}else if (ccTool.toLowerCase() == "cobertura") {
142+
summaryFileName = "coverage.xml";
143+
}
144+
summaryFile = path.join(buildRootPath, reportDirectoryName, summaryFileName);
140145
var coberturaCCFile = path.join(buildRootPath, "cobertura.ser");
141146
var instrumentedClassesDirectory = path.join(buildRootPath, "InstrumentedClasses");
142147

@@ -263,7 +268,7 @@ async function doWork() {
263268
var ccTool = tl.getInput('codeCoverageTool');
264269
var isCodeCoverageOpted = (typeof ccTool != "undefined" && ccTool && ccTool.toLowerCase() != 'none');
265270
var buildRootPath = path.dirname(antBuildFile);
266-
271+
267272
var summaryFile: string = null;
268273
var reportDirectory: string = null;
269274
var ccReportTask: string = null;

Tasks/ANT/task.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"version": {
1414
"Major": 1,
1515
"Minor": 0,
16-
"Patch": 55
16+
"Patch": 56
1717
},
1818
"demands": [
1919
"ant"

Tasks/ANT/task.loc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"version": {
1414
"Major": 1,
1515
"Minor": 0,
16-
"Patch": 55
16+
"Patch": 56
1717
},
1818
"demands": [
1919
"ant"

Tasks/Common/codecoverage-tools/cobertura/cobertura.ant.ccenabler.ts

Lines changed: 44 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,8 @@ export class CoberturaAntCodeCoverageEnabler extends cc.CoberturaCodeCoverageEna
4646

4747
tl.debug("Reading the build file: " + _this.buildFile);
4848

49-
return util.readXmlFileAsJson(_this.buildFile)
50-
.then(function (resp) {
51-
return _this.addCodeCoverageData(resp);
52-
})
49+
let buildContent = util.readXmlFileAsDom(_this.buildFile);
50+
return _this.addCodeCoverageData(buildContent)
5351
.thenResolve(true);
5452
}
5553

@@ -68,25 +66,20 @@ export class CoberturaAntCodeCoverageEnabler extends cc.CoberturaCodeCoverageEna
6866
return ccfilter;
6967
}
7068

71-
protected getClassData(): any {
69+
protected getClassData(): string {
7270
let _this = this;
73-
let fileset = [];
71+
let classData = "";
7472
let classDirs = _this.classDirs;
7573

7674
if (str(classDirs).isEmpty()) {
7775
classDirs = ".";
7876
}
7977
classDirs.split(",").forEach(cdir => {
80-
let filter = {
81-
$: {
82-
dir: cdir,
83-
includes: _this.includeFilter,
84-
excludes: _this.excludeFilter
85-
}
86-
};
87-
fileset.push(filter);
78+
classData += classData + `
79+
<fileset dir="${cdir}" includes="${_this.includeFilter}" excludes="${_this.excludeFilter}" />
80+
`;
8881
});
89-
return fileset;
82+
return classData;
9083
}
9184

9285
protected createReportFile(reportContent: string): Q.Promise<void> {
@@ -97,94 +90,70 @@ export class CoberturaAntCodeCoverageEnabler extends cc.CoberturaCodeCoverageEna
9790
return util.writeFile(reportFile, reportContent);
9891
}
9992

100-
protected addCodeCoverageData(pomJson: any): Q.Promise<any[]> {
93+
protected addCodeCoverageData(pomJson: CheerioStatic): Q.Promise<any[]> {
10194
let _this = this;
10295

103-
if (!pomJson || !pomJson.project) {
96+
if (!pomJson || !pomJson("project")) {
10497
return Q.reject<any>(tl.loc("InvalidBuildFile"));
10598
}
10699

107100
let reportPluginData = ccc.coberturaAntReport(_this.sourceDirs, path.join(path.dirname(_this.buildFile), _this.reportDir));
108101
return Q.all([_this.addCodeCoverageNodes(pomJson), _this.createReportFile(reportPluginData)]);
109102
}
110103

111-
protected addCodeCoverageNodes(buildJsonContent: any): Q.Promise<any> {
104+
protected addCodeCoverageNodes(buildJsonContent: CheerioStatic): Q.Promise<any> {
112105
let _this = this;
113106

114-
if (!buildJsonContent.project.target) {
115-
tl.debug("Build tag is not present");
107+
if (!buildJsonContent("project").children("target")) {
108+
tl.debug("Target tasks are not present");
116109
return Q.reject(tl.loc("InvalidBuildFile"));
117110
}
118111

119-
ccc.coberturaAntCoverageEnable(buildJsonContent.project);
120-
121-
if (!buildJsonContent.project.target || typeof buildJsonContent.project.target === "string") {
122-
buildJsonContent.project.target = {};
123-
}
112+
buildJsonContent("project").prepend(ccc.coberturaAntCoverageEnable());
113+
buildJsonContent("project").children("target").each(function (i, elem) {
114+
_this.enableForking(buildJsonContent, elem);
115+
});
124116

125-
if (buildJsonContent.project.target instanceof Array) {
126-
buildJsonContent.project.target.forEach(element => {
127-
_this.enableForking(element);
128-
});
129-
} else {
130-
_this.enableForking(buildJsonContent.project.target);
131-
}
132-
return util.writeJsonAsXmlFile(_this.buildFile, buildJsonContent);
117+
return util.writeFile(_this.buildFile, buildJsonContent.xml());
133118
}
134119

135-
protected enableForking(targetNode: any) {
120+
protected enableForking(buildJsonContent: CheerioStatic, targetNode: CheerioElement) {
136121
let _this = this;
137-
let coberturaNode = ccc.coberturaAntInstrumentedClasses(path.dirname(_this.buildFile), _this.reportDir);
138-
coberturaNode.fileset = _this.getClassData();
139122
let testNodes = ["junit", "java", "testng", "batchtest"];
140-
141-
if (targetNode.javac) {
142-
if (targetNode.javac instanceof Array) {
143-
targetNode.javac.forEach(jn => {
144-
jn.$.debug = "true";
145-
});
146-
}
123+
let buildDir = path.dirname(_this.buildFile);
124+
let coberturaNode = ccc.coberturaAntProperties(path.join(buildDir, _this.reportDir), path.dirname(_this.buildFile));
125+
let classData = ccc.coberturaAntInstrumentedClasses(buildDir, path.join(buildDir, _this.reportDir), _this.getClassData());
126+
127+
if (targetNode.children) {
128+
targetNode.children.forEach(n => {
129+
if (n.name && n.name === "javac") {
130+
n.attribs["debug"] = "true";
131+
}
132+
});
147133
}
148134

149135
testNodes.forEach(tn => {
150-
if (!targetNode[tn]) {
136+
if (!targetNode.children) {
151137
return;
152138
}
153139

154-
let node = targetNode[tn];
155-
_this.enableForkOnTestNodes(node, true);
156-
if (node instanceof Array) {
157-
node.forEach(n => {
158-
ccc.coberturaAntProperties(n, _this.reportDir, path.dirname(_this.buildFile));
159-
});
160-
} else {
161-
ccc.coberturaAntProperties(node, _this.reportDir, path.dirname(_this.buildFile));
140+
targetNode.children.forEach(node => {
141+
if (node.name && node.name === tn) {
142+
_this.enableForkOnTestNodes(node);
143+
buildJsonContent("project").children("target").children(tn).prepend(coberturaNode);
144+
buildJsonContent("project").children("target").children(tn).append(ccc.coberturaAntClasspathRef());
145+
};
146+
});
147+
if (buildJsonContent("project").children("target").children(tn)
148+
&& (!buildJsonContent("project").children("target").children("cobertura-instrument")
149+
|| buildJsonContent("project").children("target").children("cobertura-instrument").length === 0)) {
150+
buildJsonContent("project").children("target").children(tn).before(classData);
162151
}
163-
164-
targetNode["cobertura-instrument"] = coberturaNode;
165152
});
166153
}
167154

168-
protected enableForkOnTestNodes(testNode: any, enableForkMode: boolean) {
169-
if (testNode instanceof Array) {
170-
testNode.forEach(element => {
171-
if (!element.$) {
172-
element.$ = {};
173-
}
174-
if (enableForkMode) {
175-
element.$.forkmode = "once";
176-
}
177-
element.$.fork = "true";
178-
179-
});
180-
} else {
181-
if (!testNode.$) {
182-
testNode.$ = {};
183-
}
184-
if (enableForkMode) {
185-
testNode.$.forkmode = "once";
186-
}
187-
testNode.$.fork = "true";
188-
}
155+
protected enableForkOnTestNodes(testNode: CheerioElement) {
156+
testNode.attribs["forkmode"] = "once";
157+
testNode.attribs["fork"] = "true";
189158
}
190159
}

Tasks/Common/codecoverage-tools/codecoverageconstants.ts

Lines changed: 48 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -373,34 +373,34 @@ export function coberturaMavenReport(): Q.Promise<any> {
373373
}
374374

375375
export function jacocoAntReport(reportDir: string, classData: string, sourceData: string): string {
376-
return `
377-
<?xml version='1.0'?>
378-
<project name='JacocoReport'>
379-
<target name='CodeCoverage_9064e1d0'>
380-
<jacoco:report xmlns:jacoco='antlib:org.jacoco.ant'>
381-
<executiondata>
382-
<file file='${path.join(reportDir, "jacoco.exec")}'/>
383-
</executiondata>
384-
<structure name = 'Jacoco report'>
385-
<classfiles>${classData}</classfiles>
386-
<sourcefiles>${sourceData}</sourcefiles>
387-
</structure>
388-
<html destdir='${reportDir}' />
389-
<csv destfile='${reportDir + path.sep}summary.csv' />
390-
<xml destfile='${reportDir + path.sep}summary.xml' />
391-
</jacoco:report>
392-
</target>
393-
</project>
376+
return `<?xml version="1.0"?>
377+
<project name="JacocoReport">
378+
<target name="CodeCoverage_9064e1d0">
379+
<jacoco:report xmlns:jacoco="antlib:org.jacoco.ant">
380+
<executiondata>
381+
<file file="${path.join(reportDir, "jacoco.exec")}"/>
382+
</executiondata>
383+
<structure name="Jacoco report">
384+
<classfiles>${classData}</classfiles>
385+
<sourcefiles>${sourceData}</sourcefiles>
386+
</structure>
387+
<html destdir="${reportDir}" />
388+
<csv destfile="${reportDir + path.sep}summary.csv" />
389+
<xml destfile="${reportDir + path.sep}summary.xml" />
390+
</jacoco:report>
391+
</target>
392+
</project>
394393
`;
395394
}
396395

397-
export function jacocoAntCoverageEnable(): any {
396+
export function jacocoAntCoverageEnable(reportDir: string): any {
397+
let file = path.join(reportDir,"jacoco.exec");
398398
return {
399399
$:
400400
{
401-
"destfile": "jacoco.exec",
401+
"destfile": file,
402402
"append": true,
403-
"xlmns:jacoco": "antlib:org.jacoco.ant"
403+
"xmlns:jacoco": "antlib:org.jacoco.ant"
404404
}
405405
};
406406
}
@@ -424,80 +424,38 @@ export function coberturaAntReport(srcDir: string, reportDir: string): string {
424424
`;
425425
}
426426

427-
export function coberturaAntCoverageEnable(buildJsonContent: any): void {
428-
let propertyNode = {
429-
$: {
430-
environment: "env"
431-
}
432-
};
433-
util.addPropToJson(buildJsonContent, "property", propertyNode);
434-
435-
let pathNode = {
436-
$: {
437-
id: "cobertura-classpath",
438-
description: "classpath for instrumenting classes"
439-
},
440-
fileset: {
441-
$: {
442-
dir: "${env.COBERTURA_HOME}"
443-
},
444-
include: [
445-
{
446-
$: {
447-
name: "cobertura*.jar"
448-
}
449-
},
450-
{
451-
$: {
452-
name: "**/lib/**/*.jar"
453-
}
454-
}
455-
]
456-
}
457-
};
458-
util.addPropToJson(buildJsonContent, "path", pathNode);
459-
460-
let taskdefNode = {
461-
$: {
462-
classpathref: "cobertura-classpath",
463-
resource: "tasks.properties"
464-
}
465-
};
466-
util.addPropToJson(buildJsonContent, "taskdef", taskdefNode);
427+
export function coberturaAntCoverageEnable(): string {
428+
return `
429+
<property environment="env" />
430+
<path id="cobertura-classpath-vsts" description="classpath for instrumenting classes">
431+
<fileset dir="\${env.COBERTURA_HOME}">
432+
<include name="cobertura*.jar" />
433+
<include name="**/lib/**/*.jar" />
434+
</fileset>
435+
</path>
436+
<taskdef classpathref="cobertura-classpath-vsts" resource="tasks.properties" />
437+
`;
467438
}
468439

469-
export function coberturaAntInstrumentedClasses(baseDir: string, reportDir: string): any {
470-
let ccProperty = {
471-
$: {
472-
todir: path.join(baseDir, "InstrumentedClasses"),
473-
datafile: path.join(baseDir, reportDir, "cobertura.ser")
474-
},
475-
fileset: []
476-
};
477-
return ccProperty;
440+
export function coberturaAntInstrumentedClasses(baseDir: string, reportDir: string, classData: string): any {
441+
return `
442+
<cobertura-instrument todir="${path.join(baseDir,"InstrumentedClasses")}" datafile="${path.join(reportDir,"cobertura.ser")}">
443+
${classData}
444+
</cobertura-instrument>
445+
`;
478446
}
479447

480-
export function coberturaAntProperties(node: any, reportDir: string, baseDir: string): any {
481-
node.sysproperty = {
482-
$: {
483-
key: "net.sourceforge.cobertura.datafile",
484-
file: path.join(baseDir, reportDir, "cobertura.ser")
485-
}
486-
};
487-
488-
let classpath = [
489-
{
490-
$: {
491-
location: path.join(baseDir, "InstrumentedClasses"),
492-
}
493-
}
494-
];
448+
export function coberturaAntProperties(reportDir: string, baseDir: string): any {
449+
return `
450+
<sysproperty key="net.sourceforge.cobertura.datafile" file="${path.join(reportDir,"cobertura.ser")}" />
451+
<classpath location="${path.join(baseDir,"InstrumentedClasses")}" />
452+
`;
453+
}
495454

496-
if (node.classpath && node.classpath instanceof Array) {
497-
node.classpath = classpath.concat(node.classpath);
498-
} else {
499-
node.classpath = classpath;
500-
}
455+
export function coberturaAntClasspathRef(): string {
456+
return `
457+
<classpath refid="cobertura-classpath-vsts" />
458+
`;
501459
}
502460

503461
// Gradle Coberutra plugin

0 commit comments

Comments
 (0)