Просмотр исходного кода

Merge branch 'stacks-v1' of github.com:porter-dev/porter into stacks-v1

Justin Rhee 3 лет назад
Родитель
Сommit
17bd4073df

+ 29 - 18
api/server/handlers/environment/delete_deployment.go

@@ -11,6 +11,7 @@ import (
 	"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/commonutils"
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/api/server/shared/requestutils"
 	"github.com/porter-dev/porter/api/types"
@@ -57,18 +58,6 @@ func (c *DeleteDeploymentHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque
 		return
 	}
 
-	// delete corresponding namespace
-	agent, err := c.GetAgent(r, cluster, "")
-	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-		return
-	}
-
-	// make sure we do not delete any kubernetes "system" namespaces
-	if !isSystemNamespace(depl.Namespace) {
-		agent.DeleteNamespace(depl.Namespace)
-	}
-
 	// check that the environment belongs to the project and cluster IDs
 	env, err := c.Repo().Environment().ReadEnvironmentByID(project.ID, cluster.ID, depl.EnvironmentID)
 	if err != nil {
@@ -81,6 +70,34 @@ func (c *DeleteDeploymentHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque
 		return
 	}
 
+	// try to cancel any existing github workflow for this deployment
+	client, err := getGithubClientFromEnvironment(c.Config(), env)
+	if err == nil {
+		workflowRun, err := commonutils.GetLatestWorkflowRun(client, depl.RepoOwner, depl.RepoName,
+			fmt.Sprintf("porter_%s_env.yml", env.Name), depl.PRBranchFrom)
+		if err == nil {
+			if workflowRun.GetStatus() == "in_progress" || workflowRun.GetStatus() == "queued" ||
+				workflowRun.GetStatus() == "waiting" || workflowRun.GetStatus() == "requested" ||
+				workflowRun.GetStatus() == "pending" {
+				client.Actions.CancelWorkflowRunByID(
+					context.Background(), depl.RepoOwner, depl.RepoName, workflowRun.GetID(),
+				)
+			}
+		}
+	}
+
+	// delete corresponding namespace
+	agent, err := c.GetAgent(r, cluster, "")
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	// make sure we do not delete any kubernetes "system" namespaces
+	if !isSystemNamespace(depl.Namespace) {
+		agent.DeleteNamespace(depl.Namespace)
+	}
+
 	_, err = c.Repo().Environment().DeleteDeployment(depl)
 
 	if err != nil {
@@ -93,12 +110,6 @@ func (c *DeleteDeploymentHandler) ServeHTTP(w http.ResponseWriter, r *http.Reque
 		return
 	}
 
-	client, err := getGithubClientFromEnvironment(c.Config(), env)
-	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
-		return
-	}
-
 	if depl.GHDeploymentID != 0 {
 		// set the GitHub deployment status to be inactive
 		_, _, err := client.Repositories.CreateDeploymentStatus(

+ 33 - 14
api/server/handlers/stacks/parse.go

@@ -2,6 +2,7 @@ package stacks
 
 import (
 	"fmt"
+	"strings"
 
 	"github.com/porter-dev/porter/api/server/shared/config"
 	"github.com/porter-dev/porter/api/types"
@@ -60,23 +61,46 @@ func buildStackValues(parsed *PorterStackYAML, imageInfo *types.ImageInfo) (map[
 	values := make(map[string]interface{})
 
 	for name, app := range parsed.Apps {
-		defaultValues := getDefaultValues(app, parsed.Env, imageInfo)
+		appType := getType(name, app)
+		defaultValues := getDefaultValues(app, parsed.Env, appType)
 		helm_values := utils.CoalesceValues(defaultValues, app.Config)
 		values[name] = helm_values
+		if imageInfo != nil {
+			values["global"] = map[string]interface{}{
+				"image": map[string]interface{}{
+					"repository": imageInfo.Repository,
+					"tag":        imageInfo.Tag,
+				},
+			}
+		}
 	}
 
 	return values, nil
 }
 
-func getDefaultValues(app *App, env map[string]string, imageInfo *types.ImageInfo) map[string]interface{} {
+func getType(name string, app *App) string {
+	if app.Type != nil {
+		return *app.Type
+	}
+	if strings.Contains(name, "web") {
+		return "web"
+	}
+	return "worker"
+}
+
+func getDefaultValues(app *App, env map[string]string, appType string) map[string]interface{} {
 	var defaultValues map[string]interface{}
-	if *app.Type == "web" {
+	var runCommand string
+	if app.Run != nil {
+		runCommand = *app.Run
+	}
+	if appType == "web" {
 		defaultValues = map[string]interface{}{
 			"ingress": map[string]interface{}{
 				"enabled": false,
 			},
 			"container": map[string]interface{}{
-				"command": *app.Run,
+				"command": runCommand,
 				"env": map[string]interface{}{
 					"normal": CopyEnv(env),
 				},
@@ -85,19 +109,13 @@ func getDefaultValues(app *App, env map[string]string, imageInfo *types.ImageInf
 	} else {
 		defaultValues = map[string]interface{}{
 			"container": map[string]interface{}{
-				"command": *app.Run,
+				"command": runCommand,
 				"env": map[string]interface{}{
 					"normal": CopyEnv(env),
 				},
 			},
 		}
 	}
-	if imageInfo != nil {
-		defaultValues["image"] = map[string]interface{}{
-			"repository": imageInfo.Repository,
-			"tag":        imageInfo.Tag,
-		}
-	}
 	return defaultValues
 }
 
@@ -105,13 +123,14 @@ func buildStackChart(parsed *PorterStackYAML, config *config.Config, projectID u
 	deps := make([]*chart.Dependency, 0)
 
 	for alias, app := range parsed.Apps {
-		selectedRepo := "https://charts.getporter.dev"
-		selectedVersion, err := getLatestTemplateVersion(*app.Type, config, projectID)
+		appType := getType(alias, app)
+		selectedRepo := config.ServerConf.DefaultApplicationHelmRepoURL
+		selectedVersion, err := getLatestTemplateVersion(appType, config, projectID)
 		if err != nil {
 			return nil, err
 		}
 		deps = append(deps, &chart.Dependency{
-			Name:       *app.Type,
+			Name:       appType,
 			Alias:      alias,
 			Version:    selectedVersion,
 			Repository: selectedRepo,

+ 1 - 1
cli/cmd/apply.go

@@ -151,7 +151,7 @@ func apply(_ *types.GetAuthenticatedUserResponse, client *api.Client, _ []string
 		if err != nil {
 			return fmt.Errorf("error parsing porter.yaml: %w", err)
 		}
-	} else if previewVersion.Version == "v1stack" {
+	} else if previewVersion.Version == "v1stack" || previewVersion.Version == "" {
 		stackName := os.Getenv("PORTER_STACK_NAME")
 		if stackName == "" {
 			return fmt.Errorf("environment variable PORTER_STACK_NAME must be set")

+ 5 - 1
cli/cmd/deploy.go

@@ -637,7 +637,11 @@ func updateSetEnvGroup(_ *types.GetAuthenticatedUserResponse, client *api.Client
 
 	newEnvGroup := &types.CreateEnvGroupRequest{
 		Name:      envGroupResp.Name,
-		Variables: envGroupResp.Variables,
+		Variables: make(map[string]string),
+	}
+
+	for k, v := range envGroupResp.Variables {
+		newEnvGroup.Variables[k] = v
 	}
 
 	// first check for multiple variables being set using the -e or -s flags

+ 9 - 5
cli/cmd/stack/hooks.go

@@ -63,12 +63,16 @@ func (t *DeployStackHook) PostApply(driverOutput map[string]interface{}) error {
 func (t *DeployStackHook) applyStack(client *api.Client, shouldCreate bool, driverOutput map[string]interface{}) error {
 	var imageInfo types.ImageInfo
 	image, ok := driverOutput["image"].(string)
-	if ok && image != "" {
-		// split image into image-path:tag format
+	// if it contains a $, then it means the query didn't resolve to anything
+	if ok && !strings.Contains(image, "$") {
 		imageSpl := strings.Split(image, ":")
-		imageInfo = types.ImageInfo{
-			Repository: imageSpl[0],
-			Tag:        imageSpl[1],
+		if len(imageSpl) == 2 {
+			imageInfo = types.ImageInfo{
+				Repository: imageSpl[0],
+				Tag:        imageSpl[1],
+			}
+		} else {
+			return fmt.Errorf("could not parse image info %s", image)
 		}
 	}
 

+ 1 - 0
dashboard/src/main/home/app-dashboard/new-app-flow/AdvancedBuildSettings.tsx

@@ -69,6 +69,7 @@ const AdvancedBuildSettings: React.FC<AdvancedBuildSettingsProps> = (props) => {
           folderPath={props.folderPath}
           onChange={(config) => {
             props.setBuildConfig(config);
+            props.setDockerfilePath("");
           }}
           hide={false}
         />

+ 51 - 24
dashboard/src/main/home/app-dashboard/new-app-flow/NewAppFlow.tsx

@@ -108,19 +108,31 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
       parsedYaml = yaml.load(yamlString);
       const parsedData = PorterYamlSchema.parse(parsedYaml);
       const porterYamlToJson = parsedData as z.infer<typeof PorterYamlSchema>;
-      setPorterJson(porterYamlToJson)
-      console.log(porterYamlToJson)
+      setPorterJson(porterYamlToJson);
+      console.log(porterYamlToJson);
       // go through key value pairs and create services from them, if they don't already exist
       const newServices = [];
-      const existingServices = formState.serviceList.map(s => s.name);
+      const existingServices = formState.serviceList.map((s) => s.name);
       for (const [name, app] of Object.entries(porterYamlToJson.apps)) {
         if (!existingServices.includes(name)) {
           if (app.type) {
-            newServices.push(Service.default(name, app.type, { readOnly: true, value: app.run }))
-          } else if (name.includes('web')) {
-            newServices.push(Service.default(name, 'web', { readOnly: true, value: app.run }))
+            newServices.push(
+              Service.default(name, app.type, {
+                readOnly: true,
+                value: app.run,
+              })
+            );
+          } else if (name.includes("web")) {
+            newServices.push(
+              Service.default(name, "web", { readOnly: true, value: app.run })
+            );
           } else {
-            newServices.push(Service.default(name, 'worker', { readOnly: true, value: app.run }))
+            newServices.push(
+              Service.default(name, "worker", {
+                readOnly: true,
+                value: app.run,
+              })
+            );
           }
         }
       }
@@ -168,7 +180,7 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
           git_branch: branch,
           build_context: folderPath,
           builder: (buildConfig as any)?.builder,
-          buildpacks: (buildConfig as any)?.buildPacks,
+          buildpacks: (buildConfig as any)?.buildpacks,
           dockerfile: dockerfilePath,
           image_repo_uri: imageUrl,
         },
@@ -193,7 +205,7 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
           cluster_id: currentCluster.id,
           project_id: currentProject.id,
         }
-      )
+      );
     } catch (err) {
       console.log(err);
     }
@@ -201,7 +213,10 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
     // TODO: update Porter stack
   };
 
-  const combineEnv = (dashboardSetVariables: KeyValueType[], porterYamlSetVariables: Record<string, string> | undefined): z.infer<typeof EnvSchema> => {
+  const combineEnv = (
+    dashboardSetVariables: KeyValueType[],
+    porterYamlSetVariables: Record<string, string> | undefined
+  ): z.infer<typeof EnvSchema> => {
     const env: z.infer<typeof EnvSchema> = {};
     for (const { key, value } of dashboardSetVariables) {
       env[key] = value;
@@ -212,32 +227,39 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
       }
     }
     return env;
-  }
+  };
 
   const createApps = (serviceList: Service[]): z.infer<typeof AppsSchema> => {
     const apps: z.infer<typeof AppsSchema> = {};
     for (const service of serviceList) {
       let config = Service.serialize(service);
-      if (porterJson != null && porterJson.apps[service.name] != null && porterJson.apps[service.name].config != null) {
-        config = overrideObjectValues(config, porterJson.apps[service.name].config)
+      if (
+        porterJson != null &&
+        porterJson.apps[service.name] != null &&
+        porterJson.apps[service.name].config != null
+      ) {
+        config = overrideObjectValues(
+          config,
+          porterJson.apps[service.name].config
+        );
       }
       apps[service.name] = {
         type: service.type,
         run: service.startCommand.value,
         config,
-      }
+      };
     }
 
-    return apps
-  }
+    return apps;
+  };
 
   const createFinalPorterYaml = (): z.infer<typeof PorterYamlSchema> => {
     return {
       version: "v1stack",
       env: combineEnv(formState.envVariables, porterJson.env),
       apps: createApps(formState.serviceList),
-    }
-  }
+    };
+  };
 
   return (
     <CenterWrapper>
@@ -323,12 +345,17 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
               <>
                 <Text size={16}>Application services</Text>
                 <Spacer y={0.5} />
-                {porterJson && porterJson.apps && Object.keys(porterJson.apps).length > 0 &&
-                  <AppearingDiv>
-                    <Text size={16} color={"green"}>Auto-detected {Object.keys(porterJson.apps).length} services from porter.yaml!</Text>
-                    <Spacer y={1} />
-                  </AppearingDiv>
-                }
+                {porterJson &&
+                  porterJson.apps &&
+                  Object.keys(porterJson.apps).length > 0 && (
+                    <AppearingDiv>
+                      <Text size={16} color={"green"}>
+                        Auto-detected {Object.keys(porterJson.apps).length}{" "}
+                        services from porter.yaml!
+                      </Text>
+                      <Spacer y={1} />
+                    </AppearingDiv>
+                  )}
                 <Services
                   setServices={(services: any[]) => {
                     setFormState({ ...formState, serviceList: services });

+ 22 - 23
dashboard/src/main/home/cluster-dashboard/preview-environments/deployments/DeploymentCard.tsx

@@ -193,7 +193,12 @@ const DeploymentCard: React.FC<{
     },
   ];
 
-  console.error(deployment, deployment.gh_pr_branch_from, deployment.gh_pr_branch_into, deployment.gh_pr_branch_from === deployment.gh_pr_branch_into);
+  console.error(
+    deployment,
+    deployment.gh_pr_branch_from,
+    deployment.gh_pr_branch_into,
+    deployment.gh_pr_branch_from === deployment.gh_pr_branch_into
+  );
 
   return (
     <DeploymentCardWrapper
@@ -275,28 +280,22 @@ const DeploymentCard: React.FC<{
               </>
             ) : null}
 
-            {deployment.status !== DeploymentStatus.Creating && (
-              <>
-                {deployment.subdomain &&
-                deployment.status === DeploymentStatus.Created ? (
-                  <RowButton
-                    onClick={(e) => {
-                      e.preventDefault();
-                      e.stopPropagation();
-
-                      window.open(deployment.subdomain, "_blank");
-                    }}
-                    key={deployment.subdomain}
-                  >
-                    <i className="material-icons">open_in_new</i>
-                    View Live
-                  </RowButton>
-                ) : null}
-                <DeploymentCardActionsDropdown
-                  options={DeploymentCardActions}
-                />
-              </>
-            )}
+            {deployment.subdomain &&
+            deployment.status === DeploymentStatus.Created ? (
+              <RowButton
+                onClick={(e) => {
+                  e.preventDefault();
+                  e.stopPropagation();
+
+                  window.open(deployment.subdomain, "_blank");
+                }}
+                key={deployment.subdomain}
+              >
+                <i className="material-icons">open_in_new</i>
+                View Live
+              </RowButton>
+            ) : null}
+            <DeploymentCardActionsDropdown options={DeploymentCardActions} />
             {/* <Button
               onClick={() => {
                 setCurrentOverlay({