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

add deployment target id to yaml and allow selecting deployment target in app view (#4482)

d-g-town 2 лет назад
Родитель
Сommit
baab02f301

+ 14 - 13
api/server/handlers/porter_app/create_secret_and_open_pr.go

@@ -133,19 +133,20 @@ func (c *OpenStackPRHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 
 	if request.OpenPr || request.DeleteWorkflowFilename != "" {
 		openPRInput := &actions.GithubPROpts{
-			PRAction:       actions.GithubPRAction_NewAppWorkflow,
-			Client:         client,
-			GitRepoOwner:   request.GithubRepoOwner,
-			GitRepoName:    request.GithubRepoName,
-			StackName:      appName,
-			ProjectID:      project.ID,
-			ClusterID:      cluster.ID,
-			ServerURL:      c.Config().ServerConf.ServerURL,
-			DefaultBranch:  request.Branch,
-			SecretName:     secretName,
-			PorterYamlPath: request.PorterYamlPath,
-			Body:           prRequestBody,
-			PRBranch:       prBranchName,
+			PRAction:           actions.GithubPRAction_NewAppWorkflow,
+			Client:             client,
+			GitRepoOwner:       request.GithubRepoOwner,
+			GitRepoName:        request.GithubRepoName,
+			StackName:          appName,
+			ProjectID:          project.ID,
+			ClusterID:          cluster.ID,
+			ServerURL:          c.Config().ServerConf.ServerURL,
+			DefaultBranch:      request.Branch,
+			SecretName:         secretName,
+			PorterYamlPath:     request.PorterYamlPath,
+			Body:               prRequestBody,
+			PRBranch:           prBranchName,
+			DeploymentTargetId: request.DeploymentTargetId,
 		}
 		if request.DeleteWorkflowFilename != "" {
 			openPRInput.PRAction = actions.GithubPRAction_DeleteAppWorkflow

+ 1 - 0
api/types/stack.go

@@ -20,6 +20,7 @@ type CreateSecretAndOpenGHPRRequest struct {
 	PorterYamlPath           string `json:"porter_yaml_path"`
 	DeleteWorkflowFilename   string `json:"delete_workflow_filename"`
 	PreviewsWorkflowFilename string `json:"previews_workflow_filename"`
+	DeploymentTargetId       string `json:"deployment_target_id"`
 }
 
 type CreateSecretAndOpenGHPRResponse struct {

+ 5 - 2
dashboard/src/components/porter/Select.tsx

@@ -21,6 +21,7 @@ type Props = {
   prefix?: React.ReactNode;
   width?: string;
   height?: string;
+  noShrink?: boolean;
 };
 
 const Select: React.FC<Props> = ({
@@ -34,9 +35,10 @@ const Select: React.FC<Props> = ({
   prefix,
   width,
   height,
+  noShrink,
 }) => {
   return (
-    <Div width={width}>
+    <Div width={width} noShrink={noShrink}>
       {label && <Label color={labelColor}>{label}</Label>}
       <SelectWrapper isDisabled={disabled ?? false} height={height}>
         {prefix && (
@@ -86,8 +88,9 @@ const Select: React.FC<Props> = ({
 
 export default Select;
 
-const Div = styled.div<{ width?: string }>`
+const Div = styled.div<{ width?: string, noShrink?: boolean }>`
   width: ${({ width }) => width || ""};
+  ${({ noShrink }) => (noShrink ? "flex-shrink: 0;" : "")}
 `;
 
 const Img = styled.img`

+ 58 - 9
dashboard/src/main/home/app-dashboard/apps/Apps.tsx

@@ -13,9 +13,8 @@ import Container from "components/porter/Container";
 import DashboardPlaceholder from "components/porter/DashboardPlaceholder";
 import Image from "components/porter/Image";
 import PorterLink from "components/porter/Link";
-import Link from "components/porter/Link";
-import Modal from "components/porter/Modal";
 import SearchBar from "components/porter/SearchBar";
+import Select from "components/porter/Select";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import Toggle from "components/porter/Toggle";
@@ -24,6 +23,10 @@ import DeleteEnvModal from "main/home/cluster-dashboard/preview-environments/v2/
 import BillingModal from "main/home/modals/BillingModal";
 import { clientAddonFromProto, type ClientAddon } from "lib/addons";
 import { useAppAnalytics } from "lib/hooks/useAppAnalytics";
+import {
+  useDeploymentTargetList,
+  type DeploymentTarget,
+} from "lib/hooks/useDeploymentTarget";
 import { checkIfProjectHasPayment } from "lib/hooks/useStripe";
 
 import api from "shared/api";
@@ -35,6 +38,7 @@ import gift from "assets/gift.svg";
 import grid from "assets/grid.png";
 import list from "assets/list.png";
 import pull_request from "assets/pull_request_icon.svg";
+import target from "assets/target.svg";
 import letter from "assets/vector.svg";
 
 import AppGrid from "./AppGrid";
@@ -50,6 +54,10 @@ const Apps: React.FC = () => {
   const { currentProject, currentCluster } = useContext(Context);
   const { updateAppStep } = useAppAnalytics();
   const { currentDeploymentTarget } = useDeploymentTarget();
+  const { deploymentTargetList } = useDeploymentTargetList({ preview: false });
+  const [deploymentTargetIdFilter, setDeploymentTargetIdFilter] =
+    useState<string>("all");
+
   const { hasPaymentEnabled } = checkIfProjectHasPayment();
   const history = useHistory();
 
@@ -69,6 +77,7 @@ const Apps: React.FC = () => {
             cluster_id: currentCluster?.id,
             project_id: currentProject?.id,
             deployment_target_id: currentDeploymentTarget?.id,
+            deployment_target_id_filter: deploymentTargetIdFilter,
           },
         ],
         queryFn: async () => {
@@ -82,14 +91,20 @@ const Apps: React.FC = () => {
             return;
           }
 
+          let deploymentTargetId = currentDeploymentTarget.id;
+          if (currentProject.managed_deployment_targets_enabled) {
+            if (!currentDeploymentTarget.is_preview) {
+              deploymentTargetId =
+                deploymentTargetIdFilter !== "all"
+                  ? deploymentTargetIdFilter
+                  : "";
+            }
+          }
+
           const res = await api.getLatestAppRevisions(
             "<token>",
             {
-              deployment_target_id:
-                currentProject.managed_deployment_targets_enabled &&
-                !currentDeploymentTarget.is_preview
-                  ? undefined
-                  : currentDeploymentTarget.id,
+              deployment_target_id: deploymentTargetId,
               ignore_preview_apps: !currentDeploymentTarget.is_preview,
             },
             { cluster_id: currentCluster.id, project_id: currentProject.id }
@@ -210,7 +225,10 @@ const Apps: React.FC = () => {
       return <Loading offset="-150px" />;
     }
 
-    if (apps.length === 0) {
+    if (
+      apps.length === 0 &&
+      !currentProject?.managed_deployment_targets_enabled
+    ) {
       if (currentCluster?.status === "FAILED") {
         return <ClusterProvisioningPlaceholder />;
       }
@@ -312,6 +330,37 @@ const Apps: React.FC = () => {
             width="100%"
           />
           <Spacer inline x={2} />
+          {currentProject?.managed_deployment_targets_enabled &&
+            !currentDeploymentTarget?.is_preview && (
+              <>
+                <Select
+                  options={[{ value: "all", label: "All" }].concat(
+                    deploymentTargetList.map((target: DeploymentTarget) => {
+                      return {
+                        value: target.id,
+                        label: target.name,
+                        key: target.id,
+                      };
+                    })
+                  )}
+                  value={deploymentTargetIdFilter}
+                  setValue={(value) => {
+                    if (value !== deploymentTargetIdFilter) {
+                      setDeploymentTargetIdFilter(value);
+                    }
+                  }}
+                  prefix={
+                    <Container row>
+                      <Image src={target} size={15} opacity={0.6} />
+                      <Spacer inline x={0.5} />
+                      Target
+                    </Container>
+                  }
+                  noShrink={true}
+                />
+                <Spacer inline x={1} />
+              </>
+            )}
           <Toggle
             items={[
               { label: <ToggleIcon src={calendar} />, value: "calendar" },
@@ -341,7 +390,7 @@ const Apps: React.FC = () => {
               }
             }}
           />
-          <Spacer inline x={2} />
+          <Spacer inline x={1} />
           {currentDeploymentTarget?.is_preview ? (
             <Button
               onClick={async () => {

+ 1 - 0
dashboard/src/main/home/app-dashboard/create-app/CreateApp.tsx

@@ -742,6 +742,7 @@ const CreateApp: React.FC<CreateAppProps> = ({ history }) => {
           stackName={name.value}
           projectId={currentProject.id}
           clusterId={currentCluster.id}
+          deploymentTargetId={deploymentTargetID}
           deployPorterApp={async () =>
             await update({
               app: validatedAppProto,

+ 8 - 3
dashboard/src/main/home/app-dashboard/new-app-flow/GithubActionModal.tsx

@@ -25,6 +25,7 @@ type Props = RouteComponentProps & {
   stackName?: string;
   projectId?: number;
   clusterId?: number;
+  deploymentTargetId?: string;
   deployPorterApp?: () => Promise<boolean>;
   deploymentError?: string;
   porterYamlPath?: string;
@@ -42,6 +43,7 @@ const GithubActionModal: React.FC<Props> = ({
   stackName,
   projectId,
   clusterId,
+  deploymentTargetId,
   deployPorterApp,
   deploymentError,
   porterYamlPath,
@@ -62,7 +64,8 @@ const GithubActionModal: React.FC<Props> = ({
       clusterId,
       stackName,
       branch,
-      porterYamlPath
+      porterYamlPath,
+      deploymentTargetId
     );
   }, [projectId, clusterId, stackName, branch, porterYamlPath]);
 
@@ -95,6 +98,7 @@ const GithubActionModal: React.FC<Props> = ({
               branch,
               open_pr: choice === "open_pr" || isChecked,
               porter_yaml_path: porterYamlPath,
+              deployment_target_id: deploymentTargetId,
             },
             {
               project_id: projectId,
@@ -157,7 +161,8 @@ const GithubActionModal: React.FC<Props> = ({
           <Select
             options={[
               {
-                label: "I authorize Porter to open a PR on my behalf (recommended)",
+                label:
+                  "I authorize Porter to open a PR on my behalf (recommended)",
                 value: "open_pr",
               },
               {
@@ -228,4 +233,4 @@ const ModalHeader = styled.div`
   height: 40px;
   display: flex;
   align-items: center;
-`;
+`;

+ 5 - 3
dashboard/src/main/home/app-dashboard/new-app-flow/utils.ts

@@ -23,8 +23,9 @@ export const getGithubAction = (
   clusterId: number,
   stackName: string,
   branchName: string,
-  porterYamlPath: string = "porter.yaml"
-) => {
+  porterYamlPath: string = "porter.yaml",
+  deploymentTargetId: string = "",
+): string => {
   return `on:
   push:
     branches:
@@ -50,7 +51,8 @@ jobs:
         PORTER_PROJECT: ${projectID}
         PORTER_STACK_NAME: ${stackName}
         PORTER_TAG: \${{ steps.vars.outputs.sha_short }}
-        PORTER_TOKEN: \${{ secrets.PORTER_STACK_${projectID}_${clusterId} }}`;
+        PORTER_TOKEN: \${{ secrets.PORTER_STACK_${projectID}_${clusterId} }}
+        ${deploymentTargetId ? `PORTER_DEPLOYMENT_TARGET_ID: ${deploymentTargetId}` : ""}`;
 };
 
 export const getPreviewGithubAction = ({

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

@@ -3511,6 +3511,7 @@ const createSecretAndOpenGitHubPullRequest = baseApi<
     porter_yaml_path?: string;
     delete_workflow_filename?: string;
     previews_workflow_filename?: string;
+    deployment_target_id?: string;
   },
   {
     project_id: number;

+ 12 - 8
internal/integrations/ci/actions/stack.go

@@ -35,6 +35,7 @@ type GithubPROpts struct {
 	Body                      string
 	WorkflowFileName          string
 	PRBranch                  string
+	DeploymentTargetId        string
 }
 
 type GetStackApplyActionYAMLOpts struct {
@@ -45,6 +46,7 @@ type GetStackApplyActionYAMLOpts struct {
 	SecretName           string
 	PorterYamlPath       string
 	Preview              bool
+	DeploymentTargetId   string
 }
 
 func OpenGithubPR(opts *GithubPROpts) (*github.PullRequest, error) {
@@ -104,14 +106,15 @@ func commitChange(prBranchName string, opts GithubPROpts) error {
 	switch opts.PRAction {
 	case GithubPRAction_NewAppWorkflow:
 		applyWorkflowYAML, err := getStackApplyActionYAML(&GetStackApplyActionYAMLOpts{
-			ServerURL:      opts.ServerURL,
-			ClusterID:      opts.ClusterID,
-			ProjectID:      opts.ProjectID,
-			StackName:      opts.StackName,
-			DefaultBranch:  opts.DefaultBranch,
-			SecretName:     opts.SecretName,
-			PorterYamlPath: opts.PorterYamlPath,
-			Preview:        false,
+			ServerURL:          opts.ServerURL,
+			ClusterID:          opts.ClusterID,
+			ProjectID:          opts.ProjectID,
+			StackName:          opts.StackName,
+			DefaultBranch:      opts.DefaultBranch,
+			SecretName:         opts.SecretName,
+			PorterYamlPath:     opts.PorterYamlPath,
+			DeploymentTargetId: opts.DeploymentTargetId,
+			Preview:            false,
 		})
 		if err != nil {
 			return err
@@ -186,6 +189,7 @@ func getStackApplyActionYAML(opts *GetStackApplyActionYAMLOpts) ([]byte, error)
 			opts.PorterYamlPath,
 			opts.ProjectID,
 			opts.ClusterID,
+			opts.DeploymentTargetId,
 			opts.Preview,
 		),
 	}

+ 18 - 11
internal/integrations/ci/actions/steps.go

@@ -81,6 +81,7 @@ func getCreatePreviewEnvStep(
 func getDeployStackStep(
 	serverURL, porterTokenSecretName, stackName, actionVersion, porterYamlPath string,
 	projectID, clusterID uint,
+	deploymentTargetId string,
 	preview bool,
 ) GithubActionYAMLStep {
 	command := "exec porter apply"
@@ -97,18 +98,24 @@ func getDeployStackStep(
 		name = "Build and deploy preview environment"
 	}
 
+	env := map[string]string{
+		"PORTER_CLUSTER":    fmt.Sprintf("%d", clusterID),
+		"PORTER_HOST":       serverURL,
+		"PORTER_PROJECT":    fmt.Sprintf("%d", projectID),
+		"PORTER_TOKEN":      fmt.Sprintf("${{ secrets.%s }}", porterTokenSecretName),
+		"PORTER_TAG":        "${{ steps.vars.outputs.sha_short }}",
+		"PORTER_STACK_NAME": stackName,
+		"PORTER_PR_NUMBER":  "${{ github.event.number }}",
+	}
+
+	if deploymentTargetId != "" {
+		env["PORTER_DEPLOYMENT_TARGET_ID"] = deploymentTargetId
+	}
+
 	return GithubActionYAMLStep{
-		Name: name,
-		Run:  command,
-		Env: map[string]string{
-			"PORTER_CLUSTER":    fmt.Sprintf("%d", clusterID),
-			"PORTER_HOST":       serverURL,
-			"PORTER_PROJECT":    fmt.Sprintf("%d", projectID),
-			"PORTER_TOKEN":      fmt.Sprintf("${{ secrets.%s }}", porterTokenSecretName),
-			"PORTER_TAG":        "${{ steps.vars.outputs.sha_short }}",
-			"PORTER_STACK_NAME": stackName,
-			"PORTER_PR_NUMBER":  "${{ github.event.number }}",
-		},
+		Name:    name,
+		Run:     command,
+		Env:     env,
 		Timeout: 30,
 	}
 }