Skip to content

Commit 5e35c1b

Browse files
committed
#669 Support for relative paths when using "publishCodeCoverageResults "
1 parent 5337051 commit 5e35c1b

File tree

5 files changed

+129
-82
lines changed

5 files changed

+129
-82
lines changed

src/AzureDevopsTask/ReportGenerator/reportgenerator.ts

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,43 @@ async function executeReportGenerator(): Promise<number> {
2929
return await tool.execAsync();
3030
}
3131

32+
async function run() {
33+
const publishCodeCoverageResults = ((tl.getInput('publishCodeCoverageResults') || 'false') + '').toLowerCase() === 'true';
34+
try {
35+
tl.setResourcePath(path.join( __dirname, 'task.json'));
36+
37+
let code = await executeReportGenerator();
38+
if (code != 0) {
39+
tl.setResult(tl.TaskResult.Failed, tl.loc('FailedMsg'));
40+
return;
41+
}
42+
43+
if (!publishCodeCoverageResults) {
44+
tl.setResult(tl.TaskResult.Succeeded, tl.loc('SucceedMsg'));
45+
return;
46+
}
47+
}
48+
catch (e) {
49+
tl.debug(e.message);
50+
tl.setResult(tl.TaskResult.Failed, e.message);
51+
}
52+
53+
try {
54+
publishCodeCoverageReport();
55+
}
56+
catch (e) {
57+
tl.debug(e.message);
58+
tl.setResult(tl.TaskResult.Failed, tl.loc('FailedToPublishReportMsg') + ': ' + e.message);
59+
return;
60+
}
61+
}
62+
3263
function publishCodeCoverageReport() {
3364
if (((tl.getInput('publishCodeCoverageResults') || 'false') + '').toLowerCase() !== 'true') {
3465
return;
3566
}
3667

37-
const targetdir = trimPathEnd((tl.getInput('targetdir') || ''));
68+
const targetdir = resolvePathToSingleItem(tl.getInput('targetdir') || '');
3869
const reporttypes = (tl.getInput('reporttypes') || '').toLowerCase().split(';');
3970
const createSubdirectoryForAllReportTypes = (tl.getInput('customSettings') || '').toLowerCase().indexOf('createsubdirectoryforallreporttypes=true') > -1;
4071

@@ -71,49 +102,39 @@ function publishCodeCoverageReport() {
71102
tl.setResult(tl.TaskResult.Succeeded, tl.loc('SucceedMsg'));
72103
}
73104

74-
async function run() {
75-
const publishCodeCoverageResults = ((tl.getInput('publishCodeCoverageResults') || 'false') + '').toLowerCase() === 'true';
76-
try {
77-
tl.setResourcePath(path.join( __dirname, 'task.json'));
105+
// Resolves the specified path to a single item based on whether it contains wildcards
106+
function resolvePathToSingleItem(pathInput: string): string {
107+
// Default to using the specific pathInput value
108+
let resolvedPath: string = pathInput;
78109

79-
let code = await executeReportGenerator();
80-
if (code != 0) {
81-
tl.setResult(tl.TaskResult.Failed, tl.loc('FailedMsg'));
82-
return;
110+
if (pathInput) {
111+
// Find match patterns won't work if the directory has a trailing slash
112+
if (pathInput.endsWith('/') || pathInput.endsWith('\\')) {
113+
pathInput = pathInput.slice(0, -1);
83114
}
84-
85-
if (!publishCodeCoverageResults) {
86-
tl.setResult(tl.TaskResult.Succeeded, tl.loc('SucceedMsg'));
87-
return;
115+
// Resolve matches of the pathInput pattern
116+
const findOptions: tl.FindOptions = { allowBrokenSymbolicLinks: false, followSymbolicLinks: false, followSpecifiedSymbolicLink: false };
117+
const pathMatches: string[] = tl.findMatch(
118+
tl.getVariable('System.DefaultWorkingDirectory'),
119+
pathInput,
120+
findOptions);
121+
122+
// Were any matches found?
123+
if (pathMatches.length === 0) {
124+
resolvedPath = undefined;
125+
} else {
126+
// Select the path to be used from the matches
127+
resolvedPath = pathMatches[0];
128+
129+
// If more than one path matches, use the first and issue a warning
130+
if (pathMatches.length > 1) {
131+
tl.warning(tl.loc('MultipleSummaryFilesFound', resolvedPath));
132+
}
88133
}
89134
}
90-
catch (e) {
91-
tl.debug(e.message);
92-
tl.setResult(tl.TaskResult.Failed, e.message);
93-
}
94-
95-
try {
96-
publishCodeCoverageReport();
97-
}
98-
catch (e) {
99-
tl.debug(e.message);
100-
tl.setResult(tl.TaskResult.Failed, tl.loc('FailedToPublishReportMsg') + ': ' + e.message);
101-
return;
102-
}
103-
}
104-
105-
function trimPathEnd(input: string) {
106-
if (!input || input.length === 0) {
107-
return input;
108-
}
109-
110-
let result = input;
111-
112-
while (result.length > 0 && (result.endsWith('/') || result.endsWith('\\'))) {
113-
result = result.substring(0, result.length - 1);
114-
}
115135

116-
return result;
136+
// Return resolved path
137+
return resolvedPath;
117138
}
118139

119140
run();

src/AzureDevopsTask/ReportGenerator/task.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@
159159
},
160160
"messages": {
161161
"FailedMsg": "ReportGenerator failed",
162-
"SucceedMsg": "Successfully executed ReportGenerator."
162+
"FailedToPublishReportMsg": "Failed to publish report",
163+
"SucceedMsg": "Successfully executed ReportGenerator.",
164+
"PublishCodeCoverageResultsRequiresCobertura": "When using 'publishCodeCoverageResults: true' please add 'Cobertura' as a report type",
165+
"PublishCodeCoverageResultsRequiresHtmlFormat": "When using 'publishCodeCoverageResults: true' please add one of the Html report types",
166+
"MultipleSummaryFilesFound": "Multiple file or directory matches were found. Using the first match: %s"
163167
}
164168
}

src/AzureDevopsTaskTest/ReportGenerator/reportgenerator.ts

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,43 @@ async function executeReportGenerator(): Promise<number> {
2929
return await tool.execAsync();
3030
}
3131

32+
async function run() {
33+
const publishCodeCoverageResults = ((tl.getInput('publishCodeCoverageResults') || 'false') + '').toLowerCase() === 'true';
34+
try {
35+
tl.setResourcePath(path.join( __dirname, 'task.json'));
36+
37+
let code = await executeReportGenerator();
38+
if (code != 0) {
39+
tl.setResult(tl.TaskResult.Failed, tl.loc('FailedMsg'));
40+
return;
41+
}
42+
43+
if (!publishCodeCoverageResults) {
44+
tl.setResult(tl.TaskResult.Succeeded, tl.loc('SucceedMsg'));
45+
return;
46+
}
47+
}
48+
catch (e) {
49+
tl.debug(e.message);
50+
tl.setResult(tl.TaskResult.Failed, e.message);
51+
}
52+
53+
try {
54+
publishCodeCoverageReport();
55+
}
56+
catch (e) {
57+
tl.debug(e.message);
58+
tl.setResult(tl.TaskResult.Failed, tl.loc('FailedToPublishReportMsg') + ': ' + e.message);
59+
return;
60+
}
61+
}
62+
3263
function publishCodeCoverageReport() {
3364
if (((tl.getInput('publishCodeCoverageResults') || 'false') + '').toLowerCase() !== 'true') {
3465
return;
3566
}
3667

37-
const targetdir = trimPathEnd((tl.getInput('targetdir') || ''));
68+
const targetdir = resolvePathToSingleItem(tl.getInput('targetdir') || '');
3869
const reporttypes = (tl.getInput('reporttypes') || '').toLowerCase().split(';');
3970
const createSubdirectoryForAllReportTypes = (tl.getInput('customSettings') || '').toLowerCase().indexOf('createsubdirectoryforallreporttypes=true') > -1;
4071

@@ -71,49 +102,39 @@ function publishCodeCoverageReport() {
71102
tl.setResult(tl.TaskResult.Succeeded, tl.loc('SucceedMsg'));
72103
}
73104

74-
async function run() {
75-
const publishCodeCoverageResults = ((tl.getInput('publishCodeCoverageResults') || 'false') + '').toLowerCase() === 'true';
76-
try {
77-
tl.setResourcePath(path.join( __dirname, 'task.json'));
105+
// Resolves the specified path to a single item based on whether it contains wildcards
106+
function resolvePathToSingleItem(pathInput: string): string {
107+
// Default to using the specific pathInput value
108+
let resolvedPath: string = pathInput;
78109

79-
let code = await executeReportGenerator();
80-
if (code != 0) {
81-
tl.setResult(tl.TaskResult.Failed, tl.loc('FailedMsg'));
82-
return;
110+
if (pathInput) {
111+
// Find match patterns won't work if the directory has a trailing slash
112+
if (pathInput.endsWith('/') || pathInput.endsWith('\\')) {
113+
pathInput = pathInput.slice(0, -1);
83114
}
84-
85-
if (!publishCodeCoverageResults) {
86-
tl.setResult(tl.TaskResult.Succeeded, tl.loc('SucceedMsg'));
87-
return;
115+
// Resolve matches of the pathInput pattern
116+
const findOptions: tl.FindOptions = { allowBrokenSymbolicLinks: false, followSymbolicLinks: false, followSpecifiedSymbolicLink: false };
117+
const pathMatches: string[] = tl.findMatch(
118+
tl.getVariable('System.DefaultWorkingDirectory'),
119+
pathInput,
120+
findOptions);
121+
122+
// Were any matches found?
123+
if (pathMatches.length === 0) {
124+
resolvedPath = undefined;
125+
} else {
126+
// Select the path to be used from the matches
127+
resolvedPath = pathMatches[0];
128+
129+
// If more than one path matches, use the first and issue a warning
130+
if (pathMatches.length > 1) {
131+
tl.warning(tl.loc('MultipleSummaryFilesFound', resolvedPath));
132+
}
88133
}
89134
}
90-
catch (e) {
91-
tl.debug(e.message);
92-
tl.setResult(tl.TaskResult.Failed, e.message);
93-
}
94-
95-
try {
96-
publishCodeCoverageReport();
97-
}
98-
catch (e) {
99-
tl.debug(e.message);
100-
tl.setResult(tl.TaskResult.Failed, tl.loc('FailedToPublishReportMsg') + ': ' + e.message);
101-
return;
102-
}
103-
}
104-
105-
function trimPathEnd(input: string) {
106-
if (!input || input.length === 0) {
107-
return input;
108-
}
109-
110-
let result = input;
111-
112-
while (result.length > 0 && (result.endsWith('/') || result.endsWith('\\'))) {
113-
result = result.substring(0, result.length - 1);
114-
}
115135

116-
return result;
136+
// Return resolved path
137+
return resolvedPath;
117138
}
118139

119140
run();

src/AzureDevopsTaskTest/ReportGenerator/task.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"version": {
1414
"Major": 5,
1515
"Minor": 2,
16-
"Patch": 5
16+
"Patch": 4
1717
},
1818
"instanceNameFormat": "ReportGeneratorTest",
1919
"groups": [
@@ -162,6 +162,7 @@
162162
"FailedToPublishReportMsg": "Failed to publish report",
163163
"SucceedMsg": "Successfully executed ReportGenerator.",
164164
"PublishCodeCoverageResultsRequiresCobertura": "When using 'publishCodeCoverageResults: true' please add 'Cobertura' as a report type",
165-
"PublishCodeCoverageResultsRequiresHtmlFormat": "When using 'publishCodeCoverageResults: true' please add one of the Html report types"
165+
"PublishCodeCoverageResultsRequiresHtmlFormat": "When using 'publishCodeCoverageResults: true' please add one of the Html report types",
166+
"MultipleSummaryFilesFound": "Multiple file or directory matches were found. Using the first match: %s"
166167
}
167168
}

src/AzureDevopsTaskTest/vss-extension.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"manifestVersion": 1,
33
"id": "reportgeneratortest",
44
"name": "ReportGeneratorTest",
5-
"version": "5.2.5",
5+
"version": "5.2.4",
66
"publisher": "Palmmedia",
77
"public": false,
88
"targets": [

0 commit comments

Comments
 (0)