Skip to content

Commit f9585bb

Browse files
bgavrilMSBogdan Gavril
authored andcommitted
Maven task does not find the task-report.txt is some cases (#2559)
* Search for task-report.txt instead of picking it up from a fixed location * Update Gradle to use the same aproach * fs exists sync * Remove unused var
1 parent c9029c2 commit f9585bb

File tree

14 files changed

+145
-58
lines changed

14 files changed

+145
-58
lines changed

Tasks/Gradle/CodeAnalysis/SonarQube/common.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import Q = require('q');
44
import path = require('path');
5+
import glob = require('glob');
56

67
import {ToolRunner} from 'vsts-task-lib/toolrunner';
78

@@ -40,9 +41,15 @@ export function applySonarQubeParameters(toolRunner: ToolRunner): ToolRunner {
4041
* @param sqBuildFolder
4142
* @returns {Promise<void>} Promise resolved when all SQ integration actions are complete.
4243
*/
43-
export function processSonarQubeIntegration(sqBuildFolder:string):Q.Promise<void> {
44-
var sqRunSettings:SonarQubeRunSettings = getSonarQubeRunSettings(sqBuildFolder);
45-
var sqMetrics:SonarQubeMetrics = getSonarQubeMetrics(sqRunSettings);
44+
export function processSonarQubeIntegration(sqTaskReportGlob: string): Q.Promise<void> {
45+
46+
let sqTaskReportPath: string = findReportTaskFile(sqTaskReportGlob);
47+
if (sqTaskReportPath === null) {
48+
return Q.when();
49+
}
50+
51+
var sqRunSettings: SonarQubeRunSettings = getSonarQubeRunSettings(sqTaskReportPath);
52+
var sqMetrics: SonarQubeMetrics = getSonarQubeMetrics(sqRunSettings);
4653

4754
// Wait for all promises to complete before proceeding (even if one or more promises reject).
4855
return Q.all([
@@ -58,28 +65,46 @@ export function processSonarQubeIntegration(sqBuildFolder:string):Q.Promise<void
5865
* Returns, as an object, the contents of the report-task.txt file created by SonarQube plugins
5966
* The returned object contains the following properties:
6067
* projectKey, serverUrl, dashboardUrl, ceTaskId, ceTaskUrl
61-
* @param sonarPluginFolder The folder created by SonarQube integration during build
68+
* @param sqTaskReportPath Path to the report-task.txt file
6269
* @returns {SonarQubeRunSettings} An object with fields corresponding to the properties exposed in report-task.txt, or null if PR build
6370
*/
64-
function getSonarQubeRunSettings(sonarPluginFolder: string): SonarQubeRunSettings {
71+
function getSonarQubeRunSettings(sqTaskReportPath: string): SonarQubeRunSettings {
6572
if (VstsServerUtils.isPrBuild()) {
6673
return null;
6774
}
6875

69-
var reportFilePath:string = path.join(sonarPluginFolder, 'report-task.txt');
70-
return SonarQubeRunSettings.createRunSettingsFromFile(reportFilePath);
76+
return SonarQubeRunSettings.createRunSettingsFromFile(sqTaskReportPath);
7177
}
7278

7379
/**
7480
* Returns the appropriate SQMetrics object for this build.
7581
* @param sqRunSettings An object with fields corresponding to the properties exposed in report-task.txt
7682
* @returns {SonarQubeMetrics} An SQMetrics instance for this build on the SQ server, or null if PR build
7783
*/
78-
function getSonarQubeMetrics(sqRunSettings:SonarQubeRunSettings): SonarQubeMetrics {
84+
function getSonarQubeMetrics(sqRunSettings: SonarQubeRunSettings): SonarQubeMetrics {
7985
if (VstsServerUtils.isPrBuild()) {
8086
return null;
8187
}
8288

83-
var sqServer:ISonarQubeServer = new SonarQubeServer(SonarQubeEndpoint.getTaskSonarQubeEndpoint());
89+
var sqServer: ISonarQubeServer = new SonarQubeServer(SonarQubeEndpoint.getTaskSonarQubeEndpoint());
8490
return new SonarQubeMetrics(sqServer, sqRunSettings.ceTaskId);
91+
}
92+
93+
function findReportTaskFile(reportTaskGlob: string): string {
94+
95+
// the output folder may not be directly in the build root, for example if the entire project is in a top-lvel dir
96+
let reportTaskGlobResults: string[] = glob.sync(reportTaskGlob);
97+
98+
tl.debug(`[SQ] Searching for ${reportTaskGlob} - found ${reportTaskGlobResults.length} file(s)`);
99+
100+
if (reportTaskGlobResults.length === 0) {
101+
tl.warning(tl.loc('sqAnalysis_NoReportTask'));
102+
return null;
103+
}
104+
105+
if (reportTaskGlobResults.length > 1) {
106+
tl.warning(tl.loc('sqAnalysis_MultipleReportTasks'));
107+
}
108+
109+
return reportTaskGlobResults[0];
85110
}

Tasks/Gradle/CodeAnalysis/SonarQube/run-settings.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ export class SonarQubeRunSettings {
1818
* @param ceTaskUrl A string leading to the SonarQube Web API endpoint for the details of this analysis task
1919
*/
2020
constructor(public projectKey: string,
21-
public serverUrl: string,
22-
public dashboardUrl: string,
23-
public ceTaskId: string,
24-
public ceTaskUrl: string) {
21+
public serverUrl: string,
22+
public dashboardUrl: string,
23+
public ceTaskId: string,
24+
public ceTaskUrl: string) {
2525
if (!projectKey) {
2626
// Looks like: Failed to create TaskReport object. Missing field: projectKey
2727
throw new Error(tl.loc('sqCommon_CreateTaskReport_MissingField', 'projectKey'));
@@ -49,8 +49,9 @@ export class SonarQubeRunSettings {
4949
* @param filePath Path to a report-task.txt file generated by a SonarQube build plugin
5050
* @returns {SonarQubeRunSettings} A new SonarQubeRunSettings with appropriate fields filled
5151
*/
52-
public static createRunSettingsFromFile(filePath:string): SonarQubeRunSettings {
53-
if (!tl.exist(filePath)) {
52+
public static createRunSettingsFromFile(filePath: string): SonarQubeRunSettings {
53+
54+
if (!SonarQubeRunSettings.fsExistsSync(filePath)) {
5455
tl.debug('Task report not found at: ' + filePath);
5556
// Looks like: Invalid or missing task report. Check SonarQube finished successfully.
5657
throw new Error(tl.loc('sqAnalysis_TaskReportInvalid'));
@@ -76,19 +77,17 @@ export class SonarQubeRunSettings {
7677
// Looks like: Invalid or missing task report. Check SonarQube finished successfully.
7778
throw new Error(tl.loc('sqAnalysis_TaskReportInvalid'));
7879
}
79-
80-
8180
}
8281

8382
/**
8483
* Transforms a string read of report-task.txt into a key-value map of the run settings.
8584
* @param runSettingsString The contents of report-task.txt as a string
8685
*/
87-
private static createRunSettingsMapFromString(runSettingsString:string):Map<string, string> {
86+
private static createRunSettingsMapFromString(runSettingsString: string): Map<string, string> {
8887
var lines: string[] = runSettingsString.replace(/\r\n/g, '\n').split('\n'); // proofs against xplat line-ending issues
8988

9089
var runSettingsMap = new Map<string, string>();
91-
lines.forEach((line:string) => {
90+
lines.forEach((line: string) => {
9291
var splitLine: string[] = line.split('=');
9392
if (splitLine.length > 1) {
9493
runSettingsMap.set(splitLine[0], splitLine.slice(1, splitLine.length).join());
@@ -97,4 +96,13 @@ export class SonarQubeRunSettings {
9796

9897
return runSettingsMap;
9998
}
99+
100+
private static fsExistsSync(filePath: string): boolean {
101+
try {
102+
fs.accessSync(filePath);
103+
return true;
104+
} catch (e) {
105+
return false;
106+
}
107+
}
100108
}

Tasks/Gradle/CodeAnalysis/gradlesonar.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import Q = require('q');
44
import path = require('path');
55
import fs = require('fs');
6+
import glob = require('glob');
67

78
import tl = require('vsts-task-lib/task');
89
import trm = require('vsts-task-lib/toolrunner');
@@ -50,6 +51,9 @@ export function processSonarQubeIntegration(): Q.Promise<void> {
5051
return Q.when();
5152
}
5253

53-
var sqBuildFolder: string = path.join(tl.getVariable('build.sourcesDirectory'), 'build', 'sonar');
54-
return sqCommon.processSonarQubeIntegration(sqBuildFolder);
55-
}
54+
// the output folder may not be directly in the build root, for example if the entire project is in a top-lvel dir
55+
var reportTaskGlob: string = path.join(tl.getVariable('build.sourcesDirectory'), '**', 'build', 'sonar', 'report-task.txt');
56+
57+
return sqCommon.processSonarQubeIntegration(reportTaskGlob);
58+
}
59+

Tasks/Gradle/Strings/resources.resjson/en-US/resources.resjson

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080
"loc.messages.sqAnalysis_QualityGatePassed": "The SonarQube quality gate associated with this build has passed (status %s)",
8181
"loc.messages.sqAnalysis_UnknownComparatorString": "The SonarQube build summary encountered a problem: unknown comparator '%s'",
8282
"loc.messages.sqAnalysis_NoUnitsFound": "The list of SonarQube measurement units could not be retrieved from the server.",
83+
"loc.messages.sqAnalysis_NoReportTask": "Could not find report-task.txt. Possible cause: the SonarQube analysis did not complete successfully.",
84+
"loc.messages.sqAnalysis_MultipleReportTasks": "Multiple report-task.txt files found. Choosing the first one. The build summary and the build breaker may not be accurate. Possible cause: multiple SonarQube analysis during the same build, which is not supported.",
8385
"loc.messages.codeAnalysisBuildSummaryLine_SomeViolationsSomeFiles": "%s found %d violations in %d files.",
8486
"loc.messages.codeAnalysisBuildSummaryLine_SomeViolationsOneFile": "%s found %d violations in 1 file.",
8587
"loc.messages.codeAnalysisBuildSummaryLine_OneViolationOneFile": "%s found 1 violation in 1 file.",

Tasks/Gradle/task.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"version": {
1313
"Major": 1,
1414
"Minor": 0,
15-
"Patch": 60
15+
"Patch": 61
1616
},
1717
"demands": [
1818
"java"
@@ -344,6 +344,8 @@
344344
"sqAnalysis_QualityGatePassed": "The SonarQube quality gate associated with this build has passed (status %s)",
345345
"sqAnalysis_UnknownComparatorString": "The SonarQube build summary encountered a problem: unknown comparator '%s'",
346346
"sqAnalysis_NoUnitsFound": "The list of SonarQube measurement units could not be retrieved from the server.",
347+
"sqAnalysis_NoReportTask": "Could not find report-task.txt. Possible cause: the SonarQube analysis did not complete successfully.",
348+
"sqAnalysis_MultipleReportTasks": "Multiple report-task.txt files found. Choosing the first one. The build summary and the build breaker may not be accurate. Possible cause: multiple SonarQube analysis during the same build, which is not supported.",
347349
"codeAnalysisBuildSummaryLine_SomeViolationsSomeFiles": "%s found %d violations in %d files.",
348350
"codeAnalysisBuildSummaryLine_SomeViolationsOneFile": "%s found %d violations in 1 file.",
349351
"codeAnalysisBuildSummaryLine_OneViolationOneFile": "%s found 1 violation in 1 file.",

Tasks/Gradle/task.loc.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"version": {
1313
"Major": 1,
1414
"Minor": 0,
15-
"Patch": 60
15+
"Patch": 61
1616
},
1717
"demands": [
1818
"java"
@@ -344,6 +344,8 @@
344344
"sqAnalysis_QualityGatePassed": "ms-resource:loc.messages.sqAnalysis_QualityGatePassed",
345345
"sqAnalysis_UnknownComparatorString": "ms-resource:loc.messages.sqAnalysis_UnknownComparatorString",
346346
"sqAnalysis_NoUnitsFound": "ms-resource:loc.messages.sqAnalysis_NoUnitsFound",
347+
"sqAnalysis_NoReportTask": "ms-resource:loc.messages.sqAnalysis_NoReportTask",
348+
"sqAnalysis_MultipleReportTasks": "ms-resource:loc.messages.sqAnalysis_MultipleReportTasks",
347349
"codeAnalysisBuildSummaryLine_SomeViolationsSomeFiles": "ms-resource:loc.messages.codeAnalysisBuildSummaryLine_SomeViolationsSomeFiles",
348350
"codeAnalysisBuildSummaryLine_SomeViolationsOneFile": "ms-resource:loc.messages.codeAnalysisBuildSummaryLine_SomeViolationsOneFile",
349351
"codeAnalysisBuildSummaryLine_OneViolationOneFile": "ms-resource:loc.messages.codeAnalysisBuildSummaryLine_OneViolationOneFile",

Tasks/Maven/CodeAnalysis/SonarQube/common.ts

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import Q = require('q');
44
import path = require('path');
5+
import glob = require('glob');
56

67
import {ToolRunner} from 'vsts-task-lib/toolrunner';
78

@@ -40,9 +41,15 @@ export function applySonarQubeParameters(toolRunner: ToolRunner): ToolRunner {
4041
* @param sqBuildFolder
4142
* @returns {Promise<void>} Promise resolved when all SQ integration actions are complete.
4243
*/
43-
export function processSonarQubeIntegration(sqBuildFolder:string):Q.Promise<void> {
44-
var sqRunSettings:SonarQubeRunSettings = getSonarQubeRunSettings(sqBuildFolder);
45-
var sqMetrics:SonarQubeMetrics = getSonarQubeMetrics(sqRunSettings);
44+
export function processSonarQubeIntegration(sqTaskReportGlob: string): Q.Promise<void> {
45+
46+
let sqTaskReportPath: string = findReportTaskFile(sqTaskReportGlob);
47+
if (sqTaskReportPath === null) {
48+
return Q.when();
49+
}
50+
51+
var sqRunSettings: SonarQubeRunSettings = getSonarQubeRunSettings(sqTaskReportPath);
52+
var sqMetrics: SonarQubeMetrics = getSonarQubeMetrics(sqRunSettings);
4653

4754
// Wait for all promises to complete before proceeding (even if one or more promises reject).
4855
return Q.all([
@@ -58,28 +65,46 @@ export function processSonarQubeIntegration(sqBuildFolder:string):Q.Promise<void
5865
* Returns, as an object, the contents of the report-task.txt file created by SonarQube plugins
5966
* The returned object contains the following properties:
6067
* projectKey, serverUrl, dashboardUrl, ceTaskId, ceTaskUrl
61-
* @param sonarPluginFolder The folder created by SonarQube integration during build
68+
* @param sqTaskReportPath Path to the report-task.txt file
6269
* @returns {SonarQubeRunSettings} An object with fields corresponding to the properties exposed in report-task.txt, or null if PR build
6370
*/
64-
function getSonarQubeRunSettings(sonarPluginFolder: string): SonarQubeRunSettings {
71+
function getSonarQubeRunSettings(sqTaskReportPath: string): SonarQubeRunSettings {
6572
if (VstsServerUtils.isPrBuild()) {
6673
return null;
6774
}
6875

69-
var reportFilePath:string = path.join(sonarPluginFolder, 'report-task.txt');
70-
return SonarQubeRunSettings.createRunSettingsFromFile(reportFilePath);
76+
return SonarQubeRunSettings.createRunSettingsFromFile(sqTaskReportPath);
7177
}
7278

7379
/**
7480
* Returns the appropriate SQMetrics object for this build.
7581
* @param sqRunSettings An object with fields corresponding to the properties exposed in report-task.txt
7682
* @returns {SonarQubeMetrics} An SQMetrics instance for this build on the SQ server, or null if PR build
7783
*/
78-
function getSonarQubeMetrics(sqRunSettings:SonarQubeRunSettings): SonarQubeMetrics {
84+
function getSonarQubeMetrics(sqRunSettings: SonarQubeRunSettings): SonarQubeMetrics {
7985
if (VstsServerUtils.isPrBuild()) {
8086
return null;
8187
}
8288

83-
var sqServer:ISonarQubeServer = new SonarQubeServer(SonarQubeEndpoint.getTaskSonarQubeEndpoint());
89+
var sqServer: ISonarQubeServer = new SonarQubeServer(SonarQubeEndpoint.getTaskSonarQubeEndpoint());
8490
return new SonarQubeMetrics(sqServer, sqRunSettings.ceTaskId);
91+
}
92+
93+
function findReportTaskFile(reportTaskGlob: string): string {
94+
95+
// the output folder may not be directly in the build root, for example if the entire project is in a top-lvel dir
96+
let reportTaskGlobResults: string[] = glob.sync(reportTaskGlob);
97+
98+
tl.debug(`[SQ] Searching for ${reportTaskGlob} - found ${reportTaskGlobResults.length} file(s)`);
99+
100+
if (reportTaskGlobResults.length === 0) {
101+
tl.warning(tl.loc('sqAnalysis_NoReportTask'));
102+
return null;
103+
}
104+
105+
if (reportTaskGlobResults.length > 1) {
106+
tl.warning(tl.loc('sqAnalysis_MultipleReportTasks'));
107+
}
108+
109+
return reportTaskGlobResults[0];
85110
}

Tasks/Maven/CodeAnalysis/SonarQube/run-settings.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ export class SonarQubeRunSettings {
1818
* @param ceTaskUrl A string leading to the SonarQube Web API endpoint for the details of this analysis task
1919
*/
2020
constructor(public projectKey: string,
21-
public serverUrl: string,
22-
public dashboardUrl: string,
23-
public ceTaskId: string,
24-
public ceTaskUrl: string) {
21+
public serverUrl: string,
22+
public dashboardUrl: string,
23+
public ceTaskId: string,
24+
public ceTaskUrl: string) {
2525
if (!projectKey) {
2626
// Looks like: Failed to create TaskReport object. Missing field: projectKey
2727
throw new Error(tl.loc('sqCommon_CreateTaskReport_MissingField', 'projectKey'));
@@ -49,8 +49,9 @@ export class SonarQubeRunSettings {
4949
* @param filePath Path to a report-task.txt file generated by a SonarQube build plugin
5050
* @returns {SonarQubeRunSettings} A new SonarQubeRunSettings with appropriate fields filled
5151
*/
52-
public static createRunSettingsFromFile(filePath:string): SonarQubeRunSettings {
53-
if (!tl.exist(filePath)) {
52+
public static createRunSettingsFromFile(filePath: string): SonarQubeRunSettings {
53+
54+
if (!SonarQubeRunSettings.fsExistsSync(filePath)) {
5455
tl.debug('Task report not found at: ' + filePath);
5556
// Looks like: Invalid or missing task report. Check SonarQube finished successfully.
5657
throw new Error(tl.loc('sqAnalysis_TaskReportInvalid'));
@@ -76,19 +77,17 @@ export class SonarQubeRunSettings {
7677
// Looks like: Invalid or missing task report. Check SonarQube finished successfully.
7778
throw new Error(tl.loc('sqAnalysis_TaskReportInvalid'));
7879
}
79-
80-
8180
}
8281

8382
/**
8483
* Transforms a string read of report-task.txt into a key-value map of the run settings.
8584
* @param runSettingsString The contents of report-task.txt as a string
8685
*/
87-
private static createRunSettingsMapFromString(runSettingsString:string):Map<string, string> {
86+
private static createRunSettingsMapFromString(runSettingsString: string): Map<string, string> {
8887
var lines: string[] = runSettingsString.replace(/\r\n/g, '\n').split('\n'); // proofs against xplat line-ending issues
8988

9089
var runSettingsMap = new Map<string, string>();
91-
lines.forEach((line:string) => {
90+
lines.forEach((line: string) => {
9291
var splitLine: string[] = line.split('=');
9392
if (splitLine.length > 1) {
9493
runSettingsMap.set(splitLine[0], splitLine.slice(1, splitLine.length).join());
@@ -97,4 +96,13 @@ export class SonarQubeRunSettings {
9796

9897
return runSettingsMap;
9998
}
99+
100+
private static fsExistsSync(filePath: string): boolean {
101+
try {
102+
fs.accessSync(filePath);
103+
return true;
104+
} catch (e) {
105+
return false;
106+
}
107+
}
100108
}

Tasks/Maven/CodeAnalysis/mavensonar.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import path = require('path');
55
import fs = require('fs');
66
import util = require('util');
77

8+
89
import {ToolRunner} from 'vsts-task-lib/toolrunner';
910
import tl = require('vsts-task-lib/task');
1011

@@ -38,6 +39,8 @@ export function processSonarQubeIntegration(): Q.Promise<void> {
3839
return Q.when();
3940
}
4041

41-
var sqBuildFolder: string = path.join(tl.getVariable('build.sourcesDirectory'), 'target', 'sonar');
42-
return sqCommon.processSonarQubeIntegration(sqBuildFolder);
42+
// the output folder may not be directly in the build root, for example if the entire project is in a top-lvel dir
43+
var reportTaskGlob: string = path.join(tl.getVariable('build.sourcesDirectory'), '**', 'target', 'sonar', 'report-task.txt');
44+
45+
return sqCommon.processSonarQubeIntegration(reportTaskGlob);
4346
}

Tasks/Maven/Strings/resources.resjson/en-US/resources.resjson

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282
"loc.messages.sqAnalysis_QualityGatePassed": "The SonarQube quality gate associated with this build has passed (status %s)",
8383
"loc.messages.sqAnalysis_UnknownComparatorString": "The SonarQube build summary encountered a problem: unknown comparator '%s'",
8484
"loc.messages.sqAnalysis_NoUnitsFound": "The list of SonarQube measurement units could not be retrieved from the server.",
85+
"loc.messages.sqAnalysis_NoReportTask": "Could not find report-task.txt. Possible cause: the SonarQube analysis did not complete successfully.",
86+
"loc.messages.sqAnalysis_MultipleReportTasks": "Multiple report-task.txt files found. Choosing the first one. The build summary and the build breaker may not be accurate. Possible cause: multiple SonarQube analysis during the same build, which is not supported.",
8587
"loc.messages.codeAnalysisBuildSummaryLine_SomeViolationsSomeFiles": "%s found %d violations in %d files.",
8688
"loc.messages.codeAnalysisBuildSummaryLine_SomeViolationsOneFile": "%s found %d violations in 1 file.",
8789
"loc.messages.codeAnalysisBuildSummaryLine_OneViolationOneFile": "%s found 1 violation in 1 file.",

0 commit comments

Comments
 (0)