Skip to content

Commit 10f3b80

Browse files
committed
feat: Improve error handling in API client and enhance report generation logic
1 parent 3c3b8d9 commit 10f3b80

4 files changed

Lines changed: 197 additions & 119 deletions

File tree

pdf-generator/src/main/java/com/ods/GenerateSonarReport.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package com.ods;
22

3-
import java.io.IOException;
43
import java.util.HashMap;
54
import java.util.Map;
65

76
public class GenerateSonarReport {
87

9-
public static void main(String[] args) throws IOException {
8+
public static void main(String[] args) {
109
Map<String, String> params = parseArgs(args);
1110

1211
String sonarUrl = params.get("--sonar-url");
@@ -21,7 +20,13 @@ public static void main(String[] args) throws IOException {
2120
System.exit(1);
2221
}
2322

24-
new ReportBuilder(sonarUrl, token, project, branch).build(output);
23+
try {
24+
new ReportBuilder(sonarUrl, token, project, branch).build(output);
25+
} catch (Exception e) {
26+
System.err.println("ERROR: " + e.getMessage());
27+
e.printStackTrace(System.err);
28+
System.exit(1);
29+
}
2530
}
2631

2732
static Map<String, String> parseArgs(String[] args) {

pdf-generator/src/main/java/com/ods/ReportBuilder.java

Lines changed: 45 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,7 @@ public void build(String outputFile) throws IOException {
7171
}
7272

7373
private void buildIntroductionAndConfiguration() throws IOException {
74-
JSONObject data = null;
75-
try {
76-
data = client.fetchDataFromURL("/api/navigation/component?component=", project);
77-
} catch (IOException | InterruptedException e) {
78-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
79-
}
74+
JSONObject data = client.fetchDataFromURL("/api/navigation/component?component=", project);
8075

8176
String name = data.getString("name");
8277

@@ -111,13 +106,8 @@ private void buildSynthesisSection() throws IOException {
111106
pdf.tittle3Font();
112107
pdf.addLine("ANALYSIS STATUS");
113108

114-
JSONObject data = null;
115-
try {
116-
data = client.fetchDataFromURL("/api/measures/component?metricKeys=reliability_rating,software_quality_maintainability_rating,security_rating,security_review_rating&component=", project);
117-
data = data.getJSONObject("component");
118-
} catch (IOException | InterruptedException e) {
119-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
120-
}
109+
JSONObject data = client.fetchDataFromURL("/api/measures/component?metricKeys=reliability_rating,software_quality_maintainability_rating,security_rating,security_review_rating&component=", project);
110+
data = data.getJSONObject("component");
121111

122112
String[] headers = {"Reliability", "Security", "Security Review", "Maintainability"};
123113
List<String[]> rows = new ArrayList<>();
@@ -133,12 +123,8 @@ private void buildSynthesisSection() throws IOException {
133123
pdf.tittle3Font();
134124
pdf.addLine("QUALITY GATE STATUS");
135125

136-
try {
137-
data = client.fetchDataFromURL("/api/qualitygates/project_status?projectKey=", project);
138-
data = data.getJSONObject("projectStatus");
139-
} catch (IOException | InterruptedException e) {
140-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
141-
}
126+
data = client.fetchDataFromURL("/api/qualitygates/project_status?projectKey=", project);
127+
data = data.getJSONObject("projectStatus");
142128

143129
pdf.bodyFont();
144130
pdf.addLine("| Quality Gate Status | " + data.getString("status") + " |");
@@ -147,12 +133,8 @@ private void buildSynthesisSection() throws IOException {
147133
pdf.tittle3Font();
148134
pdf.addLine("METRICS");
149135

150-
try {
151-
data = client.fetchDataFromURL("/api/measures/component?metricKeys=duplicated_lines_density,comment_lines_density,ncloc,complexity,cognitive_complexity,coverage&component=", project);
152-
data = data.getJSONObject("component");
153-
} catch (IOException | InterruptedException e) {
154-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
155-
}
136+
data = client.fetchDataFromURL("/api/measures/component?metricKeys=duplicated_lines_density,comment_lines_density,ncloc,complexity,cognitive_complexity,coverage&component=", project);
137+
data = data.getJSONObject("component");
156138

157139
headers = new String[]{"Coverage", "Duplications", "Comment Density", "Lines of Code", "Cyclomatic Complexity", "Cognitive Complexity"};
158140
rows = new ArrayList<>();
@@ -187,12 +169,8 @@ private void buildSynthesisSection() throws IOException {
187169
pdf.tittle3Font();
188170
pdf.addLine("TESTS");
189171

190-
try {
191-
data = client.fetchDataFromURL("/api/measures/component?metricKeys=tests,test_success_density,skipped_tests,test_errors,test_failures&component=", project);
192-
data = data.getJSONObject("component");
193-
} catch (IOException | InterruptedException e) {
194-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
195-
}
172+
data = client.fetchDataFromURL("/api/measures/component?metricKeys=tests,test_success_density,skipped_tests,test_errors,test_failures&component=", project);
173+
data = data.getJSONObject("component");
196174

197175
headers = new String[]{"Total", "Success Rate", "Skipped", "Errors", "Failures"};
198176
rows = new ArrayList<>();
@@ -226,12 +204,8 @@ private void buildSynthesisSection() throws IOException {
226204
pdf.tittle3Font();
227205
pdf.addLine("DETAILED TECHNICAL DEBTS");
228206

229-
try {
230-
data = client.fetchDataFromURL("/api/measures/component?metricKeys=reliability_remediation_effort,security_remediation_effort,sqale_index&component=", project);
231-
data = data.getJSONObject("component");
232-
} catch (IOException | InterruptedException e) {
233-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
234-
}
207+
data = client.fetchDataFromURL("/api/measures/component?metricKeys=reliability_remediation_effort,security_remediation_effort,sqale_index&component=", project);
208+
data = data.getJSONObject("component");
235209

236210
headers = new String[]{"Reliability", "Security", "Maintainability", "Total"};
237211
rows = new ArrayList<>();
@@ -266,12 +240,8 @@ private void buildSynthesisSection() throws IOException {
266240
pdf.tittle3Font();
267241
pdf.addLine("LINES PER LANGUAGE");
268242

269-
try {
270-
data = client.fetchDataFromURL("/api/measures/component?metricKeys=ncloc_language_distribution&component=", project);
271-
data = data.getJSONObject("component");
272-
} catch (IOException | InterruptedException e) {
273-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
274-
}
243+
data = client.fetchDataFromURL("/api/measures/component?metricKeys=ncloc_language_distribution&component=", project);
244+
data = data.getJSONObject("component");
275245

276246
headers = new String[]{"Language", "Number of Lines", "Total Percent"};
277247
rows = new ArrayList<>();
@@ -295,14 +265,8 @@ private void buildSecurityHotspotsSection() throws IOException {
295265
pdf.tittle3Font();
296266
pdf.addLine("SECURITY HOTSPOTS COUNT BY CATEGORY AND PRIORITY");
297267

298-
JSONObject data = null;
299-
JSONArray dataArray = null;
300-
try {
301-
data = client.fetchDataFromURL("/api/security_reports/show?standard=sonarsourceSecurity&project=", project);
302-
dataArray = data.getJSONArray("categories");
303-
} catch (IOException | InterruptedException e) {
304-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
305-
}
268+
JSONObject data = client.fetchDataFromURL("/api/security_reports/show?standard=sonarsourceSecurity&project=", project);
269+
JSONArray dataArray = data.getJSONArray("categories");
306270

307271
String[] headers = {"Categories", "Security", "Security Hotspots"};
308272
List<String[]> rows = new ArrayList<>();
@@ -326,26 +290,22 @@ private void buildSecurityHotspotsSection() throws IOException {
326290
pdf.tittle3Font();
327291
pdf.addLine("SECURITY HOTSPOT LIST");
328292

329-
try {
330-
int pageIndex = 1;
331-
int total = Integer.MAX_VALUE;
332-
dataArray = new JSONArray();
333-
while ((pageIndex - 1) * 500 < total) {
334-
data = client.fetchDataFromURL(
335-
String.format("/api/hotspots/search?status=TO_REVIEW&ps=500&pageIndex=%d&project=", pageIndex),
336-
project
337-
);
338-
JSONArray currentPage = data.getJSONArray("hotspots");
339-
for (int i = 0; i < currentPage.length(); i++) {
340-
dataArray.put(currentPage.getJSONObject(i));
341-
}
342-
if (data.has("paging")) {
343-
total = data.getJSONObject("paging").getInt("total");
344-
}
345-
pageIndex++;
293+
int pageIndex = 1;
294+
int total = Integer.MAX_VALUE;
295+
dataArray = new JSONArray();
296+
while ((pageIndex - 1) * 500 < total) {
297+
data = client.fetchDataFromURL(
298+
String.format("/api/hotspots/search?status=TO_REVIEW&ps=500&pageIndex=%d&project=", pageIndex),
299+
project
300+
);
301+
JSONArray currentPage = data.getJSONArray("hotspots");
302+
for (int i = 0; i < currentPage.length(); i++) {
303+
dataArray.put(currentPage.getJSONObject(i));
346304
}
347-
} catch (IOException | InterruptedException e) {
348-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
305+
if (data.has("paging")) {
306+
total = data.getJSONObject("paging").getInt("total");
307+
}
308+
pageIndex++;
349309
}
350310

351311
JSONArray hotspotArray = new JSONArray(groupHotspotsByRule(dataArray).values());
@@ -372,12 +332,7 @@ private void buildIssuesSection() throws IOException {
372332

373333
String[][] typeLabels = {{"BUG", "Bug"}, {"VULNERABILITY", "Vulnerability"}, {"CODE_SMELL", "Code Smell"}};
374334
for (String[] typeLabel : typeLabels) {
375-
JSONObject data = null;
376-
try {
377-
data = client.fetchDataFromURL("/api/issues/search?types=" + typeLabel[0] + "&facets=severities&componentKeys=", project);
378-
} catch (IOException | InterruptedException e) {
379-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
380-
}
335+
JSONObject data = client.fetchDataFromURL("/api/issues/search?types=" + typeLabel[0] + "&facets=severities&componentKeys=", project);
381336
JSONArray facetValues = data.getJSONArray("facets").getJSONObject(0).getJSONArray("values");
382337
rows.add(new String[]{
383338
typeLabel[1],
@@ -395,25 +350,21 @@ private void buildIssuesSection() throws IOException {
395350
pdf.addLine("ISSUES LIST");
396351

397352
JSONArray dataArray = new JSONArray();
398-
try {
399-
int pageIndex = 1;
400-
int total = Integer.MAX_VALUE;
401-
while ((pageIndex - 1) * 500 < total) {
402-
JSONObject data = client.fetchDataFromURL(
403-
String.format("/api/issues/search?issueStatuses=OPEN&ps=500&pageIndex=%d&componentKeys=", pageIndex),
404-
project
405-
);
406-
JSONArray currentPage = data.getJSONArray("issues");
407-
for (int i = 0; i < currentPage.length(); i++) {
408-
dataArray.put(currentPage.getJSONObject(i));
409-
}
410-
if (data.has("paging")) {
411-
total = data.getJSONObject("paging").getInt("total");
412-
}
413-
pageIndex++;
353+
int pageIndex = 1;
354+
int total = Integer.MAX_VALUE;
355+
while ((pageIndex - 1) * 500 < total) {
356+
JSONObject data = client.fetchDataFromURL(
357+
String.format("/api/issues/search?issueStatuses=OPEN&ps=500&pageIndex=%d&componentKeys=", pageIndex),
358+
project
359+
);
360+
JSONArray currentPage = data.getJSONArray("issues");
361+
for (int i = 0; i < currentPage.length(); i++) {
362+
dataArray.put(currentPage.getJSONObject(i));
363+
}
364+
if (data.has("paging")) {
365+
total = data.getJSONObject("paging").getInt("total");
414366
}
415-
} catch (IOException | InterruptedException e) {
416-
System.err.println("Error at doing the HTTP petition: " + e.getMessage());
367+
pageIndex++;
417368
}
418369

419370
JSONArray issuesArray = new JSONArray(groupIssuesByRule(dataArray).values());

pdf-generator/src/main/java/com/ods/SonarApiClient.java

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public void checkServerTrusted(java.security.cert.X509Certificate[] certs, Strin
5959
}
6060
}
6161

62-
public JSONObject fetchDataFromURL(String call, String projectKey) throws IOException, InterruptedException {
62+
public JSONObject fetchDataFromURL(String call, String projectKey) throws IOException {
6363
String encodedProjectKey = URLEncoder.encode(projectKey, StandardCharsets.UTF_8);
6464
String fullURL = String.format("%s%s%s", apiUrl, call, encodedProjectKey);
6565
if (branch != null && !branch.isBlank()) {
@@ -71,13 +71,36 @@ public JSONObject fetchDataFromURL(String call, String projectKey) throws IOExce
7171
.header("Authorization", "Bearer " + authToken)
7272
.build();
7373

74-
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
75-
JSONObject json = new JSONObject(response.body());
74+
HttpResponse<String> response;
75+
try {
76+
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
77+
} catch (InterruptedException e) {
78+
Thread.currentThread().interrupt();
79+
throw new IOException("HTTP request was interrupted: " + fullURL, e);
80+
}
7681

7782
if (response.statusCode() >= 200 && response.statusCode() < 300) {
78-
return json;
83+
return new JSONObject(response.body());
7984
} else {
80-
throw new IOException("Error at obtaining data from the URL: Status Code " + response.statusCode() + ", Body: " + response.body());
85+
String body = response.body();
86+
String detail = extractSonarError(body);
87+
throw new IOException("SonarQube API error (HTTP " + response.statusCode() + ")"
88+
+ (detail != null ? ": " + detail : " — " + body));
8189
}
8290
}
91+
92+
private static String extractSonarError(String body) {
93+
try {
94+
org.json.JSONArray errors = new JSONObject(body).optJSONArray("errors");
95+
if (errors != null && errors.length() > 0) {
96+
StringBuilder sb = new StringBuilder();
97+
for (int i = 0; i < errors.length(); i++) {
98+
if (i > 0) sb.append("; ");
99+
sb.append(errors.getJSONObject(i).optString("msg", "unknown error"));
100+
}
101+
return sb.toString();
102+
}
103+
} catch (Exception ignored) {}
104+
return null;
105+
}
83106
}

0 commit comments

Comments
 (0)