Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve git setup for docker previews #4637

Merged
merged 2 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 40 additions & 12 deletions api/server/handlers/porter_app/create_app_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
},
Comment on lines +204 to +207
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you just create this input field? I'm not seeing it on my local

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm silly, I see now

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{}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ type EncodedAddonWithEnv = {
secrets: Record<string, string>;
};

export type RepoOverrides = {
id: number;
fullName: string;
};

export const PreviewAppDataContainer: React.FC<Props> = ({
existingTemplate,
}) => {
Expand Down Expand Up @@ -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) {
Expand All @@ -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,
Expand Down Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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([
Expand Down
5 changes: 5 additions & 0 deletions dashboard/src/shared/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
45 changes: 20 additions & 25 deletions internal/porter_app/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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")
}
Expand All @@ -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>")
}
Expand All @@ -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")
}
Expand All @@ -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(),
}

Expand Down
Loading