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),

Reply via email to