Explorar el Código

check if PR has been closed inside deployment handlers

Mohammed Nafees hace 3 años
padre
commit
3a02870af7

+ 16 - 0
api/server/handlers/environment/create_deployment.go

@@ -66,6 +66,22 @@ func (c *CreateDeploymentHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque
 		return
 	}
 
+	// add a check for Github PR status
+	prClosed, err := isGithubPRClosed(client, owner, name, int(request.PullRequestID))
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("error fetching details of github PR. Error: %w", err), http.StatusConflict,
+		))
+		return
+	}
+
+	if prClosed {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("Github PR has been closed"),
+			http.StatusConflict))
+		return
+	}
+
 	ghDeployment, err := createDeployment(client, env, request.PRBranchFrom, request.ActionID)
 
 	if err != nil {

+ 8 - 2
api/server/handlers/environment/enable_pull_request.go

@@ -56,14 +56,20 @@ func (c *EnablePullRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ
 	}
 
 	// add an extra check that the installation has permission to read this pull request
-	pr, ghResp, err := client.PullRequests.Get(r.Context(), env.GitRepoOwner, env.GitRepoName, int(request.Number))
+	pr, _, err := client.PullRequests.Get(r.Context(), env.GitRepoOwner, env.GitRepoName, int(request.Number))
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
 	}
 
-	ghResp, err = client.Actions.CreateWorkflowDispatchEventByFileName(
+	if pr.GetState() == "closed" {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("Github PR has been closed"),
+			http.StatusConflict))
+		return
+	}
+
+	ghResp, err := client.Actions.CreateWorkflowDispatchEventByFileName(
 		r.Context(), env.GitRepoOwner, env.GitRepoName, fmt.Sprintf("porter_%s_env.yml", env.Name),
 		github.CreateWorkflowDispatchEventRequest{
 			Ref: request.BranchFrom,

+ 33 - 0
api/server/handlers/environment/finalize_deployment.go

@@ -104,6 +104,23 @@ func (c *FinalizeDeploymentHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
 		return
 	}
 
+	// add a check for the PR to be open before creating a comment
+	prClosed, err := isGithubPRClosed(client, owner, name, int(depl.PullRequestID))
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("error fetching details of github PR for deployment ID: %d. Error: %w",
+				depl.ID, err), http.StatusConflict,
+		))
+		return
+	}
+
+	if prClosed {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("Github PR has been closed"),
+			http.StatusConflict))
+		return
+	}
+
 	workflowRun, err := commonutils.GetLatestWorkflowRun(client, depl.RepoOwner, depl.RepoName,
 		fmt.Sprintf("porter_%s_env.yml", env.Name), depl.PRBranchFrom)
 
@@ -163,3 +180,19 @@ func (c *FinalizeDeploymentHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
 
 	c.WriteResult(w, r, depl.ToDeploymentType())
 }
+
+func isGithubPRClosed(
+	client *github.Client,
+	owner, name string,
+	prNumber int,
+) (bool, error) {
+	ghPR, _, err := client.PullRequests.Get(
+		context.Background(), owner, name, prNumber,
+	)
+
+	if err != nil {
+		return false, err
+	}
+
+	return ghPR.GetState() == "closed", nil
+}

+ 24 - 7
api/server/handlers/environment/finalize_deployment_with_errors.go

@@ -82,12 +82,6 @@ func (c *FinalizeDeploymentWithErrorsHandler) ServeHTTP(w http.ResponseWriter, r
 		return
 	}
 
-	depl.Status = types.DeploymentStatusFailed
-
-	// we do not care of the error in this case because the list deployments endpoint
-	// talks to the github API to fetch the deployment status correctly
-	c.Repo().Environment().UpdateDeployment(depl)
-
 	client, err := getGithubClientFromEnvironment(c.Config(), env)
 
 	if err != nil {
@@ -97,7 +91,30 @@ func (c *FinalizeDeploymentWithErrorsHandler) ServeHTTP(w http.ResponseWriter, r
 		return
 	}
 
-	// FIXME: ignore the status of thie API call for now
+	// add a check for the PR to be open before creating a comment
+	prClosed, err := isGithubPRClosed(client, owner, name, int(depl.PullRequestID))
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("error fetching details of github PR for deployment ID: %d. Error: %w",
+				depl.ID, err), http.StatusConflict,
+		))
+		return
+	}
+
+	if prClosed {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("Github PR has been closed"),
+			http.StatusConflict))
+		return
+	}
+
+	depl.Status = types.DeploymentStatusFailed
+
+	// we do not care of the error in this case because the list deployments endpoint
+	// talks to the github API to fetch the deployment status correctly
+	c.Repo().Environment().UpdateDeployment(depl)
+
+	// FIXME: ignore the status of this API call for now
 	client.Repositories.CreateDeploymentStatus(
 		context.Background(), owner, name, depl.GHDeploymentID, &github.DeploymentStatusRequest{
 			State:       github.String("failure"),

+ 28 - 8
api/server/handlers/environment/reenable_deployment.go

@@ -51,41 +51,61 @@ func (c *ReenableDeploymentHandler) ServeHTTP(w http.ResponseWriter, r *http.Req
 	}
 
 	if depl.Status != types.DeploymentStatusInactive {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("trying to re-enable deployment which is not marked \"inactive\""), http.StatusPreconditionFailed,
+		))
 		return
 	}
 
-	depl.Status = types.DeploymentStatusCreating
-
-	depl, err = c.Repo().Environment().UpdateDeployment(depl)
+	env, err := c.Repo().Environment().ReadEnvironmentByID(project.ID, cluster.ID, depl.EnvironmentID)
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
 	}
 
-	// create the backing namespace
-	agent, err := c.GetAgent(r, cluster, "")
+	client, err := getGithubClientFromEnvironment(c.Config(), env)
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
 	}
 
-	_, err = agent.CreateNamespace(depl.Namespace)
+	// add a check for the PR to be open before creating a comment
+	prClosed, err := isGithubPRClosed(client, depl.RepoOwner, depl.RepoName, int(depl.PullRequestID))
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("error fetching details of github PR for deployment ID: %d. Error: %w",
+				depl.ID, err), http.StatusConflict,
+		))
+		return
+	}
+
+	if prClosed {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("Github PR has been closed"),
+			http.StatusConflict))
+		return
+	}
+
+	depl.Status = types.DeploymentStatusCreating
+
+	depl, err = c.Repo().Environment().UpdateDeployment(depl)
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
 	}
 
-	env, err := c.Repo().Environment().ReadEnvironmentByID(project.ID, cluster.ID, depl.EnvironmentID)
+	// create the backing namespace
+	agent, err := c.GetAgent(r, cluster, "")
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
 		return
 	}
 
-	client, err := getGithubClientFromEnvironment(c.Config(), env)
+	_, err = agent.CreateNamespace(depl.Namespace)
 
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))

+ 20 - 0
api/server/handlers/environment/trigger_deployment_workflow.go

@@ -52,6 +52,9 @@ func (c *TriggerDeploymentWorkflowHandler) ServeHTTP(w http.ResponseWriter, r *h
 	}
 
 	if depl.Status == types.DeploymentStatusInactive {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("trying to trigger workflow run for inactive deployment"), http.StatusConflict,
+		))
 		return
 	}
 
@@ -69,6 +72,23 @@ func (c *TriggerDeploymentWorkflowHandler) ServeHTTP(w http.ResponseWriter, r *h
 		return
 	}
 
+	// add a check for the PR to be open before creating a comment
+	prClosed, err := isGithubPRClosed(client, depl.RepoOwner, depl.RepoName, int(depl.PullRequestID))
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("error fetching details of github PR for deployment ID: %d. Error: %w",
+				depl.ID, err), http.StatusConflict,
+		))
+		return
+	}
+
+	if prClosed {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("Github PR has been closed"),
+			http.StatusConflict))
+		return
+	}
+
 	latestWorkflowRun, err := commonutils.GetLatestWorkflowRun(client, env.GitRepoOwner, env.GitRepoName,
 		fmt.Sprintf("porter_%s_env.yml", env.Name), depl.PRBranchFrom)
 

+ 18 - 0
api/server/handlers/environment/update_deployment.go

@@ -1,6 +1,7 @@
 package environment
 
 import (
+	"fmt"
 	"net/http"
 
 	"github.com/porter-dev/porter/api/server/authz"
@@ -71,6 +72,23 @@ func (c *UpdateDeploymentHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque
 		return
 	}
 
+	// add a check for the PR to be open before creating a comment
+	prClosed, err := isGithubPRClosed(client, owner, name, int(depl.PullRequestID))
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("error fetching details of github PR for deployment ID: %d. Error: %w",
+				depl.ID, err), http.StatusConflict,
+		))
+		return
+	}
+
+	if prClosed {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("Github PR has been closed"),
+			http.StatusConflict))
+		return
+	}
+
 	ghDeployment, err := createDeployment(client, env, request.PRBranchFrom, request.ActionID)
 
 	if err != nil {

+ 27 - 0
api/server/handlers/environment/update_deployment_status.go

@@ -1,6 +1,7 @@
 package environment
 
 import (
+	"fmt"
 	"net/http"
 
 	"github.com/porter-dev/porter/api/server/authz"
@@ -63,6 +64,32 @@ func (c *UpdateDeploymentStatusHandler) ServeHTTP(w http.ResponseWriter, r *http
 		return
 	}
 
+	client, err := getGithubClientFromEnvironment(c.Config(), env)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("unable to get github client: %w", err), http.StatusConflict,
+		))
+		return
+	}
+
+	// add a check for the PR to be open before creating a comment
+	prClosed, err := isGithubPRClosed(client, depl.RepoOwner, depl.RepoName, int(depl.PullRequestID))
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("error fetching details of github PR for deployment ID: %d. Error: %w",
+				depl.ID, err), http.StatusConflict,
+		))
+		return
+	}
+
+	if prClosed {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("Github PR has been closed"),
+			http.StatusConflict))
+		return
+	}
+
 	if depl.Status == types.DeploymentStatusInactive && request.Status != string(types.DeploymentStatusCreating) {
 		// a deployment from "inactive" state can only transition to "creating"
 		c.WriteResult(w, r, depl.ToDeploymentType())