From 3fa03a0e1296b33a4d0125987a22ea5096861a97 Mon Sep 17 00:00:00 2001 From: Martin Lowe <martin.lowe@eclipse-foundation.org> Date: Thu, 14 Sep 2023 14:09:54 -0400 Subject: [PATCH 1/2] Add error page for GH status validation page for bad requests --- .../git/eca/resource/StatusResource.java | 8 +++++--- src/main/resources/templates/404.html | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/templates/404.html diff --git a/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java b/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java index 630ae1f1..717783e5 100644 --- a/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java +++ b/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java @@ -15,7 +15,6 @@ import java.util.List; import java.util.stream.Collectors; import javax.inject.Inject; -import javax.ws.rs.BadRequestException; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.Path; @@ -64,6 +63,8 @@ public class StatusResource extends GithubAdjacentResource { // Qute templates, generates UI status page @Location("simple_fingerprint_ui") Template statusUiTemplate; + @Location("404") + Template errorTemplate; /** * Standard endpoint for retrieving raw validation information on a historic request, using the fingerprint for lookups. @@ -120,11 +121,12 @@ public class StatusResource extends GithubAdjacentResource { @Path("gh/{org}/{repoName}/{prNo}") public Response getCommitValidationForGithub(@PathParam("org") String org, @PathParam("repoName") String repoName, @PathParam("prNo") Integer prNo) { + String repoFullName = org + '/' + repoName; // check that the passed repo has a valid installation String installationId = ghAppService.getInstallationForRepo(org, repoName); if (StringUtils.isBlank(installationId)) { - throw new BadRequestException("Repo " + repoFullName + " requested, but does not have visible installation, returning"); + return Response.ok().entity(errorTemplate.render()).build(); } // generate the URL used to retrieve valid projects @@ -139,7 +141,7 @@ public class StatusResource extends GithubAdjacentResource { // run the validation for the current request ValidationResponse r = validationHelper.validateIncomingRequest(wrapper, org, repoName, prNo); if (r == null) { - throw new BadRequestException("Cannot validate request for " + repoFullName + "#" + prNo + " as it is already closed"); + return Response.ok().entity(errorTemplate.render()).build(); } // retrieve the status of the commits to display on the status page diff --git a/src/main/resources/templates/404.html b/src/main/resources/templates/404.html new file mode 100644 index 00000000..bc6bac4f --- /dev/null +++ b/src/main/resources/templates/404.html @@ -0,0 +1,14 @@ +{#include eclipse_header} + {#title}Git ECA Validation{/} +{/include} +{#include eclipse_breadcrumb /} +<div class="container" id="main-page-content"> + <div id="main-content-row" class="row"> + <section id="main-content" class="col-md-18 col-sm-16 margin-bottom-20"> + <h1>Git ECA Validation Status</h1> + <p>The requested ECA validation could not be served, as the data was deemed unable to be validated for the Eclipse Foundation projects namespaces.</p> + <p>If you think this is an error, please report a new issue to the <a href="https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/issues">Eclipse Foundation Helpdesk</a></p> + </section> + </div> +</div> +{#include eclipse_footer /} \ No newline at end of file -- GitLab From 305e023ee36a09e687583ff1cf925631965e50bb Mon Sep 17 00:00:00 2001 From: Martin Lowe <martin.lowe@eclipse-foundation.org> Date: Mon, 18 Sep 2023 12:29:10 -0400 Subject: [PATCH 2/2] Add better handling of errors in GH status page for different cases --- .../git/eca/resource/StatusResource.java | 127 ++++++++++++------ .../templates/{404.html => error.html} | 10 +- 2 files changed, 97 insertions(+), 40 deletions(-) rename src/main/resources/templates/{404.html => error.html} (59%) diff --git a/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java b/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java index 717783e5..98fd73d3 100644 --- a/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java +++ b/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.stream.Collectors; import javax.inject.Inject; +import javax.ws.rs.BadRequestException; import javax.ws.rs.GET; import javax.ws.rs.NotFoundException; import javax.ws.rs.Path; @@ -35,6 +36,7 @@ import org.eclipsefoundation.git.eca.namespace.ProviderType; import org.eclipsefoundation.git.eca.service.GithubApplicationService; import org.eclipsefoundation.git.eca.service.ValidationService; import org.eclipsefoundation.git.eca.service.ValidationStatusService; +import org.jboss.resteasy.client.exception.ResteasyWebApplicationException; import io.quarkus.qute.Location; import io.quarkus.qute.Template; @@ -48,6 +50,12 @@ import io.quarkus.qute.Template; @Path("eca/status") public class StatusResource extends GithubAdjacentResource { + // parameter names for the status error page + private static final String INCLUDE_INSTALL_LINK_PARAMETER = "includeInstallLink"; + private static final String MESSAGE_PARAMETER = "message"; + private static final String PULL_REQUEST_NUMBER_PARAMETER = "pullRequestNumber"; + private static final String REPO_URL_PARAMETER = "repoUrl"; + @Inject GithubApplicationService ghAppService; @Inject @@ -63,7 +71,7 @@ public class StatusResource extends GithubAdjacentResource { // Qute templates, generates UI status page @Location("simple_fingerprint_ui") Template statusUiTemplate; - @Location("404") + @Location("error") Template errorTemplate; /** @@ -98,10 +106,10 @@ public class StatusResource extends GithubAdjacentResource { .ok() .entity(statusUiTemplate .data("statuses", statuses) - .data("pullRequestNumber", null) + .data(PULL_REQUEST_NUMBER_PARAMETER, null) .data("fullRepoName", null) .data("project", ps.isEmpty() ? null : ps.get(0)) - .data("repoUrl", statuses.get(0).getRepoUrl()) + .data(REPO_URL_PARAMETER, statuses.get(0).getRepoUrl()) .data("installationId", null) .render()) .build(); @@ -121,48 +129,89 @@ public class StatusResource extends GithubAdjacentResource { @Path("gh/{org}/{repoName}/{prNo}") public Response getCommitValidationForGithub(@PathParam("org") String org, @PathParam("repoName") String repoName, @PathParam("prNo") Integer prNo) { - + // get the repo full name, used in a few lookups String repoFullName = org + '/' + repoName; - // check that the passed repo has a valid installation - String installationId = ghAppService.getInstallationForRepo(org, repoName); - if (StringUtils.isBlank(installationId)) { - return Response.ok().entity(errorTemplate.render()).build(); - } - // generate the URL used to retrieve valid projects String repoUrl = GithubValidationHelper.getRepoUrl(org, repoName); - // get the data about the current request, and check that we have some validation statuses - ValidationRequest req = validationHelper.generateRequest(installationId, repoFullName, prNo, repoUrl); - List<CommitValidationStatus> statuses = validationStatus - .getHistoricValidationStatusByShas(wrapper, req.getCommits().stream().map(Commit::getHash).collect(Collectors.toList())); - // check if we have any data, and if there is none, attempt to validate the request information - if (statuses.isEmpty()) { - // run the validation for the current request - ValidationResponse r = validationHelper.validateIncomingRequest(wrapper, org, repoName, prNo); - if (r == null) { - return Response.ok().entity(errorTemplate.render()).build(); + try { + // check that the passed repo has a valid installation + String installationId = ghAppService.getInstallationForRepo(org, repoName); + if (StringUtils.isBlank(installationId)) { + return Response + .ok() + .entity(errorTemplate + .data(MESSAGE_PARAMETER, "No Github ECA app installation could be found for the current pull request.") + .data(REPO_URL_PARAMETER, repoUrl) + .data(PULL_REQUEST_NUMBER_PARAMETER, prNo) + .data(INCLUDE_INSTALL_LINK_PARAMETER, true) + .render()) + .build(); } - // retrieve the status of the commits to display on the status page - statuses = validationStatus - .getHistoricValidationStatusByShas(wrapper, r.getCommits().keySet().stream().collect(Collectors.toList())); - } + // get the data about the current request, and check that we have some validation statuses + ValidationRequest req = validationHelper.generateRequest(installationId, repoFullName, prNo, repoUrl); + List<CommitValidationStatus> statuses = validationStatus + .getHistoricValidationStatusByShas(wrapper, + req.getCommits().stream().map(Commit::getHash).collect(Collectors.toList())); + // check if we have any data, and if there is none, attempt to validate the request information + if (statuses.isEmpty()) { + // run the validation for the current request adhoc + ValidationResponse r = validationHelper.validateIncomingRequest(wrapper, org, repoName, prNo); + if (r == null) { + return Response + .ok() + .entity(errorTemplate + .data(MESSAGE_PARAMETER, + "The currently selected PR is in a non-opened state, and will not be validated.") + .data(REPO_URL_PARAMETER, repoUrl) + .data(PULL_REQUEST_NUMBER_PARAMETER, prNo) + .data(INCLUDE_INSTALL_LINK_PARAMETER, false) + .render()) + .build(); + } + + // retrieve the status of the commits to display on the status page + statuses = validationStatus + .getHistoricValidationStatusByShas(wrapper, r.getCommits().keySet().stream().collect(Collectors.toList())); + } - // get projects for use in queries + UI - List<Project> ps = projects.retrieveProjectsForRepoURL(repoUrl, ProviderType.GITHUB); - // render and return the status UI - return Response - .ok() - .entity(statusUiTemplate - .data("statuses", statuses) - .data("pullRequestNumber", prNo) - .data("fullRepoName", repoFullName) - .data("project", ps.isEmpty() ? null : ps.get(0)) - .data("repoUrl", repoUrl) - .data("installationId", installationId) - .render()) - .build(); + // get projects for use in queries + UI + List<Project> ps = projects.retrieveProjectsForRepoURL(repoUrl, ProviderType.GITHUB); + // render and return the status UI + return Response + .ok() + .entity(statusUiTemplate + .data("statuses", statuses) + .data(PULL_REQUEST_NUMBER_PARAMETER, prNo) + .data("fullRepoName", repoFullName) + .data("project", ps.isEmpty() ? null : ps.get(0)) + .data(REPO_URL_PARAMETER, repoUrl) + .data("installationId", installationId) + .render()) + .build(); + } catch (BadRequestException e) { + return Response + .ok() + .entity(errorTemplate + .data(MESSAGE_PARAMETER, + "Request made to validate content that is not eligible for validation (either closed, or with no identifiable changes to validate).") + .data(REPO_URL_PARAMETER, repoUrl) + .data(PULL_REQUEST_NUMBER_PARAMETER, prNo) + .data(INCLUDE_INSTALL_LINK_PARAMETER, false) + .render()) + .build(); + } catch (NotFoundException | ResteasyWebApplicationException e) { + return Response + .ok() + .entity(errorTemplate + .data(MESSAGE_PARAMETER, + "Could not find a pull request given the passed parameters, please check the URL and try again.") + .data(REPO_URL_PARAMETER, repoUrl) + .data(PULL_REQUEST_NUMBER_PARAMETER, prNo) + .data(INCLUDE_INSTALL_LINK_PARAMETER, false) + .render()) + .build(); + } } - } diff --git a/src/main/resources/templates/404.html b/src/main/resources/templates/error.html similarity index 59% rename from src/main/resources/templates/404.html rename to src/main/resources/templates/error.html index bc6bac4f..9a1c92da 100644 --- a/src/main/resources/templates/404.html +++ b/src/main/resources/templates/error.html @@ -6,8 +6,16 @@ <div id="main-content-row" class="row"> <section id="main-content" class="col-md-18 col-sm-16 margin-bottom-20"> <h1>Git ECA Validation Status</h1> - <p>The requested ECA validation could not be served, as the data was deemed unable to be validated for the Eclipse Foundation projects namespaces.</p> + <p>{message}</p> <p>If you think this is an error, please report a new issue to the <a href="https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/issues">Eclipse Foundation Helpdesk</a></p> + <h2>Helpful links</h2> + <ul> + <li><a href="{repoUrl}">Target repository</a> + <li><a href="{repoUrl}/{pullRequestNumber}">Pull request</a> + {#if includeInstallLink} + <li><a href="https://github.com/apps/eclipse-eca-validation/installations/select_target">Install the application</a> + {/if} + </ul> </section> </div> </div> -- GitLab