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