diff --git a/pom.xml b/pom.xml
index e173bae..4ccc2a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,6 +54,10 @@
io.quarkus
quarkus-smallrye-health
+
+ io.quarkus
+ quarkus-rest-client-reactive-jackson
+
org.glassfish
jakarta.el
diff --git a/src/main/java/io/quarkus/bot/AnalyzeWorkflowRunResults.java b/src/main/java/io/quarkus/bot/AnalyzeWorkflowRunResults.java
index 869ff60..a321266 100644
--- a/src/main/java/io/quarkus/bot/AnalyzeWorkflowRunResults.java
+++ b/src/main/java/io/quarkus/bot/AnalyzeWorkflowRunResults.java
@@ -7,11 +7,12 @@
import java.util.Date;
import java.util.List;
import java.util.Optional;
-import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import javax.inject.Inject;
+import io.quarkus.bot.workflow.ArtifactsAreReady;
+import io.quarkus.bot.workflow.GHWorkflowJobComparator;
import org.apache.commons.lang3.StringUtils;
import org.awaitility.Awaitility;
import org.awaitility.core.ConditionTimeoutException;
@@ -107,7 +108,7 @@ void analyzeWorkflowResults(@WorkflowRun.Completed GHEventPayload.WorkflowRun wo
List surefireReportsArtifacts = artifacts
.stream()
.filter(a -> a.getName().startsWith(WorkflowConstants.BUILD_REPORTS_ARTIFACT_PREFIX))
- .sorted((a1, a2) -> a1.getName().compareTo(a2.getName()))
+ .sorted(Comparator.comparing(GHArtifact::getName))
.collect(Collectors.toList());
List jobs = workflowRun.listJobs().toList()
@@ -115,7 +116,7 @@ void analyzeWorkflowResults(@WorkflowRun.Completed GHEventPayload.WorkflowRun wo
.sorted(GHWorkflowJobComparator.INSTANCE)
.collect(Collectors.toList());
- Optional workflowReportOptional = workflowRunAnalyzer.getReport(workflowRun, pullRequest, jobs,
+ Optional workflowReportOptional = workflowRunAnalyzer.getErrorReport(workflowRun, pullRequest, jobs,
surefireReportsArtifacts);
if (workflowReportOptional.isEmpty()) {
return;
@@ -230,42 +231,4 @@ private Optional createCheckRun(GHWorkflowRun workflowRun, GHPullReq
}
}
- private final static class GHWorkflowJobComparator implements Comparator {
-
- private static final GHWorkflowJobComparator INSTANCE = new GHWorkflowJobComparator();
-
- private static final String INITIAL_JDK_PREFIX = "Initial JDK ";
-
- @Override
- public int compare(GHWorkflowJob o1, GHWorkflowJob o2) {
- if (o1.getName().startsWith(INITIAL_JDK_PREFIX) && !o2.getName().startsWith(INITIAL_JDK_PREFIX)) {
- return -1;
- }
- if (!o1.getName().startsWith(INITIAL_JDK_PREFIX) && o2.getName().startsWith(INITIAL_JDK_PREFIX)) {
- return 1;
- }
-
- return o1.getName().compareTo(o2.getName());
- }
-
- }
-
- private final static class ArtifactsAreReady implements Callable {
- private final GHWorkflowRun workflowRun;
- private List artifacts;
-
- private ArtifactsAreReady(GHWorkflowRun workflowRun) {
- this.workflowRun = workflowRun;
- }
-
- @Override
- public Boolean call() throws Exception {
- artifacts = workflowRun.listArtifacts().toList();
- return !artifacts.isEmpty();
- }
-
- public List getArtifacts() {
- return artifacts;
- }
- }
}
diff --git a/src/main/java/io/quarkus/bot/PushTestResults.java b/src/main/java/io/quarkus/bot/PushTestResults.java
new file mode 100644
index 0000000..f99e4e6
--- /dev/null
+++ b/src/main/java/io/quarkus/bot/PushTestResults.java
@@ -0,0 +1,233 @@
+package io.quarkus.bot;
+
+import io.quarkiverse.githubapp.event.WorkflowRun;
+import io.quarkus.bot.config.QuarkusBotConfig;
+import io.quarkus.bot.test.JobResult;
+import io.quarkus.bot.test.QuarkusStatusClient;
+import io.quarkus.bot.test.TestResult;
+import io.quarkus.bot.test.WorkflowResult;
+import io.quarkus.bot.workflow.ArtifactsAreReady;
+import io.quarkus.bot.workflow.GHWorkflowJobComparator;
+import io.quarkus.bot.workflow.StackTraceUtils;
+import io.quarkus.bot.workflow.WorkflowConstants;
+import io.quarkus.bot.workflow.WorkflowReportFormatter;
+import io.quarkus.bot.workflow.WorkflowRunAnalyzer;
+import io.quarkus.bot.workflow.report.WorkflowReport;
+import io.quarkus.bot.workflow.report.WorkflowReportJob;
+import io.quarkus.bot.workflow.report.WorkflowReportModule;
+import io.quarkus.bot.workflow.report.WorkflowReportTestCase;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.plugins.surefire.report.ReportTestCase;
+import org.apache.maven.plugins.surefire.report.ReportTestSuite;
+import org.awaitility.Awaitility;
+import org.awaitility.core.ConditionTimeoutException;
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+import org.jboss.logging.Logger;
+import org.kohsuke.github.GHArtifact;
+import org.kohsuke.github.GHCheckRun;
+import org.kohsuke.github.GHCheckRun.AnnotationLevel;
+import org.kohsuke.github.GHCheckRunBuilder;
+import org.kohsuke.github.GHCheckRunBuilder.Annotation;
+import org.kohsuke.github.GHCheckRunBuilder.Output;
+import org.kohsuke.github.GHEvent;
+import org.kohsuke.github.GHEventPayload;
+import org.kohsuke.github.GHIssueState;
+import org.kohsuke.github.GHPullRequest;
+import org.kohsuke.github.GHWorkflow;
+import org.kohsuke.github.GHWorkflowJob;
+import org.kohsuke.github.GHWorkflowRun;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import java.io.IOException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@ApplicationScoped
+public class PushTestResults {
+
+ private static final Logger LOG = Logger.getLogger(PushTestResults.class);
+
+ private static final int GITHUB_FIELD_LENGTH_HARD_LIMIT = 65000;
+
+ @Inject
+ WorkflowRunAnalyzer workflowRunAnalyzer;
+
+ @Inject
+ WorkflowReportFormatter workflowReportFormatter;
+
+ @Inject
+ QuarkusBotConfig quarkusBotConfig;
+
+ @RestClient
+ QuarkusStatusClient quarkusStatusClient;
+
+ void analyzeWorkflowResults(@WorkflowRun.Completed GHEventPayload.WorkflowRun workflowRunPayload)
+ throws IOException {
+ GHWorkflowRun workflowRun = workflowRunPayload.getWorkflowRun();
+ GHWorkflow workflow = workflowRunPayload.getWorkflow();
+
+ if (!WorkflowConstants.QUARKUS_CI_WORKFLOW_NAME.equals(workflow.getName())) {
+ return;
+ }
+ if (workflowRun.getEvent() != GHEvent.PULL_REQUEST) {
+ return;
+ }
+
+ List artifacts;
+ try {
+ ArtifactsAreReady artifactsAreReady = new ArtifactsAreReady(workflowRun);
+ Awaitility.await()
+ .atMost(Duration.ofMinutes(5))
+ .pollDelay(Duration.ofSeconds(5))
+ .pollInterval(Duration.ofSeconds(30))
+ .ignoreExceptions()
+ .until(artifactsAreReady);
+ artifacts = artifactsAreReady.getArtifacts();
+ } catch (ConditionTimeoutException e) {
+ LOG.warn("Workflow run #" + workflowRun.getId()
+ + " - Unable to get the artifacts in a timely manner, ignoring them");
+ return;
+ }
+
+ Optional pullRequestOptional = getAssociatedPullRequest(workflowRun, artifacts);
+ if (pullRequestOptional.isEmpty()) {
+ LOG.error("Workflow run #" + workflowRun.getId() + " - Unable to find the associated pull request");
+ return;
+ }
+ GHPullRequest pullRequest = pullRequestOptional.get();
+
+ HideOutdatedWorkflowRunResults.hideOutdatedWorkflowRunResults(quarkusBotConfig, pullRequest);
+
+ if (pullRequest.isDraft()) {
+ return;
+ }
+
+ List surefireReportsArtifacts = artifacts
+ .stream()
+ .filter(a -> a.getName().startsWith(WorkflowConstants.BUILD_REPORTS_ARTIFACT_PREFIX))
+ .sorted((a1, a2) -> a1.getName().compareTo(a2.getName()))
+ .collect(Collectors.toList());
+
+ List jobs = workflowRun.listJobs().toList()
+ .stream()
+ .sorted(GHWorkflowJobComparator.INSTANCE)
+ .collect(Collectors.toList());
+
+ Optional workflowReportOptional = workflowRunAnalyzer.getTestReport(workflowRun, pullRequest, jobs,
+ surefireReportsArtifacts);
+ if (workflowReportOptional.isEmpty()) {
+ return; // the reason was logged by workflowRunAnalyzer
+ }
+ WorkflowReport workflowReport = workflowReportOptional.get();
+
+ List jobResults = new ArrayList<>();
+ for (WorkflowReportJob job : workflowReport.getJobs()) {
+ List testResults = new ArrayList<>();
+ for (WorkflowReportModule module : job.getModules()) {
+ for (ReportTestSuite reportTestSuite : module.getReportTestSuites()) {
+ for (ReportTestCase testCase : reportTestSuite.getTestCases()) {
+ if (!testCase.hasSkipped()) {
+ String testFullName = testCase.getFullName();
+ TestResult result = new TestResult(testFullName, testCase.isSuccessful());
+ testResults.add(result);
+ }
+ }
+ }
+ }
+ jobResults.add(new JobResult(job.getUrl(), job.getName(), testResults, job.getCompletedAt()));
+ }
+
+ quarkusStatusClient.storeTestResults(new WorkflowResult(jobResults, workflowReport.getSha()));
+ }
+
+ /**
+ * Unfortunately when the pull request is coming from a fork, the pull request is not in the payload
+ * so we use a dirty trick to get it.
+ * We use the sha as last resort as the workflow takes some time and the sha might not be associated to the pull request
+ * anymore.
+ */
+ private Optional getAssociatedPullRequest(GHWorkflowRun workflowRun, List artifacts)
+ throws NumberFormatException, IOException {
+ Optional pullRequestNumberArtifact = artifacts.stream()
+ .filter(a -> a.getName().startsWith(WorkflowConstants.PULL_REQUEST_NUMBER_PREFIX)).findFirst();
+ if (!pullRequestNumberArtifact.isEmpty()) {
+ GHPullRequest pullRequest = workflowRun.getRepository().getPullRequest(
+ Integer.valueOf(
+ pullRequestNumberArtifact.get().getName().replace(WorkflowConstants.PULL_REQUEST_NUMBER_PREFIX,
+ "")));
+ return Optional.of(pullRequest);
+ }
+
+ LOG.warn("Workflow run #" + workflowRun.getId() + " - Unable to get the pull request artifact, trying with sha");
+
+ List pullRequests = workflowRun.getRepository().queryPullRequests()
+ .state(GHIssueState.OPEN)
+ .head(workflowRun.getHeadRepository().getOwnerName() + ":" + workflowRun.getHeadBranch())
+ .list().toList();
+ if (!pullRequests.isEmpty()) {
+ return Optional.of(pullRequests.get(0));
+ }
+
+ return Optional.empty();
+ }
+
+ private Optional createCheckRun(GHWorkflowRun workflowRun, GHPullRequest pullRequest,
+ boolean artifactsAvailable, WorkflowReport workflowReport) {
+ if (!workflowReport.hasTestFailures() || quarkusBotConfig.isDryRun()) {
+ return Optional.empty();
+ }
+
+ try {
+ String name = "Build summary for " + workflowRun.getHeadSha();
+ String summary = workflowReportFormatter.getCheckRunReportSummary(workflowReport, pullRequest, artifactsAvailable);
+ String checkRunReport = workflowReportFormatter.getCheckRunReport(workflowReport, true);
+ if (checkRunReport.length() > GITHUB_FIELD_LENGTH_HARD_LIMIT) {
+ checkRunReport = workflowReportFormatter.getCheckRunReport(workflowReport, false);
+ }
+
+ Output checkRunOutput = new Output(name, summary).withText(checkRunReport);
+
+ for (WorkflowReportJob workflowReportJob : workflowReport.getJobs()) {
+ if (!workflowReportJob.hasTestFailures()) {
+ continue;
+ }
+
+ List annotatedWorkflowReportTestCases = workflowReportJob.getModules().stream()
+ .filter(m -> m.hasTestFailures())
+ .flatMap(m -> m.getTestFailures().stream())
+ .collect(Collectors.toList());
+
+ for (WorkflowReportTestCase workflowReportTestCase : annotatedWorkflowReportTestCases) {
+ checkRunOutput.add(new Annotation(workflowReportTestCase.getClassPath(),
+ StringUtils.isNumeric(workflowReportTestCase.getFailureErrorLine())
+ ? Integer.valueOf(workflowReportTestCase.getFailureErrorLine())
+ : 1,
+ AnnotationLevel.FAILURE,
+ StringUtils.isNotBlank(workflowReportTestCase.getFailureDetail()) ? StackTraceUtils
+ .firstLines(StackTraceUtils.abbreviate(workflowReportTestCase.getFailureDetail(),
+ GITHUB_FIELD_LENGTH_HARD_LIMIT), 3)
+ : "The test failed.")
+ .withTitle(StringUtils.abbreviate(workflowReportJob.getName(), 255))
+ .withRawDetails(
+ StackTraceUtils.abbreviate(workflowReportTestCase.getFailureDetail(),
+ GITHUB_FIELD_LENGTH_HARD_LIMIT)));
+ }
+ }
+
+ GHCheckRunBuilder checkRunBuilder = workflowRun.getRepository().createCheckRun(name, workflowRun.getHeadSha())
+ .add(checkRunOutput)
+ .withConclusion(GHCheckRun.Conclusion.NEUTRAL)
+ .withCompletedAt(new Date());
+
+ return Optional.of(checkRunBuilder.create());
+ } catch (Exception e) {
+ LOG.error("Pull request #" + pullRequest.getNumber() + " - Unable to create check run for test failures", e);
+ return Optional.empty();
+ }
+ }
+}
diff --git a/src/main/java/io/quarkus/bot/test/JobResult.java b/src/main/java/io/quarkus/bot/test/JobResult.java
new file mode 100644
index 0000000..d0b6449
--- /dev/null
+++ b/src/main/java/io/quarkus/bot/test/JobResult.java
@@ -0,0 +1,35 @@
+package io.quarkus.bot.test;
+
+import java.util.Date;
+import java.util.List;
+
+public class JobResult {
+ private String jobUrl;
+ private String jobName;
+ private Date completedAt;
+
+ private List tests;
+
+ public JobResult(String jobUrl, String jobName, List tests, Date completedAt) {
+ this.jobUrl = jobUrl;
+ this.jobName = jobName;
+ this.tests = tests;
+ this.completedAt = completedAt;
+ }
+
+ public String getJobUrl() {
+ return jobUrl;
+ }
+
+ public String getJobName() {
+ return jobName;
+ }
+
+ public List getTests() {
+ return tests;
+ }
+
+ public Date getCompletedAt() {
+ return completedAt;
+ }
+}
diff --git a/src/main/java/io/quarkus/bot/test/QuarkusStatusClient.java b/src/main/java/io/quarkus/bot/test/QuarkusStatusClient.java
new file mode 100644
index 0000000..c3bc787
--- /dev/null
+++ b/src/main/java/io/quarkus/bot/test/QuarkusStatusClient.java
@@ -0,0 +1,27 @@
+package io.quarkus.bot.test;
+
+import org.eclipse.microprofile.config.ConfigProvider;
+import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam;
+import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
+
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+@Path("/")
+@RegisterRestClient(configKey = "quarkus-status")
+public interface QuarkusStatusClient {
+ @POST
+ @Path("/test-results")
+ @ClientHeaderParam(name = "Authorization", value = "{basicAuthString}")
+ Response storeTestResults(WorkflowResult results);
+
+ default String basicAuthString() {
+ String auth = ConfigProvider.getConfig()
+ .getOptionalValue("quarkus.status.auth-string", String.class)
+ .orElseThrow(() -> new IllegalStateException("No authorization string provided for quarkus-status client." +
+ " Please set `quarkus.status.auth-string` to the " +
+ "auth string to communicate with the quarkus-status application."));
+ return String.format("Basic %s", auth);
+ }
+}
diff --git a/src/main/java/io/quarkus/bot/test/TestResult.java b/src/main/java/io/quarkus/bot/test/TestResult.java
new file mode 100644
index 0000000..2046c07
--- /dev/null
+++ b/src/main/java/io/quarkus/bot/test/TestResult.java
@@ -0,0 +1,19 @@
+package io.quarkus.bot.test;
+
+public class TestResult {
+ private String name;
+ private boolean successful;
+
+ public TestResult(String name, boolean successful) {
+ this.name = name;
+ this.successful = successful;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isSuccessful() {
+ return successful;
+ }
+}
diff --git a/src/main/java/io/quarkus/bot/test/WorkflowResult.java b/src/main/java/io/quarkus/bot/test/WorkflowResult.java
new file mode 100644
index 0000000..ec77435
--- /dev/null
+++ b/src/main/java/io/quarkus/bot/test/WorkflowResult.java
@@ -0,0 +1,24 @@
+package io.quarkus.bot.test;
+
+import java.util.List;
+
+public class WorkflowResult {
+ private String sha;
+ private List jobs;
+
+ public WorkflowResult() {
+ }
+
+ public WorkflowResult(List jobs, String sha) {
+ this.jobs = jobs;
+ this.sha = sha;
+ }
+
+ public List getJobs() {
+ return jobs;
+ }
+
+ public String getSha() {
+ return sha;
+ }
+}
diff --git a/src/main/java/io/quarkus/bot/workflow/ArtifactsAreReady.java b/src/main/java/io/quarkus/bot/workflow/ArtifactsAreReady.java
new file mode 100644
index 0000000..5ef2e55
--- /dev/null
+++ b/src/main/java/io/quarkus/bot/workflow/ArtifactsAreReady.java
@@ -0,0 +1,26 @@
+package io.quarkus.bot.workflow;
+
+import org.kohsuke.github.GHArtifact;
+import org.kohsuke.github.GHWorkflowRun;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+
+public final class ArtifactsAreReady implements Callable {
+ private final GHWorkflowRun workflowRun;
+ private List artifacts;
+
+ public ArtifactsAreReady(GHWorkflowRun workflowRun) {
+ this.workflowRun = workflowRun;
+ }
+
+ @Override
+ public Boolean call() throws Exception {
+ artifacts = workflowRun.listArtifacts().toList();
+ return !artifacts.isEmpty();
+ }
+
+ public List getArtifacts() {
+ return artifacts;
+ }
+}
diff --git a/src/main/java/io/quarkus/bot/workflow/GHWorkflowJobComparator.java b/src/main/java/io/quarkus/bot/workflow/GHWorkflowJobComparator.java
new file mode 100644
index 0000000..39a968e
--- /dev/null
+++ b/src/main/java/io/quarkus/bot/workflow/GHWorkflowJobComparator.java
@@ -0,0 +1,25 @@
+package io.quarkus.bot.workflow;
+
+import org.kohsuke.github.GHWorkflowJob;
+
+import java.util.Comparator;
+
+public class GHWorkflowJobComparator implements Comparator {
+
+ public static final GHWorkflowJobComparator INSTANCE = new GHWorkflowJobComparator();
+
+ private static final String INITIAL_JDK_PREFIX = "Initial JDK ";
+
+ @Override
+ public int compare(GHWorkflowJob o1, GHWorkflowJob o2) {
+ if (o1.getName().startsWith(INITIAL_JDK_PREFIX) && !o2.getName().startsWith(INITIAL_JDK_PREFIX)) {
+ return -1;
+ }
+ if (!o1.getName().startsWith(INITIAL_JDK_PREFIX) && o2.getName().startsWith(INITIAL_JDK_PREFIX)) {
+ return 1;
+ }
+
+ return o1.getName().compareTo(o2.getName());
+ }
+
+}
diff --git a/src/main/java/io/quarkus/bot/workflow/WorkflowRunAnalyzer.java b/src/main/java/io/quarkus/bot/workflow/WorkflowRunAnalyzer.java
index a3f4187..1f6e04b 100644
--- a/src/main/java/io/quarkus/bot/workflow/WorkflowRunAnalyzer.java
+++ b/src/main/java/io/quarkus/bot/workflow/WorkflowRunAnalyzer.java
@@ -61,7 +61,87 @@ public class WorkflowRunAnalyzer {
@Inject
UrlShortener urlShortener;
- public Optional getReport(GHWorkflowRun workflowRun,
+ public Optional getTestReport(GHWorkflowRun workflowRun,
+ GHPullRequest pullRequest,
+ List jobs,
+ List buildReportsArtifacts) throws IOException {
+ if (jobs.isEmpty()) {
+ LOG.error("Pull request #" + pullRequest.getNumber() + " - No jobs found");
+ return Optional.empty();
+ }
+
+ GHRepository repository = workflowRun.getRepository();
+ String pullRequestRepositoryName = pullRequest.getHead().getRepository().getFullName();
+ String sha = workflowRun.getHeadSha();
+ Path allBuildReportsDirectory = Files.createTempDirectory("build-reports-analyzer-");
+
+ try {
+ List workflowReportJobs = new ArrayList<>();
+
+ for (GHWorkflowJob job : jobs) {
+ Optional buildReportsArtifactOptional = buildReportsArtifacts.stream()
+ .filter(a -> a.getName().replace(WorkflowConstants.BUILD_REPORTS_ARTIFACT_PREFIX, "")
+ .equals(job.getName()))
+ .findFirst();
+
+ BuildReport buildReport = EMPTY_BUILD_REPORT;
+ List modules = Collections.emptyList();
+ boolean errorDownloadingBuildReports = false;
+ if (buildReportsArtifactOptional.isPresent()) {
+ GHArtifact buildReportsArtifact = buildReportsArtifactOptional.get();
+ Path jobDirectory = allBuildReportsDirectory.resolve(buildReportsArtifact.getName());
+ try {
+ BuildReports buildReports = buildReportsUnarchiver.getBuildReports(buildReportsArtifact, jobDirectory);
+
+ if (buildReports.getBuildReportPath() != null) {
+ buildReport = getBuildReport(pullRequest, buildReports.getBuildReportPath());
+ }
+
+ modules = getModules(pullRequest, buildReport, jobDirectory, buildReports.getTestResultsPaths(),
+ pullRequestRepositoryName, sha, true);
+ } catch (Exception e) {
+ errorDownloadingBuildReports = true;
+ LOG.error("Pull request #" + pullRequest.getNumber() + " - Unable to analyze build report for artifact "
+ + buildReportsArtifact.getName(), e);
+ }
+ }
+
+ workflowReportJobs.add(new WorkflowReportJob(job.getName(),
+ getFailuresAnchor(job.getId()),
+ job.getConclusion(),
+ getFailingStep(job.getSteps()),
+ getJobUrl(job),
+ getRawLogsUrl(job, workflowRun.getHeadSha()),
+ buildReport,
+ modules,
+ errorDownloadingBuildReports,
+ job.getCompletedAt()));
+ }
+
+ if (workflowReportJobs.isEmpty()) {
+ LOG.warn("Pull request #" + pullRequest.getNumber() + " - Report jobs empty");
+ return Optional.empty();
+ }
+
+ WorkflowReport report = new WorkflowReport(sha, workflowReportJobs,
+ repository.getFullName().equals(pullRequestRepositoryName),
+ workflowRun.getConclusion(), workflowRun.getHtmlUrl().toString());
+
+ return Optional.of(report);
+ } finally {
+ try {
+ Files.walk(allBuildReportsDirectory)
+ .sorted(Comparator.reverseOrder())
+ .map(Path::toFile)
+ .forEach(File::delete);
+ } catch (IOException e) {
+ LOG.error("Pull request #" + pullRequest.getNumber() + " - Unable to delete temp directory "
+ + allBuildReportsDirectory);
+ }
+ }
+ }
+
+ public Optional getErrorReport(GHWorkflowRun workflowRun,
GHPullRequest pullRequest,
List jobs,
List buildReportsArtifacts) throws IOException {
@@ -81,7 +161,7 @@ public Optional getReport(GHWorkflowRun workflowRun,
for (GHWorkflowJob job : jobs) {
if (job.getConclusion() != Conclusion.FAILURE && job.getConclusion() != Conclusion.CANCELLED) {
workflowReportJobs.add(new WorkflowReportJob(job.getName(), null, job.getConclusion(), null, null, null,
- EMPTY_BUILD_REPORT, Collections.emptyList(), false));
+ EMPTY_BUILD_REPORT, Collections.emptyList(), false, job.getCompletedAt()));
continue;
}
@@ -103,10 +183,8 @@ public Optional getReport(GHWorkflowRun workflowRun,
buildReport = getBuildReport(pullRequest, buildReports.getBuildReportPath());
}
- modules = buildReportsArtifactOptional.isPresent()
- ? getModules(pullRequest, buildReport, jobDirectory, buildReports.getTestResultsPaths(),
- pullRequestRepositoryName, sha)
- : Collections.emptyList();
+ modules = getModules(pullRequest, buildReport, jobDirectory, buildReports.getTestResultsPaths(),
+ pullRequestRepositoryName, sha, false);
} catch (Exception e) {
errorDownloadingBuildReports = true;
LOG.error("Pull request #" + pullRequest.getNumber() + " - Unable to analyze build report for artifact "
@@ -122,7 +200,8 @@ public Optional getReport(GHWorkflowRun workflowRun,
getRawLogsUrl(job, workflowRun.getHeadSha()),
buildReport,
modules,
- errorDownloadingBuildReports));
+ errorDownloadingBuildReports,
+ job.getCompletedAt()));
}
if (workflowReportJobs.isEmpty()) {
@@ -167,7 +246,7 @@ private List getModules(GHPullRequest pullRequest,
Path jobDirectory,
Set testResultsPaths,
String pullRequestRepository,
- String sha) {
+ String sha, boolean keepSuccess) {
List modules = new ArrayList<>();
Map moduleReportsMap = mapModuleReports(buildReport, testResultsPaths, jobDirectory);
@@ -205,7 +284,7 @@ private List getModules(GHPullRequest pullRequest,
reportTestSuites,
workflowReportTestCases);
- if (module.hasReportedFailures()) {
+ if (keepSuccess || module.hasReportedFailures()) {
modules.add(module);
}
}
diff --git a/src/main/java/io/quarkus/bot/workflow/report/WorkflowReportJob.java b/src/main/java/io/quarkus/bot/workflow/report/WorkflowReportJob.java
index 116b73f..fbf99d8 100644
--- a/src/main/java/io/quarkus/bot/workflow/report/WorkflowReportJob.java
+++ b/src/main/java/io/quarkus/bot/workflow/report/WorkflowReportJob.java
@@ -1,5 +1,6 @@
package io.quarkus.bot.workflow.report;
+import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
@@ -25,10 +26,11 @@ public class WorkflowReportJob {
private final List skippedModules;
private final List modules;
private final boolean errorDownloadingSurefireReports;
+ private final Date completedAt;
public WorkflowReportJob(String name, String failuresAnchor, Conclusion conclusion, String failingStep, String url,
String rawLogsUrl, BuildReport buildReport, List modules,
- boolean errorDownloadingSurefireReports) {
+ boolean errorDownloadingSurefireReports, Date completedAt) {
this.name = name;
this.failuresAnchor = failuresAnchor;
this.conclusion = conclusion;
@@ -47,6 +49,7 @@ public WorkflowReportJob(String name, String failuresAnchor, Conclusion conclusi
.collect(Collectors.toList());
this.modules = modules;
this.errorDownloadingSurefireReports = errorDownloadingSurefireReports;
+ this.completedAt = completedAt;
}
public String getName() {
@@ -61,6 +64,10 @@ public Conclusion getConclusion() {
return conclusion;
}
+ public Date getCompletedAt() {
+ return completedAt;
+ }
+
public String getConclusionEmoji() {
// apparently, conclusion can sometimes be null...
if (conclusion == null) {
diff --git a/src/main/java/io/quarkus/bot/workflow/report/WorkflowReportModule.java b/src/main/java/io/quarkus/bot/workflow/report/WorkflowReportModule.java
index c10713e..5025304 100644
--- a/src/main/java/io/quarkus/bot/workflow/report/WorkflowReportModule.java
+++ b/src/main/java/io/quarkus/bot/workflow/report/WorkflowReportModule.java
@@ -51,6 +51,10 @@ public List getTestFailures() {
return failures;
}
+ public List getReportTestSuites() {
+ return reportTestSuites;
+ }
+
public int getTestCount() {
int testCount = 0;
for (ReportTestSuite reportTestSuite : reportTestSuites) {
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 4dd85ba..720f6bc 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -5,6 +5,8 @@ quarkus.live-reload.instrumentation=false
quarkus.qute.suffixes=md
quarkus.qute.content-types."md"=text/markdown
+%dev.quarkus-status/mp-rest/url=http://localhost:8282
+
quarkus.openshift.labels."app"=quarkus-bot
quarkus.openshift.annotations."kubernetes.io/tls-acme"=true
quarkus.openshift.env.vars.QUARKUS_GITHUB_APP_APP_ID=90234
@@ -13,6 +15,8 @@ quarkus.openshift.env.vars.QUARKUS_GITHUB_APP_APP_NAME=quarkus-bot
quarkus.openshift.env.secrets=quarkus-bot
%dev.quarkus-bot.dry-run=true
+# quarkus-bot:123 basic auth for the dev and test mode:
+%dev.quarkus.status.auth-string=cXVhcmt1c2JvdDoxMjMK
%test.quarkus-bot.dry-run=false
%test.quarkus.github-app.app-id=0