diff --git a/.github/quarkus-ecosystem-issue.java b/.github/quarkus-ecosystem-issue.java index b8a2d139e1b66..56357c54dc8e0 100644 --- a/.github/quarkus-ecosystem-issue.java +++ b/.github/quarkus-ecosystem-issue.java @@ -16,19 +16,21 @@ //usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS org.kohsuke:github-api:1.101 +//DEPS org.kohsuke:github-api:1.318 //DEPS info.picocli:picocli:4.2.0 import org.kohsuke.github.*; +import org.kohsuke.github.GHWorkflowRun.Conclusion; +import org.kohsuke.github.function.InputStreamFunction; + import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option; -import picocli.CommandLine.Parameters; -import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; -import java.util.concurrent.TimeUnit; +import java.io.BufferedReader; +import java.io.InputStreamReader; @Command(name = "report", mixinStandardHelpOptions = true, description = "Takes care of updating an issue depending on the status of the build") @@ -37,6 +39,7 @@ class Report implements Runnable { @Option(names = "token", description = "Github token to use when calling the Github API") private String token; + @Deprecated @Option(names = "status", description = "The status of the CI run") private String status; @@ -52,19 +55,26 @@ class Report implements Runnable { @Option(names = "runId", description = "The ID of the Github Action run for which we are reporting the CI status") private String runId; + + @Option(names = "--dry-run", description = "Whether to actually update the issue or not") + private boolean dryRun; + @Override public void run() { try { - final boolean succeed = "success".equalsIgnoreCase(status); - if ("cancelled".equalsIgnoreCase(status) || "skipped".equalsIgnoreCase(status)) { + final GitHub github = new GitHubBuilder().withOAuthToken(token).build(); + final GHRepository repository = github.getRepository(issueRepo); + GHWorkflowRun workflowRun = repository.getWorkflowRun(Long.parseLong(runId)); + Conclusion status = workflowRun.getConclusion(); + + System.out.println(String.format("The CI build had status %s.", status)); + + + if (status.equals(Conclusion.CANCELLED) || status.equals(Conclusion.SKIPPED)) { System.out.println("Job status is `cancelled` or `skipped` - exiting"); System.exit(0); } - System.out.println(String.format("The CI build had status %s.", status)); - - final GitHub github = new GitHubBuilder().withOAuthToken(token).build(); - final GHRepository repository = github.getRepository(issueRepo); final GHIssue issue = repository.getIssue(issueNumber); if (issue == null) { @@ -75,23 +85,51 @@ public void run() { System.out.println(String.format("The issue is currently %s", issue.getState().toString())); } - if (succeed) { + if (status.equals(Conclusion.SUCCESS)) { if (issue != null && isOpen(issue)) { - // close issue with a comment - final GHIssueComment comment = issue.comment(String.format("Build fixed:\n* Link to latest CI run: https://github.com/%s/actions/runs/%s", thisRepo, runId)); - issue.close(); - System.out.println(String.format("Comment added on issue %s - %s, the issue has also been closed", issue.getHtmlUrl().toString(), comment.getHtmlUrl().toString())); + String comment = String.format("Build fixed:\n* Link to latest CI run: https://github.com/%s/actions/runs/%s", thisRepo, runId); + if (!dryRun) { + // close issue with a comment + issue.comment(comment); + issue.close(); + } + System.out.println(String.format("Comment added on issue %s\n%s\n, the issue has also been closed", issue.getHtmlUrl().toString(), comment)); } else { System.out.println("Nothing to do - the build passed and the issue is already closed"); } } else { + StringBuilder sb = new StringBuilder("Failed jobs:\n"); + workflowRun.listJobs().toList().stream().filter(job -> job.getConclusion().equals(Conclusion.FAILURE)).forEach(job -> { + sb.append(String.format("* [%s](%s)\n", job.getName(), job.getUrl())); + job.getSteps().stream().filter(step -> step.getConclusion().equals(Conclusion.FAILURE)).forEach(step -> { + sb.append(String.format(" * Step: %s\n", step.getName())); + }); + String fullContent = ""; + try { + fullContent = job.downloadLogs(getLogArchiveInputStreamFunction()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (!fullContent.isEmpty()) { + sb.append(" Filtered logs:\n"); + sb.append(String.format("```\n%s```\n", fullContent)); + } + }); + if (isOpen(issue)) { - final GHIssueComment comment = issue.comment(String.format("The build is still failing:\n* Link to latest CI run: https://github.com/%s/actions/runs/%s", thisRepo, runId)); - System.out.println(String.format("Comment added on issue %s - %s", issue.getHtmlUrl().toString(), comment.getHtmlUrl().toString())); + String comment = String.format("The build is still failing!\n\n%s\nLink to latest CI run: https://github.com/%s/actions/runs/%s", sb.toString(), thisRepo, runId); + if (!dryRun) { + issue.comment(comment); + } + System.out.println(String.format("Comment added on issue %s\n%s", issue.getHtmlUrl().toString(), comment)); } else { - issue.reopen(); - final GHIssueComment comment = issue.comment(String.format("Unfortunately, the build failed:\n* Link to latest CI run: https://github.com/%s/actions/runs/%s", thisRepo, runId)); - System.out.println(String.format("Comment added on issue %s - %s, the issue has been re-opened", issue.getHtmlUrl().toString(), comment.getHtmlUrl().toString())); + String comment = String.format("Unfortunately, the build failed!\n\n%s\nLink to latest CI run: https://github.com/%s/actions/runs/%s", sb.toString(), thisRepo, runId); + if (!dryRun) { + issue.reopen(); + issue.comment(comment); + } + System.out.println(String.format("Comment added on issue %s\n%s, the issue has been re-opened", issue.getHtmlUrl().toString(), comment)); } } } @@ -100,6 +138,22 @@ public void run() { } } + private static InputStreamFunction getLogArchiveInputStreamFunction() { + return (is) -> { + StringBuilder stringBuilder = new StringBuilder(); + try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + if (line.contains("FAILURE [") || line.contains("Error:")) { + stringBuilder.append(line); + stringBuilder.append(System.lineSeparator()); + } + } + } + return stringBuilder.toString(); + }; + } + private static boolean isOpen(GHIssue issue) { return (issue.getState() == GHIssueState.OPEN); } diff --git a/.github/workflows/base-windows.yml b/.github/workflows/base-windows.yml index 824687502f6ee..03524a578f6ea 100644 --- a/.github/workflows/base-windows.yml +++ b/.github/workflows/base-windows.yml @@ -265,7 +265,6 @@ jobs: echo "Attempting to report results" ./jbang/bin/jbang ./workflow-mandrel/.github/quarkus-ecosystem-issue.java \ token="${BOT_TOKEN}" \ - status="${{ needs.build-mandrel.result }}" \ issueRepo="${{ inputs.issue-repo }}" \ issueNumber="${{ inputs.issue-number }}" \ thisRepo="${GITHUB_REPOSITORY}" \ diff --git a/.github/workflows/base.yml b/.github/workflows/base.yml index 6490aaf530ec1..44521565ab995 100644 --- a/.github/workflows/base.yml +++ b/.github/workflows/base.yml @@ -667,7 +667,6 @@ jobs: echo "Attempting to report results" ./jbang/bin/jbang ./workflow-mandrel/.github/quarkus-ecosystem-issue.java \ token="${BOT_TOKEN}" \ - status="${{ needs.native-tests.result }}" \ issueRepo="${{ inputs.issue-repo }}" \ issueNumber="${{ inputs.issue-number }}" \ thisRepo="${GITHUB_REPOSITORY}" \