This is an automated email from the ASF dual-hosted git repository. olamy pushed a commit to branch use_json_jenkins_api in repository https://gitbox.apache.org/repos/asf/maven-dist-tool.git
commit c64d172878e1cb03ddb76c5223a98e3e67987dc6 Author: Olivier Lamy <[email protected]> AuthorDate: Sun Mar 15 11:41:38 2026 +1000 Use Json data for ListMasterJobsReport Signed-off-by: Olivier Lamy <[email protected]> --- pom.xml | 11 ++-- .../org/apache/maven/dist/tools/JsonRetry.java | 58 ++++++++++++++++++++ .../tools/jobs/master/ListMasterJobsReport.java | 61 ++++++++++++--------- .../committers/MavenCommittersRepositoryTest.java | 63 ++++++++++++++++------ 4 files changed, 149 insertions(+), 44 deletions(-) diff --git a/pom.xml b/pom.xml index cebeb27..985eabd 100644 --- a/pom.xml +++ b/pom.xml @@ -159,6 +159,11 @@ <artifactId>org.eclipse.jgit</artifactId> <version>7.5.0.202512021534-r</version> </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-client</artifactId> + <version>12.1.7</version> + </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> @@ -187,9 +192,9 @@ <scope>test</scope> </dependency> <dependency> - <groupId>org.wiremock</groupId> - <artifactId>wiremock</artifactId> - <version>3.13.2</version> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>12.1.7</version> <scope>test</scope> </dependency> <dependency> diff --git a/src/main/java/org/apache/maven/dist/tools/JsonRetry.java b/src/main/java/org/apache/maven/dist/tools/JsonRetry.java new file mode 100644 index 0000000..9f7abae --- /dev/null +++ b/src/main/java/org/apache/maven/dist/tools/JsonRetry.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.dist.tools; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.Request; + +public class JsonRetry { + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + private HttpClient httpClient = new HttpClient(); + + private JsonRetry() { + try { + this.httpClient.start(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static class JsonRetryHolder { + private static final JsonRetry INSTANCE = new JsonRetry(); + } + + public static JsonRetry getInstance() { + return JsonRetryHolder.INSTANCE; + } + + public static JsonNode get(String url) throws Exception { + Request request = getInstance().httpClient.newRequest(url); + String apiToken = System.getenv("API_TOKEN"); + if (StringUtils.isNotBlank(apiToken)) { + request.headers(httpFields -> httpFields.add("Authorization", "Basic " + apiToken)); + } + String json = request.send().getContentAsString(); + return json != null ? OBJECT_MAPPER.readTree(json) : null; + } +} diff --git a/src/main/java/org/apache/maven/dist/tools/jobs/master/ListMasterJobsReport.java b/src/main/java/org/apache/maven/dist/tools/jobs/master/ListMasterJobsReport.java index c53cc30..bd62f19 100644 --- a/src/main/java/org/apache/maven/dist/tools/jobs/master/ListMasterJobsReport.java +++ b/src/main/java/org/apache/maven/dist/tools/jobs/master/ListMasterJobsReport.java @@ -18,7 +18,6 @@ */ package org.apache.maven.dist.tools.jobs.master; -import java.io.IOException; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -30,13 +29,13 @@ import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; -import org.apache.maven.dist.tools.JsoupRetry; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.maven.dist.tools.JsonRetry; import org.apache.maven.dist.tools.jobs.AbstractJobsReport; import org.apache.maven.doxia.sink.Sink; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.reporting.MavenReportException; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; /** * Generate report with build status of the Jenkins job for the master branch of every Git repository in @@ -82,33 +81,43 @@ public class ListMasterJobsReport extends AbstractJobsReport { final String repositoryJobUrl = MAVENBOX_JOBS_BASE_URL + repository; try { - Document doc = JsoupRetry.get(repositoryJobUrl); - Result result = new Result(repository, repositoryJobUrl); - - Element masterRow = doc.getElementById("job_master"); - if (masterRow == null) { - getLog().warn(MAVENBOX_JOBS_BASE_URL + repository + " is missing id job_master"); + JsonNode jsonNode = JsonRetry.get( + repositoryJobUrl + "/api/json?tree=jobs[name,url,color,lastBuild[result,number]]"); + if (jsonNode == null) { + getLog().warn("Failed to read JSON for " + repository + " Jenkins job " + repositoryJobUrl); continue; - } else if (masterRow.hasClass("job-status-red") || masterRow.hasClass("job-status-red-anime")) { - result.setStatus("FAILURE"); - } else if (masterRow.hasClass("job-status-yellow") || masterRow.hasClass("job-status-yellow-anime")) { - result.setStatus("UNSTABLE"); - } else if (masterRow.hasClass("job-status-blue") || masterRow.hasClass("job-status-blue-anime")) { - result.setStatus("SUCCESS"); - } else { - result.setStatus("UNKNOWN"); } - result.setIcon(masterRow - .select("span.build-status-icon__wrapper") - .first() - .outerHtml()); - result.setLastBuild(getLastBuild( - masterRow.child(3).attr("data"), masterRow.child(4).attr("data"))); + // find the master node + if (jsonNode instanceof ObjectNode objectNode) { + objectNode + .get("jobs") + .valueStream() + .filter(jsonNode1 -> jsonNode1.get("name").asText().equals("master")) + .findFirst() + .ifPresent(jsonNode1 -> { + JsonNode lastBuild = jsonNode1.get("lastBuild"); + String status = "UNKNOWN"; + if (lastBuild != null) { + status = lastBuild.get("result").asText(); + } + + String buildUrl = jsonNode1.get("url").asText() + + jsonNode1 + .get("lastBuild") + .get("number") + .asText(); + Result result = new Result(repository, buildUrl); + result.setStatus(status); + // https://ci-maven.apache.org/static/67d6365a/images/24x24/blue.png + result.setIcon("https://ci-maven.apache.org/static/48x48/" + + jsonNode1.get("color").asText().toLowerCase() + ".png"); + repoStatus.add(result); + }); + } - repoStatus.add(result); - } catch (IOException e) { + } catch (Exception e) { getLog().warn("Failed to read status for " + repository + " Jenkins job " + repositoryJobUrl); } } diff --git a/src/test/java/org/apache/maven/dist/tools/committers/MavenCommittersRepositoryTest.java b/src/test/java/org/apache/maven/dist/tools/committers/MavenCommittersRepositoryTest.java index 0e81d28..65afa5f 100644 --- a/src/test/java/org/apache/maven/dist/tools/committers/MavenCommittersRepositoryTest.java +++ b/src/test/java/org/apache/maven/dist/tools/committers/MavenCommittersRepositoryTest.java @@ -18,19 +18,24 @@ */ package org.apache.maven.dist.tools.committers; +import java.net.InetSocketAddress; import java.util.List; -import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; -import com.github.tomakehurst.wiremock.junit5.WireMockTest; import org.apache.maven.dist.tools.committers.MavenCommittersRepository.Committer; +import org.eclipse.jetty.http.HttpHeader; +import org.eclipse.jetty.io.Content; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.util.Callback; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static org.assertj.core.api.Assertions.assertThat; -@WireMockTest class MavenCommittersRepositoryTest { private static final String GROUP = """ @@ -63,17 +68,45 @@ class MavenCommittersRepositoryTest { } """; - @Test - void dataLoad(WireMockRuntimeInfo wireMockRuntimeInfo) { + private Server server; + private String baseUrl; + + @BeforeEach + void startServer() throws Exception { + server = new Server(new InetSocketAddress("localhost", 0)); + server.setHandler(new Handler.Abstract() { + @Override + public boolean handle(Request request, Response response, Callback callback) throws Exception { + String path = request.getHttpURI().getPath(); + String body; + if ("/json/foundation/groups.json".equals(path)) { + body = GROUP; + } else if ("/json/foundation/people_name.json".equals(path)) { + body = NAMES; + } else { + Response.writeError(request, response, callback, 404); + return true; + } + response.setStatus(200); + response.getHeaders().put(HttpHeader.CONTENT_TYPE, "application/json"); + Content.Sink.write(response, true, body, callback); + return true; + } + }); + server.start(); + int port = ((ServerConnector) server.getConnectors()[0]).getLocalPort(); + baseUrl = "http://localhost:" + port; + } - stubFor(get("/json/foundation/groups.json") - .willReturn(aResponse().withStatus(200).withBody(GROUP))); - stubFor(get("/json/foundation/people_name.json") - .willReturn(aResponse().withStatus(200).withBody(NAMES))); + @AfterEach + void stopServer() throws Exception { + server.stop(); + } - MavenCommittersRepository mavenCommittersRepository = - new MavenCommittersRepository(wireMockRuntimeInfo.getHttpBaseUrl()); - assertThat(mavenCommittersRepository.getCommitters()) + @Test + void dataLoad() { + MavenCommittersRepository repo = new MavenCommittersRepository(baseUrl); + assertThat(repo.getCommitters()) .containsExactly( new Committer("cstamas", List.of("Tamas Cservenak", "Tamás Cservenák"), true), new Committer("m1", List.of("M1 name"), false),
