소스 검색

refactor pr deployment details and api to depend only on project/cluster

Alexander Belanger 4 년 전
부모
커밋
bead8f9cf1

+ 46 - 0
api/server/handlers/environment/get_deployment_by_cluster.go

@@ -0,0 +1,46 @@
+package environment
+
+import (
+	"net/http"
+
+	"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"
+)
+
+type GetDeploymentByClusterHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewGetDeploymentByClusterHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *GetDeploymentByClusterHandler {
+	return &GetDeploymentByClusterHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+func (c *GetDeploymentByClusterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	project, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+	cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
+
+	request := &types.GetDeploymentRequest{}
+
+	if ok := c.DecodeAndValidate(w, r, request); !ok {
+		return
+	}
+
+	depl, err := c.Repo().Environment().ReadDeploymentByCluster(project.ID, cluster.ID, request.Namespace)
+
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	}
+
+	c.WriteResult(w, r, depl.ToDeploymentType())
+}

+ 29 - 0
api/server/router/cluster.go

@@ -316,6 +316,35 @@ func getClusterRoutes(
 		Router:   r,
 		Router:   r,
 	})
 	})
 
 
+	// GET /api/projects/{project_id}/clusters/{cluster_id}/deployment -> environment.NewGetDeploymentByClusterHandler
+	getDeploymentEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbGet,
+			Method: types.HTTPVerbGet,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/deployment",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+				types.ClusterScope,
+			},
+		},
+	)
+
+	getDeploymentHandler := environment.NewGetDeploymentByClusterHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &Route{
+		Endpoint: getDeploymentEndpoint,
+		Handler:  getDeploymentHandler,
+		Router:   r,
+	})
+
 	// GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces -> cluster.NewClusterListNamespacesHandler
 	// GET /api/projects/{project_id}/clusters/{cluster_id}/namespaces -> cluster.NewClusterListNamespacesHandler
 	listNamespacesEndpoint := factory.NewAPIEndpoint(
 	listNamespacesEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{
 		&types.APIRequestMetadata{

+ 3 - 3
dashboard/src/main/home/cluster-dashboard/chart/ChartList.tsx

@@ -119,12 +119,12 @@ const ChartList: React.FunctionComponent<Props> = ({
         setCharts((currentCharts) => {
         setCharts((currentCharts) => {
           switch (event.event_type) {
           switch (event.event_type) {
             case "ADD":
             case "ADD":
-              if (currentCharts.find(isSameChart)) {
+              if (currentCharts?.find(isSameChart)) {
                 return currentCharts;
                 return currentCharts;
               }
               }
-              return currentCharts.concat(newChart);
+              return currentCharts?.concat(newChart);
             case "UPDATE":
             case "UPDATE":
-              return currentCharts.map((chart) => {
+              return currentCharts?.map((chart) => {
                 if (isSameChart(chart) && newChart.version >= chart.version) {
                 if (isSameChart(chart) && newChart.version >= chart.version) {
                   return newChart;
                   return newChart;
                 }
                 }

+ 16 - 68
dashboard/src/main/home/cluster-dashboard/dashboard/preview-environments/EnvironmentDetail.tsx

@@ -16,7 +16,7 @@ import { integrationList } from "shared/common";
 const EnvironmentDetail = () => {
 const EnvironmentDetail = () => {
   const { params } = useRouteMatch<{ namespace: string }>();
   const { params } = useRouteMatch<{ namespace: string }>();
   const context = useContext(Context);
   const context = useContext(Context);
-  const [environment, setEnvironment] = useState<PRDeployment>(null);
+  const [prDeployment, setPRDeployment] = useState<PRDeployment>(null);
   const [hasError, setHasError] = useState(false);
   const [hasError, setHasError] = useState(false);
   const [isLoading, setIsLoading] = useState(false);
   const [isLoading, setIsLoading] = useState(false);
   const [showRepoTooltip, setShowRepoTooltip] = useState(false);
   const [showRepoTooltip, setShowRepoTooltip] = useState(false);
@@ -28,15 +28,11 @@ const EnvironmentDetail = () => {
   const { search } = useLocation();
   const { search } = useLocation();
   let searchParams = new URLSearchParams(search);
   let searchParams = new URLSearchParams(search);
 
 
-  // const useQuery = () => {
-  //   return React.useMemo(() => , [search]);
-  // };
-
-  const getDeployment = (environment: Environment) => {
+  useEffect(() => {
     let isSubscribed = true;
     let isSubscribed = true;
 
 
     api
     api
-      .getPRDeployment(
+      .getPRDeploymentByCluster(
         "<token>",
         "<token>",
         {
         {
           namespace: params.namespace,
           namespace: params.namespace,
@@ -44,9 +40,6 @@ const EnvironmentDetail = () => {
         {
         {
           project_id: currentProject.id,
           project_id: currentProject.id,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          git_installation_id: environment.git_installation_id,
-          git_repo_owner: environment.git_repo_owner,
-          git_repo_name: environment.git_repo_name,
         }
         }
       )
       )
       .then(({ data }) => {
       .then(({ data }) => {
@@ -54,13 +47,13 @@ const EnvironmentDetail = () => {
           return;
           return;
         }
         }
 
 
-        setEnvironment(data);
+        setPRDeployment(data);
       })
       })
       .catch((err) => {
       .catch((err) => {
         console.error(err);
         console.error(err);
         if (isSubscribed) {
         if (isSubscribed) {
           setHasError(true);
           setHasError(true);
-          setEnvironment(null);
+          setPRDeployment(null);
         }
         }
       })
       })
       .finally(() => {
       .finally(() => {
@@ -68,58 +61,13 @@ const EnvironmentDetail = () => {
           setIsLoading(false);
           setIsLoading(false);
         }
         }
       });
       });
-  };
-
-  useEffect(() => {
-    let isSubscribed = true;
-
-    let environment_id = parseInt(searchParams.get("environment_id"));
-
-    // find the git installation id
-    api
-      .listEnvironments(
-        "<token>",
-        {
-          namespace: params.namespace,
-        },
-        {
-          project_id: currentProject.id,
-          cluster_id: currentCluster.id,
-        }
-      )
-      .then(({ data }) => {
-        if (!isSubscribed) {
-          return;
-        }
-
-        if (!Array.isArray(data)) {
-          throw Error("Data is not an array");
-        }
-
-        data.forEach((d) => {
-          if (d.id == environment_id) {
-            getDeployment(d);
-          }
-        });
-      })
-      .catch((err) => {
-        console.error(err);
-        if (isSubscribed) {
-          setHasError(true);
-          setEnvironment(null);
-        }
-      });
-
-    return () => {
-      isSubscribed = false;
-    };
   }, [params]);
   }, [params]);
 
 
-  if (!environment) {
+  if (!prDeployment) {
     return <Loading />;
     return <Loading />;
   }
   }
 
 
-  let repository = `${environment.gh_repo_owner}/${environment.gh_repo_name}`;
+  let repository = `${prDeployment.gh_repo_owner}/${prDeployment.gh_repo_name}`;
 
 
   return (
   return (
     <StyledExpandedChart>
     <StyledExpandedChart>
@@ -128,7 +76,7 @@ const EnvironmentDetail = () => {
           <BackButtonImg src={backArrow} />
           <BackButtonImg src={backArrow} />
         </BackButton>
         </BackButton>
         <Title icon={pr_icon} iconWidth="25px">
         <Title icon={pr_icon} iconWidth="25px">
-          {environment.gh_pr_name}
+          {prDeployment.gh_pr_name}
           <DeploymentImageContainer>
           <DeploymentImageContainer>
             <DeploymentTypeIcon src={integrationList.repo.icon} />
             <DeploymentTypeIcon src={integrationList.repo.icon} />
             <RepositoryName
             <RepositoryName
@@ -144,25 +92,25 @@ const EnvironmentDetail = () => {
             {showRepoTooltip && <Tooltip>{repository}</Tooltip>}
             {showRepoTooltip && <Tooltip>{repository}</Tooltip>}
           </DeploymentImageContainer>
           </DeploymentImageContainer>
           <TagWrapper>
           <TagWrapper>
-            Namespace <NamespaceTag>{environment.namespace}</NamespaceTag>
+            Namespace <NamespaceTag>{params.namespace}</NamespaceTag>
           </TagWrapper>
           </TagWrapper>
         </Title>
         </Title>
         <InfoWrapper>
         <InfoWrapper>
-          {environment.subdomain && (
-            <PRLink to={environment.subdomain} target="_blank">
+          {prDeployment.subdomain && (
+            <PRLink to={prDeployment.subdomain} target="_blank">
               <i className="material-icons">link</i>
               <i className="material-icons">link</i>
-              {environment.subdomain}
+              {prDeployment.subdomain}
             </PRLink>
             </PRLink>
           )}
           )}
         </InfoWrapper>
         </InfoWrapper>
         <Flex>
         <Flex>
           <Status>
           <Status>
-            <StatusDot status={environment.status} />
-            {capitalize(environment.status)}
+            <StatusDot status={prDeployment.status} />
+            {capitalize(prDeployment.status)}
           </Status>
           </Status>
           <Dot>•</Dot>
           <Dot>•</Dot>
           <GHALink
           <GHALink
-            to={`https://github.com/${repository}/pull/${environment.pull_request_id}`}
+            to={`https://github.com/${repository}/pull/${prDeployment.pull_request_id}`}
             target="_blank"
             target="_blank"
           >
           >
             <img src={github} /> GitHub
             <img src={github} /> GitHub
@@ -177,7 +125,7 @@ const EnvironmentDetail = () => {
           currentCluster={context.currentCluster}
           currentCluster={context.currentCluster}
           currentView="cluster-dashboard"
           currentView="cluster-dashboard"
           sortType="Newest"
           sortType="Newest"
-          namespace={environment.namespace}
+          namespace={params.namespace}
           disableBottomPadding
           disableBottomPadding
         />
         />
       </ChartListWrapper>
       </ChartListWrapper>

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

@@ -350,6 +350,20 @@ const getPRDeploymentList = baseApi<
   return `/api/projects/${project_id}/clusters/${cluster_id}/deployments`;
   return `/api/projects/${project_id}/clusters/${cluster_id}/deployments`;
 });
 });
 
 
+const getPRDeploymentByCluster = baseApi<
+  {
+    namespace: string;
+  },
+  {
+    cluster_id: number;
+    project_id: number;
+  }
+>("GET", (pathParams) => {
+  const { cluster_id, project_id } = pathParams;
+
+  return `/api/projects/${project_id}/clusters/${cluster_id}/deployment`;
+});
+
 const getPRDeployment = baseApi<
 const getPRDeployment = baseApi<
   {
   {
     namespace: string;
     namespace: string;
@@ -1350,6 +1364,7 @@ export default {
   getClusterNode,
   getClusterNode,
   getConfigMap,
   getConfigMap,
   getPRDeploymentList,
   getPRDeploymentList,
+  getPRDeploymentByCluster,
   getPRDeployment,
   getPRDeployment,
   getGHAWorkflowTemplate,
   getGHAWorkflowTemplate,
   getGitRepoList,
   getGitRepoList,

+ 1 - 0
internal/repository/environment.go

@@ -9,6 +9,7 @@ type EnvironmentRepository interface {
 	DeleteEnvironment(env *models.Environment) (*models.Environment, error)
 	DeleteEnvironment(env *models.Environment) (*models.Environment, error)
 	CreateDeployment(deployment *models.Deployment) (*models.Deployment, error)
 	CreateDeployment(deployment *models.Deployment) (*models.Deployment, error)
 	ReadDeployment(environmentID uint, namespace string) (*models.Deployment, error)
 	ReadDeployment(environmentID uint, namespace string) (*models.Deployment, error)
+	ReadDeploymentByCluster(projectID, clusterID uint, namespace string) (*models.Deployment, error)
 	ListDeploymentsByCluster(projectID, clusterID uint) ([]*models.Deployment, error)
 	ListDeploymentsByCluster(projectID, clusterID uint) ([]*models.Deployment, error)
 	ListDeployments(environmentID uint) ([]*models.Deployment, error)
 	ListDeployments(environmentID uint) ([]*models.Deployment, error)
 	UpdateDeployment(deployment *models.Deployment) (*models.Deployment, error)
 	UpdateDeployment(deployment *models.Deployment) (*models.Deployment, error)

+ 15 - 1
internal/repository/gorm/environment.go

@@ -76,10 +76,24 @@ func (repo *EnvironmentRepository) ReadDeployment(environmentID uint, namespace
 	return depl, nil
 	return depl, nil
 }
 }
 
 
+func (repo *EnvironmentRepository) ReadDeploymentByCluster(projectID, clusterID uint, namespace string) (*models.Deployment, error) {
+	depl := &models.Deployment{}
+
+	if err := repo.db.
+		Order("deployments.id asc").
+		Joins("INNER JOIN environments ON environments.id = deployments.environment_id").
+		Where("environments.project_id = ? AND environments.cluster_id = ? AND environments.deleted_at IS NULL AND namespace = ?", projectID, clusterID, depl.Namespace).
+		Find(&depl).Error; err != nil {
+		return nil, err
+	}
+
+	return depl, nil
+}
+
 func (repo *EnvironmentRepository) ListDeploymentsByCluster(projectID, clusterID uint) ([]*models.Deployment, error) {
 func (repo *EnvironmentRepository) ListDeploymentsByCluster(projectID, clusterID uint) ([]*models.Deployment, error) {
 	depls := make([]*models.Deployment, 0)
 	depls := make([]*models.Deployment, 0)
 
 
-	if err := repo.db.Debug().
+	if err := repo.db.
 		Order("deployments.id asc").
 		Order("deployments.id asc").
 		Joins("INNER JOIN environments ON environments.id = deployments.environment_id").
 		Joins("INNER JOIN environments ON environments.id = deployments.environment_id").
 		Where("environments.project_id = ? AND environments.cluster_id = ? AND environments.deleted_at IS NULL", projectID, clusterID).
 		Where("environments.project_id = ? AND environments.cluster_id = ? AND environments.deleted_at IS NULL", projectID, clusterID).

+ 4 - 0
internal/repository/test/environment.go

@@ -43,6 +43,10 @@ func (repo *EnvironmentRepository) ReadDeployment(environmentID uint, namespace
 	panic("unimplemented")
 	panic("unimplemented")
 }
 }
 
 
+func (repo *EnvironmentRepository) ReadDeploymentByCluster(projectID, clusterID uint, namespace string) (*models.Deployment, error) {
+	panic("unimplemented")
+}
+
 func (repo *EnvironmentRepository) ListDeploymentsByCluster(projectID, clusterID uint) ([]*models.Deployment, error) {
 func (repo *EnvironmentRepository) ListDeploymentsByCluster(projectID, clusterID uint) ([]*models.Deployment, error) {
 	panic("unimplemented")
 	panic("unimplemented")
 }
 }