Procházet zdrojové kódy

improve git setup for docker previews (#4637)

ianedwards před 2 roky
rodič
revize
85c81c9175

+ 40 - 12
api/server/handlers/porter_app/create_app_template.go

@@ -56,6 +56,7 @@ type CreateAppTemplateRequest struct {
 	Secrets                map[string]string        `json:"secrets"`
 	BaseDeploymentTargetID string                   `json:"base_deployment_target_id"`
 	Addons                 []Base64AddonWithEnvVars `json:"addons"`
+	GitOverrides           GitSource                `json:"git_overrides"`
 }
 
 // CreateAppTemplateResponse is the response object for the /app-template POST endpoint
@@ -173,22 +174,49 @@ func (c *CreateAppTemplateHandler) ServeHTTP(w http.ResponseWriter, r *http.Requ
 		return
 	}
 
-	err = porter_app.CreateAppWebhook(ctx, porter_app.CreateAppWebhookInput{
-		PorterAppName:           appName,
-		ProjectID:               project.ID,
-		ClusterID:               cluster.ID,
-		GithubAppSecret:         c.Config().ServerConf.GithubAppSecret,
-		GithubAppID:             c.Config().ServerConf.GithubAppID,
-		GithubWebhookSecret:     c.Config().ServerConf.GithubIncomingWebhookSecret,
-		ServerURL:               c.Config().ServerConf.ServerURL,
-		PorterAppRepository:     c.Repo().PorterApp(),
-		GithubWebhookRepository: c.Repo().GithubWebhook(),
-	})
+	porterApp, err := c.Repo().PorterApp().ReadPorterAppByName(cluster.ID, appName)
 	if err != nil {
-		err := telemetry.Error(ctx, span, err, "unable to set repo webhook")
+		err = telemetry.Error(ctx, span, err, "could not read porter app by name")
 		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
 		return
 	}
+	if porterApp.ID == 0 {
+		err = telemetry.Error(ctx, span, nil, "porter app not found")
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusNotFound))
+		return
+	}
+
+	gitSource := GitSource{
+		GitBranch:   porterApp.GitBranch,
+		GitRepoName: porterApp.RepoName,
+		GitRepoID:   porterApp.GitRepoID,
+	}
+	if request.GitOverrides.GitRepoName != "" {
+		gitSource = request.GitOverrides
+	}
+	telemetry.WithAttributes(span, telemetry.AttributeKV{Key: "git-repo-name", Value: gitSource.GitRepoName})
+
+	if gitSource.GitRepoName != "" {
+		err = porter_app.CreateAppWebhook(ctx, porter_app.CreateAppWebhookInput{
+			ProjectID:   project.ID,
+			ClusterID:   cluster.ID,
+			PorterAppID: porterApp.ID,
+			GitSource: porter_app.GitSource{
+				GitRepoName: gitSource.GitRepoName,
+				GitRepoID:   gitSource.GitRepoID,
+			},
+			GithubAppSecret:         c.Config().ServerConf.GithubAppSecret,
+			GithubAppID:             c.Config().ServerConf.GithubAppID,
+			GithubWebhookSecret:     c.Config().ServerConf.GithubIncomingWebhookSecret,
+			ServerURL:               c.Config().ServerConf.ServerURL,
+			GithubWebhookRepository: c.Repo().GithubWebhook(),
+		})
+		if err != nil {
+			err := telemetry.Error(ctx, span, err, "unable to set repo webhook")
+			c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
+			return
+		}
+	}
 
 	res := &CreateAppTemplateResponse{}
 

+ 15 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/v2/setup-app/PreviewAppDataContainer.tsx

@@ -53,6 +53,11 @@ type EncodedAddonWithEnv = {
   secrets: Record<string, string>;
 };
 
+export type RepoOverrides = {
+  id: number;
+  fullName: string;
+};
+
 export const PreviewAppDataContainer: React.FC<Props> = ({
   existingTemplate,
 }) => {
@@ -233,11 +238,13 @@ export const PreviewAppDataContainer: React.FC<Props> = ({
       variables,
       secrets,
       addons = [],
+      repo,
     }: {
       app: PorterApp | null;
       variables: Record<string, string>;
       secrets: Record<string, string>;
       addons?: EncodedAddonWithEnv[];
+      repo?: RepoOverrides;
     }) => {
       try {
         if (!app) {
@@ -252,6 +259,12 @@ export const PreviewAppDataContainer: React.FC<Props> = ({
             secrets,
             base_deployment_target_id: deploymentTarget.id,
             addons,
+            ...(repo && {
+              git_overrides: {
+                git_repo_id: repo.id,
+                git_repo_name: repo.fullName,
+              },
+            }),
           },
           {
             project_id: projectId,
@@ -335,12 +348,13 @@ export const PreviewAppDataContainer: React.FC<Props> = ({
           }}
           latestSource={latestSource}
           appName={porterApp.name}
-          savePreviewConfig={async () =>
+          savePreviewConfig={async ({ repo }: { repo?: RepoOverrides }) =>
             await createTemplateAndWorkflow({
               app: validatedAppProto,
               variables,
               secrets,
               addons: encodedAddons,
+              repo,
             })
           }
           error={createError}

+ 11 - 2
dashboard/src/main/home/cluster-dashboard/preview-environments/v2/setup-app/PreviewGHAModal.tsx

@@ -24,13 +24,15 @@ import { type SourceOptions } from "lib/porter-apps";
 
 import api from "shared/api";
 
+import { type RepoOverrides } from "./PreviewAppDataContainer";
+
 type PreviewGHAModalProps = {
   projectId: number;
   clusterId: number;
   appName: string;
   latestSource: SourceOptions;
   onClose: () => void;
-  savePreviewConfig: () => Promise<boolean>;
+  savePreviewConfig: ({ repo }: { repo?: RepoOverrides }) => Promise<boolean>;
   error: string;
 };
 
@@ -118,7 +120,14 @@ export const PreviewGHAModal: React.FC<PreviewGHAModalProps> = ({
 
   const confirmUpdate = handleSubmit(async (data) => {
     try {
-      await savePreviewConfig();
+      await savePreviewConfig({
+        ...(data.repository && {
+          repo: {
+            id: data.repoID,
+            fullName: data.repository,
+          },
+        }),
+      });
 
       if (openPRChoice === "skip") {
         await queryClient.invalidateQueries([

+ 5 - 0
dashboard/src/shared/api.tsx

@@ -1060,6 +1060,11 @@ const createAppTemplate = baseApi<
       variables: Record<string, string>;
       secrets: Record<string, string>;
     }>;
+    git_overrides?: {
+      git_branch?: string;
+      git_repo_id: number;
+      git_repo_name: string;
+    };
   },
   {
     project_id: number;

+ 20 - 25
internal/porter_app/github.go

@@ -15,17 +15,23 @@ import (
 	"github.com/porter-dev/porter/internal/telemetry"
 )
 
+// GitSource is a struct that contains the git repo name and id
+type GitSource struct {
+	GitRepoName string
+	GitRepoID   uint
+}
+
 // CreateAppWebhookInput is the input to the CreateAppWebhook function
 type CreateAppWebhookInput struct {
 	ProjectID           uint
 	ClusterID           uint
-	PorterAppName       string
+	PorterAppID         uint
+	GitSource           GitSource
 	GithubAppSecret     []byte
 	GithubAppID         string
 	GithubWebhookSecret string
 	ServerURL           string
 
-	PorterAppRepository     repository.PorterAppRepository
 	GithubWebhookRepository repository.GithubWebhookRepository
 }
 
@@ -35,15 +41,18 @@ func CreateAppWebhook(ctx context.Context, inp CreateAppWebhookInput) error {
 	ctx, span := telemetry.NewSpan(ctx, "porter-app-create-app-webhook")
 	defer span.End()
 
-	if inp.PorterAppName == "" {
-		return telemetry.Error(ctx, span, nil, "porter app name is empty")
-	}
 	if inp.ProjectID == 0 {
 		return telemetry.Error(ctx, span, nil, "project id is empty")
 	}
+	if inp.PorterAppID == 0 {
+		return telemetry.Error(ctx, span, nil, "porter app id is empty")
+	}
 	if inp.ClusterID == 0 {
 		return telemetry.Error(ctx, span, nil, "cluster id is empty")
 	}
+	if inp.GitSource.GitRepoName == "" {
+		return telemetry.Error(ctx, span, nil, "git repo name is empty")
+	}
 	if inp.GithubAppSecret == nil {
 		return telemetry.Error(ctx, span, nil, "github app secret is nil")
 	}
@@ -53,30 +62,16 @@ func CreateAppWebhook(ctx context.Context, inp CreateAppWebhookInput) error {
 	if inp.GithubWebhookSecret == "" {
 		return telemetry.Error(ctx, span, nil, "github webhook secret is empty")
 	}
-	if inp.PorterAppRepository == nil {
-		return telemetry.Error(ctx, span, nil, "porter app repository is nil")
-	}
 	if inp.GithubWebhookRepository == nil {
 		return telemetry.Error(ctx, span, nil, "github webhook repository is nil")
 	}
 
-	porterApp, err := inp.PorterAppRepository.ReadPorterAppByName(inp.ClusterID, inp.PorterAppName)
-	if err != nil {
-		return telemetry.Error(ctx, span, err, "could not read porter app by name")
-	}
-	if porterApp.ID == 0 {
-		return telemetry.Error(ctx, span, nil, "porter app not found")
-	}
-	if porterApp.GitRepoID == 0 {
-		return telemetry.Error(ctx, span, nil, "porter app git repo id is empty")
-	}
-
-	githubClient, err := GetGithubClientByRepoID(ctx, porterApp.GitRepoID, inp.GithubAppSecret, inp.GithubAppID)
+	githubClient, err := GetGithubClientByRepoID(ctx, inp.GitSource.GitRepoID, inp.GithubAppSecret, inp.GithubAppID)
 	if err != nil {
 		return telemetry.Error(ctx, span, err, "error creating github client")
 	}
 
-	repoDetails := strings.Split(porterApp.RepoName, "/")
+	repoDetails := strings.Split(inp.GitSource.GitRepoName, "/")
 	if len(repoDetails) != 2 {
 		return telemetry.Error(ctx, span, nil, "repo name is not in the format <org>/<repo>")
 	}
@@ -94,7 +89,7 @@ func CreateAppWebhook(ctx context.Context, inp CreateAppWebhookInput) error {
 	}
 
 	// check if the webhook already exists
-	webhook, err := inp.GithubWebhookRepository.GetByClusterAndAppID(ctx, inp.ClusterID, porterApp.ID)
+	webhook, err := inp.GithubWebhookRepository.GetByClusterAndAppID(ctx, inp.ClusterID, inp.PorterAppID)
 	if err != nil {
 		return telemetry.Error(ctx, span, err, "error getting github webhook")
 	}
@@ -119,9 +114,9 @@ func CreateAppWebhook(ctx context.Context, inp CreateAppWebhookInput) error {
 
 	webhook = &models.GithubWebhook{
 		ID:              webhookID,
-		ProjectID:       int(porterApp.ProjectID),
-		ClusterID:       int(porterApp.ClusterID),
-		PorterAppID:     int(porterApp.ID),
+		ProjectID:       int(inp.ProjectID),
+		ClusterID:       int(inp.ClusterID),
+		PorterAppID:     int(inp.PorterAppID),
 		GithubWebhookID: hook.GetID(),
 	}