Explorar el Código

enforce uniqueness on stack creation

Justin Rhee hace 3 años
padre
commit
3affaeb85d

+ 12 - 0
api/server/handlers/stacks/create_porter_app.go

@@ -1,11 +1,13 @@
 package stacks
 
 import (
+	"fmt"
 	"net/http"
 
 	"github.com/porter-dev/porter/api/server/authz"
 	"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"
@@ -38,6 +40,16 @@ func (c *CreatePorterAppHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques
 		return
 	}
 
+	existing, err := c.Repo().PorterApp().ReadPorterAppByName(cluster.ID, request.Name)
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(err))
+		return
+	} else if existing.Name != "" {
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(
+			fmt.Errorf("porter app with name %s already exists in this environment", existing.Name), http.StatusForbidden))
+		return
+	}
+
 	app := &models.PorterApp{
 		Name:      request.Name,
 		ClusterID: cluster.ID,

+ 2 - 11
dashboard/src/main/home/app-dashboard/new-app-flow/NewAppFlow.tsx

@@ -1,24 +1,19 @@
-import React, { useEffect, useState, useContext, useMemo } from "react";
+import React, { useState, useContext } from "react";
 import styled from "styled-components";
 import { RouteComponentProps, withRouter } from "react-router";
 import _ from "lodash";
 import yaml from "js-yaml";
 
-import { hardcodedNames, hardcodedIcons } from "shared/hardcodedNameDict";
 import { Context } from "shared/Context";
 import api from "shared/api";
-import { pushFiltered } from "shared/routing";
 import web from "assets/web.png";
 
 import Back from "components/porter/Back";
 import DashboardHeader from "../../cluster-dashboard/DashboardHeader";
-import Link from "components/porter/Link";
 import Text from "components/porter/Text";
 import Spacer from "components/porter/Spacer";
 import Input from "components/porter/Input";
 import VerticalSteps from "components/porter/VerticalSteps";
-import PorterFormWrapper from "components/porter-form/PorterFormWrapper";
-import Placeholder from "components/Placeholder";
 import Button from "components/porter/Button";
 import SourceSelector, { SourceType } from "./SourceSelector";
 import SourceSettings from "./SourceSettings";
@@ -26,12 +21,8 @@ import Services from "./Services";
 import EnvGroupArray, {
   KeyValueType,
 } from "main/home/cluster-dashboard/env-groups/EnvGroupArray";
-import Select from "components/porter/Select";
 import GithubActionModal from "./GithubActionModal";
 import {
-  ActionConfigType,
-  FullActionConfigType,
-  FullGithubActionConfigType,
   GithubActionConfigType,
 } from "shared/types";
 import Error from "components/porter/Error";
@@ -201,7 +192,7 @@ const NewAppFlow: React.FC<Props> = ({ ...props }) => {
         currentProject.id == null ||
         currentCluster.id == null
       ) {
-        throw new Error("Project or cluster not found");
+        throw ("Project or cluster not found");
       }
 
       // validate form data

+ 1 - 1
dashboard/src/main/home/integrations/IntegrationList.tsx

@@ -259,7 +259,7 @@ const Placeholder = styled.div`
   justify-content: center;
   color: #aaaabb;
   border-radius: 5px;
-  background: #26292e;
+  background: ${({ theme }) => theme.fg};
   border: 1px solid #494b4f;
 `;
 

+ 1 - 1
dashboard/src/main/home/integrations/Integrations.tsx

@@ -51,7 +51,7 @@ const Integrations: React.FC<PropsType> = (props) => {
                 >
                   {integrationList[integration].label}
                 </TitleSection>
-                <Buffer />
+                <Spacer y={1} />
                 <CreateIntegrationForm
                   integrationName={integration}
                   closeForm={() => {

+ 1 - 1
dashboard/src/main/home/integrations/SlackIntegrationList.tsx

@@ -107,7 +107,7 @@ const Placeholder = styled.div`
   justify-content: center;
   color: #aaaabb;
   border-radius: 5px;
-  background: #26292e;
+  background: ${({ theme }) => theme.fg};
   border: 1px solid #494b4f;
 `;
 

+ 1 - 1
dashboard/src/main/home/integrations/create-integration/ECRForm.tsx

@@ -132,7 +132,7 @@ ECRForm.contextType = Context;
 const CredentialWrapper = styled.div`
   padding: 30px;
   border-radius: 5px;
-  background: #26292e;
+  background: ${({ theme }) => theme.fg}};
   border: 1px solid #494b4f;
   margin-bottom: 30px;
 `;

+ 1 - 1
internal/repository/gorm/porter_app.go

@@ -37,7 +37,7 @@ func (repo *PorterAppRepository) ListPorterAppByClusterID(clusterID uint) ([]*mo
 func (repo *PorterAppRepository) ReadPorterAppByName(clusterID uint, name string) (*models.PorterApp, error) {
 	app := &models.PorterApp{}
 
-	if err := repo.db.Where("cluster_id = ? AND name = ?", clusterID, name).First(&app).Error; err != nil {
+	if err := repo.db.Where("cluster_id = ? AND name = ?", clusterID, name).Limit(1).Find(&app).Error; err != nil {
 		return nil, err
 	}