You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: enable_pull_request.go
    path of file: ./repos/porter/api/server/handlers/environment
    
    the code of the file until where you have to start completion: package environment

import (
	"errors"
	"fmt"
	"net/http"
	"strconv"

	"github.com/google/go-github/v41/github"
	"github.com/porter-dev/porter/api/server/authz"
	"github.com/porter-dev/porter/api/server/handlers"
	"github.com/porter-dev/porter/api/server/shared"
	"github.com/porter-dev/porter/api/server/shared/apierrors"
	"github.com/porter-dev/porter/api/server/shared/config"
	"github.com/porter-dev/porter/api/types"
	"github.com/porter-dev/porter/internal/models"
	"github.com/porter-dev/porter/internal/telemetry"
	"gorm.io/gorm"
)

type EnablePullRequestHandler struct {
	handlers.PorterHandlerReadWriter
	authz.KubernetesAgentGetter
}

func NewEnablePullRequestHandler(
	config *config.Config,
	decoderValidator shared.RequestDecoderValidator,
	writer shared.ResultWriter,
) *EnablePullRequestHandler {
	return &EnablePullRequestHandler{
		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
		KubernetesAgentGetter:   authz.NewOutOfClusterAgentGetter(config),
	}
}

func (c *EnablePullRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ctx, span := telemetry.NewSpan(r.Context(), "serve-enable-pull-request")
	defer span.End()

	project, _ := ctx.Value(types.ProjectScope).(*models.Project)
	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)

	telemetry.WithAttributes(span,
		telemetry.AttributeKV{Key: "project-id", Value: project.ID},
		telemetry.AttributeKV{Key: "cluster-id", Value: cluster.ID},
	)

	request := &types.PullRequest{}

	if ok := c.DecodeAndValidate(w, r, request); !ok {
		_ = telemetry.Error(ctx, span, nil, "could not decode and validate request")
		return
	}

	telemetry.WithAttributes(span,
		telemetry.AttributeKV{Key: "title", Value: request.Title},
		telemetry.AttributeKV{Key: "number", Value: request.Number},
		telemetry.AttributeKV{Key: "repo-ower", Value: request.RepoOwner},
		telemetry.AttributeKV{Key: "repo-name", Value: request.RepoName},
		telemetry.AttributeKV{Key: "branch-from", Value: request.BranchFrom},
		telemetry.AttributeKV{Key: "branch-into", Value: request.BranchInto},
		telemetry.AttributeKV{Key: "created-at", Value: request.CreatedAt},
		telemetry.AttributeKV{Key: "updated-at", Value: request.UpdatedAt},
	)

	env, err := c.Repo().Environment().ReadEnvironmentByOwnerRepoName(project.ID, cluster.ID, request.RepoOwner, request.RepoName)
	if err != nil {
		err = telemetry.Error(ctx, span, err, "error reading environment by owner repo name")

		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.HandleAPIError(w, r, apierrors.NewErrNotFound(fmt.Errorf("environment not found in cluster and project")))
			return
		}

		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
		return
	}

	envType := env.ToEnvironmentType()

	if len(envType.GitRepoBranches) > 0 {
		found := false

		for _, branch := range env.ToEnvironmentType().GitRepoBranches {
			if branch == request.BranchInto {
				found = true
				break
			}
		}

		if !found {
			telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "unsuccessful-exit-reason", Value: "cannot find branch-into in git repo branches"})

			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
				fmt.Errorf("base branch '%s' is not enabled for this preview environment, please enable it "+
					"in the settings page to continue", request.BranchInto), http.StatusBadRequest,
			))
			return
		}
	} else if len(envType.GitDeployBranches) > 0 {
		found := false

		for _, branch := range env.ToEnvironmentType().GitDeployBranches {
			if branch == request.BranchFrom {
				found = true
				break
			}
		}

		if found {
			telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "unsuccessful-exit-reason", Value: "cannot find branch-from in git deploy branches"})

			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
				fmt.Errorf("head branch '%s' is enabled for branch deploys for this preview environment, "+
					"please disable it in the settings page to continue", request.BranchInto), http.StatusBadRequest,
			))
			return
		}
	}

	client, err := getGithubClientFromEnvironment(c.Config(), env)
	if err != nil {
		err = telemetry.Error(ctx, span, err, "error getting github client from environment")

		c.HandleAPIError(w, r, 
    
func (c *EnablePullRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	ctx, span := telemetry.NewSpan(r.Context(), "serve-enable-pull-request")
	defer span.End()

	project, _ := ctx.Value(types.ProjectScope).(*models.Project)
	cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)

	telemetry.WithAttributes(span,
		telemetry.AttributeKV{Key: "project-id", Value: project.ID},
		telemetry.AttributeKV{Key: "cluster-id", Value: cluster.ID},
	)

	request := &types.PullRequest{}

	if ok := c.DecodeAndValidate(w, r, request); !ok {
		_ = telemetry.Error(ctx, span, nil, "could not decode and validate request")
		return
	}

	telemetry.WithAttributes(span,
		telemetry.AttributeKV{Key: "title", Value: request.Title},
		telemetry.AttributeKV{Key: "number", Value: request.Number},
		telemetry.AttributeKV{Key: "repo-ower", Value: request.RepoOwner},
		telemetry.AttributeKV{Key: "repo-name", Value: request.RepoName},
		telemetry.AttributeKV{Key: "branch-from", Value: request.BranchFrom},
		telemetry.AttributeKV{Key: "branch-into", Value: request.BranchInto},
		telemetry.AttributeKV{Key: "created-at", Value: request.CreatedAt},
		telemetry.AttributeKV{Key: "updated-at", Value: request.UpdatedAt},
	)

	env, err := c.Repo().Environment().ReadEnvironmentByOwnerRepoName(project.ID, cluster.ID, request.RepoOwner, request.RepoName)
	if err != nil {
		err = telemetry.Error(ctx, span, err, "error reading environment by owner repo name")

		if errors.Is(err, gorm.ErrRecordNotFound) {
			c.HandleAPIError(w, r, apierrors.NewErrNotFound(fmt.Errorf("environment not found in cluster and project")))
			return
		}

		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
		return
	}

	envType := env.ToEnvironmentType()

	if len(envType.GitRepoBranches) > 0 {
		found := false

		for _, branch := range env.ToEnvironmentType().GitRepoBranches {
			if branch == request.BranchInto {
				found = true
				break
			}
		}

		if !found {
			telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "unsuccessful-exit-reason", Value: "cannot find branch-into in git repo branches"})

			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
				fmt.Errorf("base branch '%s' is not enabled for this preview environment, please enable it "+
					"in the settings page to continue", request.BranchInto), http.StatusBadRequest,
			))
			return
		}
	} else if len(envType.GitDeployBranches) > 0 {
		found := false

		for _, branch := range env.ToEnvironmentType().GitDeployBranches {
			if branch == request.BranchFrom {
				found = true
				break
			}
		}

		if found {
			telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "unsuccessful-exit-reason", Value: "cannot find branch-from in git deploy branches"})

			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
				fmt.Errorf("head branch '%s' is enabled for branch deploys for this preview environment, "+
					"please disable it in the settings page to continue", request.BranchInto), http.StatusBadRequest,
			))
			return
		}
	}

	client, err := getGithubClientFromEnvironment(c.Config(), env)
	if err != nil {
		err = telemetry.Error(ctx, span, err, "error getting github client from environment")

		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
		return
	}

	// add an extra check that the installation has permission to read this pull request
	pr, _, err := client.PullRequests.Get(ctx, env.GitRepoOwner, env.GitRepoName, int(request.Number))
	if err != nil {
		_ = telemetry.Error(ctx, span, err, "error getting pull request")

		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("%v: %w", errGithubAPI, err),
			http.StatusConflict))
		return
	}

	if pr.GetState() == "closed" {
		telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "unsuccessful-exit-reason", Value: "pr is closed"})

		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(fmt.Errorf("cannot enable deployment for closed PR"),
			http.StatusConflict))
		return
	}

	ghResp, err := client.Actions.CreateWorkflowDispatchEventByFileName(
		ctx, env.GitRepoOwner, env.GitRepoName, fmt.Sprintf("porter_%s_env.yml", env.Name),
		github.CreateWorkflowDispatchEventRequest{
			Ref: request.BranchFrom,
			Inputs: map[string]interface{}{
				"pr_number":      strconv.FormatUint(uint64(request.Number), 10),
				"pr_title":       pr.GetTitle(),
				"pr_branch_from": request.BranchFrom,
				"pr_branch_into": request.BranchInto,
			},
		},
	)
	if err != nil {
		err = telemetry.Error(ctx, span, err, "error creating workflow dispatch event")
		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
		return
	}

	if ghResp != nil {
		telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "github-status-code", Value: ghResp.StatusCode})
		if ghResp.StatusCode == 404 {
			telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "unsuccessful-exit-reason", Value: "bad github status code"})
			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
				fmt.Errorf(
					"please make sure the preview environment workflow files are present in PR branch %s and are up to"+
						" date with the default branch", request.BranchFrom,
				), http.StatusConflict),
			)
			return
		} else if ghResp.StatusCode == 422 {
			telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "unsuccessful-exit-reason", Value: "bad github status code"})
			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
				fmt.Errorf(
					"please make sure the workflow files in PR branch %s are up to date with the default branch",
					request.BranchFrom,
				), http.StatusConflict),
			)
			return
		}
	}

	// create the deployment
	depl, err := c.Repo().Environment().CreateDeployment(&models.Deployment{
		EnvironmentID: env.ID,
		Namespace:     "",
		Status:        types.DeploymentStatusCreating,
		PullRequestID: request.Number,
		RepoOwner:     request.RepoOwner,
		RepoName:      request.RepoName,
		PRName:        request.Title,
		PRBranchFrom:  request.BranchFrom,
		PRBranchInto:  request.BranchInto,
	})
	if err != nil {
		err = telemetry.Error(ctx, span, err, "error creating deployment in repo")
		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
		return
	}

	c.WriteResult(w, r, depl.ToDeploymentType())
}