diff --git a/pom.xml b/pom.xml
index 53c2312..bf6b219 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,10 @@
io.quarkus
quarkus-jackson
+
+ org.awaitility
+ awaitility
+
io.quarkus
quarkus-junit5
diff --git a/src/main/java/io/quarkus/bot/develocity/InjectBuildScansAction.java b/src/main/java/io/quarkus/bot/develocity/InjectBuildScansAction.java
index 8c3521d..a7084a7 100644
--- a/src/main/java/io/quarkus/bot/develocity/InjectBuildScansAction.java
+++ b/src/main/java/io/quarkus/bot/develocity/InjectBuildScansAction.java
@@ -3,6 +3,7 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.time.Duration;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -11,10 +12,13 @@
import java.util.Optional;
import java.util.OptionalLong;
import java.util.TreeSet;
+import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import jakarta.inject.Inject;
+import org.awaitility.Awaitility;
+import org.awaitility.core.ConditionTimeoutException;
import org.kohsuke.github.GHCheckRun;
import org.kohsuke.github.GHCheckRunBuilder.Output;
import org.kohsuke.github.GHIssueComment;
@@ -33,7 +37,6 @@
public class InjectBuildScansAction {
- private static final String BUILD_SUMMARY_CHECK_RUN_PREFIX = "Build summary for ";
private static final String WORKFLOW_RUN_ID_MARKER = "";
private static final String BUILD_SCANS = "Build scans";
@@ -75,98 +78,123 @@ void injectBuildScans(Context context, Commands commands, Inputs inputs, GitHub
return;
}
+ createBuildScansOutput(commands, workflowRun, statuses);
updateComment(commands, pullRequest, workflowRun, buildScanMapping);
- updateCheckRun(commands, repository, workflowRun, buildScanMapping);
- createBuildScansOutput(workflowRun, statuses);
+
+ // note for future self: it is not possible to update an existing check run created by another GitHub App
} catch (IOException e) {
commands.error("Error trying to attach build scans to pull request #" + statuses.prNumber + ": " + e.getMessage());
}
}
private void updateComment(Commands commands, GHPullRequest pullRequest, GHWorkflowRun workflowRun,
- Map buildScanMapping) throws IOException {
- List commentsSinceWorkflowRunStarted = pullRequest.queryComments()
- .since(workflowRun.getCreatedAt())
- .list().toList();
- Collections.reverse(commentsSinceWorkflowRunStarted);
-
- String workflowRunIdMarker = String.format(WORKFLOW_RUN_ID_MARKER, workflowRun.getId());
- Optional reportCommentCandidate = commentsSinceWorkflowRunStarted.stream()
- .filter(c -> c.getBody().contains(workflowRunIdMarker))
- .findFirst();
-
- if (reportCommentCandidate.isEmpty()) {
- commands.warning("Unable to find a report comment to update");
- return;
- }
+ Map buildScanMapping) {
+ try {
+ Optional reportCommentCandidate = getPullRequestComment(commands, workflowRun, pullRequest);
+
+ if (reportCommentCandidate.isEmpty()) {
+ commands.warning("Unable to find a report comment to update");
+ return;
+ }
- GHIssueComment reportComment = reportCommentCandidate.get();
+ GHIssueComment reportComment = reportCommentCandidate.get();
- String updatedCommentBody = reportComment.getBody().lines().map(line -> {
- for (Entry buildScanEntry : buildScanMapping.entrySet()) {
- if (line.contains("| " + buildScanEntry.getKey() + " |")) {
- return line.replace(":construction:", "[:mag:](" + buildScanEntry.getValue() + ")");
+ String updatedCommentBody = reportComment.getBody().lines().map(line -> {
+ for (Entry buildScanEntry : buildScanMapping.entrySet()) {
+ if (line.contains("| " + buildScanEntry.getKey() + " |")) {
+ return line.replace(":construction:", "[:mag:](" + buildScanEntry.getValue() + ")");
+ }
}
+ return line;
+ }).collect(Collectors.joining("\n"));
+
+ if (!updatedCommentBody.equals(reportComment.getBody())) {
+ reportComment.update(updatedCommentBody);
}
- return line;
- }).collect(Collectors.joining("\n"));
+ } catch (Exception e) {
+ commands.error("Unable to update the PR comment: " + e.getMessage());
+ }
+ }
+
+ private static Optional getPullRequestComment(Commands commands, GHWorkflowRun workflowRun, GHPullRequest pullRequest) {
+ try {
+ PullRequestReportIsCreated pullRequestReportIsCreated = new PullRequestReportIsCreated(workflowRun, pullRequest);
+
+ Awaitility.await()
+ .atMost(Duration.ofMinutes(15))
+ .pollDelay(Duration.ofMinutes(2))
+ .pollInterval(Duration.ofMinutes(3))
+ .until(pullRequestReportIsCreated);
- if (!updatedCommentBody.equals(reportComment.getBody())) {
- reportComment.update(updatedCommentBody);
+ return pullRequestReportIsCreated.getReportComment();
+ } catch (ConditionTimeoutException e) {
+ commands.warning("Unable to find a report comment to update");
+ return Optional.empty();
}
}
- private void updateCheckRun(Commands commands, GHRepository repository, GHWorkflowRun workflowRun,
- Map buildScanMapping) throws IOException {
+ private static class PullRequestReportIsCreated implements Callable {
- Optional reportCheckRunCandidate = repository.getCheckRuns(workflowRun.getHeadSha()).toList().stream()
- .filter(cr -> cr.getOutput() != null)
- .filter(cr -> cr.getOutput().getTitle().startsWith(BUILD_SUMMARY_CHECK_RUN_PREFIX))
- .filter(cr -> cr.getOutput().getText() != null && !cr.getOutput().getText().isBlank())
- .findAny();
+ private final GHWorkflowRun workflowRun;
+ private final GHPullRequest pullRequest;
- if (reportCheckRunCandidate.isEmpty()) {
- commands.warning("Unable to find a check run to update");
- return;
+ private GHIssueComment reportComment;
+
+ private PullRequestReportIsCreated(GHWorkflowRun workflowRun, GHPullRequest pullRequest) {
+ this.workflowRun = workflowRun;
+ this.pullRequest = pullRequest;
}
- GHCheckRun reportCheckRun = reportCheckRunCandidate.get();
+ @Override
+ public Boolean call() throws Exception {
+ List commentsSinceWorkflowRunStarted = pullRequest.queryComments()
+ .since(workflowRun.getCreatedAt())
+ .list().toList();
+ Collections.reverse(commentsSinceWorkflowRunStarted);
- Output output = new Output(reportCheckRun.getOutput().getTitle(), reportCheckRun.getOutput().getSummary());
+ String workflowRunIdMarker = String.format(WORKFLOW_RUN_ID_MARKER, workflowRun.getId());
- String updatedReportText = reportCheckRun.getOutput().getText().lines().map(line -> {
- for (Entry buildScanEntry : buildScanMapping.entrySet()) {
- if (line.contains("| " + buildScanEntry.getKey() + " |")) {
- return line.replace(":construction:", "[:mag:](" + buildScanEntry.getValue() + ")");
- }
+ Optional reportCommentCandidate = commentsSinceWorkflowRunStarted.stream()
+ .filter(c -> c.getBody().contains(workflowRunIdMarker))
+ .findFirst();
+
+ if (reportCommentCandidate.isEmpty()) {
+ return false;
}
- return line;
- }).collect(Collectors.joining("\n"));
- if (!updatedReportText.equals(reportCheckRun.getOutput().getText())) {
- reportCheckRun.update().add(output).create();
+ reportComment = reportCommentCandidate.get();
+
+ return true;
+ }
+
+ public Optional getReportComment() {
+ return Optional.ofNullable(reportComment);
}
}
- private void createBuildScansOutput(GHWorkflowRun workflowRun, BuildScanStatuses statuses) throws IOException {
- Output output = new Output(BUILD_SCANS, BUILD_SCANS);
+ private void createBuildScansOutput(Commands commands, GHWorkflowRun workflowRun, BuildScanStatuses statuses) {
+ try {
+ Output output = new Output(BUILD_SCANS, BUILD_SCANS);
- StringBuilder buildScans = new StringBuilder();
- buildScans.append("| Status | Name | Build scan |\n");
- buildScans.append("| :-: | -- | :-: |\n");
+ StringBuilder buildScans = new StringBuilder();
+ buildScans.append("| Status | Name | Build scan |\n");
+ buildScans.append("| :-: | -- | :-: |\n");
- for (BuildScanStatus build : statuses.builds) {
- buildScans.append("| ").append(getConclusionEmoji(build.status)).append(" | ").append(build.jobName)
- .append(" | [:mag:](").append(build.buildScanLink).append(") |");
- }
+ for (BuildScanStatus build : statuses.builds) {
+ buildScans.append("| ").append(getConclusionEmoji(build.status)).append(" | ").append(build.jobName)
+ .append(" | [:mag:](").append(build.buildScanLink).append(") |");
+ }
- output.withText(buildScans.toString());
+ output.withText(buildScans.toString());
- workflowRun.getRepository().createCheckRun(BUILD_SCANS, workflowRun.getHeadSha())
- .add(output)
- .withConclusion(GHCheckRun.Conclusion.NEUTRAL)
- .withCompletedAt(new Date())
- .create();
+ workflowRun.getRepository().createCheckRun(BUILD_SCANS, workflowRun.getHeadSha())
+ .add(output)
+ .withConclusion(GHCheckRun.Conclusion.NEUTRAL)
+ .withCompletedAt(new Date())
+ .create();
+ } catch (Exception e) {
+ commands.error("Unable to create a check run with build scans: " + e.getMessage());
+ }
}
private static String getConclusionEmoji(String conclusion) {