Stefan McShane 3 лет назад
Родитель
Сommit
86ceca436d

+ 51 - 0
api/server/handlers/api_contract/list.go

@@ -0,0 +1,51 @@
+package api_contract
+
+import (
+	"fmt"
+	"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 APIContractRevisionListHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewAPIContractRevisionListHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *APIContractRevisionListHandler {
+	return &APIContractRevisionListHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+// APIContractListRequest contains all parameters required for filtering APIContractRevisions
+type APIContractRevisionsListRequest struct {
+	ProjectID uint `json:"project_id"`
+	ClusterID uint `json:"cluster_id"`
+}
+
+// ServeHTTP returns a list of Porter API contract revisions for a given project.
+// If clusterID is also given, it will list by project_id, cluster_id
+func (c *APIContractRevisionListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)
+
+	ctx := r.Context()
+
+	revisions, err := c.Config().Repo.APIContractRevisioner().List(ctx, proj.ID, 0)
+	if err != nil {
+		e := fmt.Errorf("error creating new capi config: %w", err)
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
+		return
+	}
+
+	w.WriteHeader(http.StatusCreated)
+	c.WriteResult(w, r, revisions)
+}

+ 107 - 0
api/server/handlers/api_contract/update.go

@@ -0,0 +1,107 @@
+package api_contract
+
+import (
+	"encoding/base64"
+	"fmt"
+	"net/http"
+
+	"github.com/golang/protobuf/jsonpb"
+	"github.com/nats-io/nats.go"
+	porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
+	"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"
+	"google.golang.org/protobuf/proto"
+)
+
+type APIContractUpdateHandler struct {
+	handlers.PorterHandlerReadWriter
+}
+
+func NewAPIContractUpdateHandler(
+	config *config.Config,
+	decoderValidator shared.RequestDecoderValidator,
+	writer shared.ResultWriter,
+) *APIContractUpdateHandler {
+	return &APIContractUpdateHandler{
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+	}
+}
+
+// ServeHTTP parses the Porter API contract for validity, and forwards the requests for handling on to another service
+// For now, this handling cluster creation only, by insertin a row into the cluster table in order to create an ID for this cluster, as well as stores the raw request JSON for updating later
+func (c *APIContractUpdateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	var apiContract porterv1.Contract
+	ctx := r.Context()
+
+	if ok := c.DecodeAndValidate(w, r, &apiContract); !ok {
+		return
+	}
+
+	// handle cluster object for now
+	cl := apiContract.Cluster
+
+	if cl.ClusterId == 0 {
+		dbClusterInput := models.Cluster{
+			ProjectID:                         uint(cl.ProjectId),
+			Status:                            types.UpdatingUnavailable,
+			ProvisionedBy:                     "CAPI",
+			CloudProvider:                     "AWS",
+			CloudProviderCredentialIdentifier: cl.CloudProviderCredentialsId,
+			Name:                              cl.GetEksKind().ClusterName,
+		}
+		dbCluster, err := c.Config().Repo.Cluster().CreateCluster(&dbClusterInput)
+		if err != nil {
+			e := fmt.Errorf("error creating new cluster: %w", err)
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
+			return
+		}
+		apiContract.Cluster.ClusterId = int32(dbCluster.ID)
+	}
+
+	var jpbm jsonpb.Marshaler
+	by, err := jpbm.MarshalToString(&apiContract)
+	if err != nil {
+		e := fmt.Errorf("error marshalling api contract: %w", err)
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
+		return
+	}
+	b64 := base64.StdEncoding.EncodeToString([]byte(by))
+
+	apiContractRevision := models.APIContractRevision{
+		ClusterID:      int(cl.ClusterId),
+		ProjectID:      int(cl.ProjectId),
+		Base64Contract: string(b64),
+	}
+
+	contractRevision, err := c.Config().Repo.APIContractRevisioner().Insert(ctx, apiContractRevision)
+	if err != nil {
+		e := fmt.Errorf("error creating new capi config: %w", err)
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
+		return
+	}
+
+	// This gates the cluster actually being provisioned by CAPI
+	// This can be removed whenever we are able to run NATS and CCP locally, easier
+	kubeBy, err := proto.Marshal(&apiContract)
+	if err != nil {
+		e := fmt.Errorf("error marshalling proto: %w", err)
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
+		return
+	}
+	if !c.Config().DisableCAPIProvisioner {
+		subject := "porter.system.infrastructure.update"
+		_, err = c.Config().NATS.JetStream.Publish(subject, kubeBy, nats.Context(ctx))
+		if err != nil {
+			e := fmt.Errorf("error publishing cluster for creation: %w", err)
+			c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
+			return
+		}
+	}
+
+	w.WriteHeader(http.StatusCreated)
+	c.WriteResult(w, r, contractRevision)
+}

+ 1 - 1
api/server/handlers/infra/forms.go

@@ -1252,4 +1252,4 @@ tabs:
       required: true
       placeholder: my-cluster
       variable: cluster_name
-`
+`

+ 0 - 155
api/server/handlers/project/create_cluster.go

@@ -1,155 +0,0 @@
-package project
-
-import (
-	"encoding/base64"
-	"encoding/json"
-	"fmt"
-	"net/http"
-
-	"github.com/nats-io/nats.go"
-	porterv1 "github.com/porter-dev/api-contracts/generated/go/porter/v1"
-	"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"
-	"google.golang.org/protobuf/proto"
-)
-
-type CreateClusterHandler struct {
-	handlers.PorterHandlerReadWriter
-}
-
-func NewProvisionClusterHandler(
-	config *config.Config,
-	decoderValidator shared.RequestDecoderValidator,
-	writer shared.ResultWriter,
-) *CreateClusterHandler {
-	return &CreateClusterHandler{
-		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
-	}
-}
-
-// ServeHTTP creates a CAPI cluster by adding the configuration to a NATS stream
-// This inserts a row into the cluster table in order to create an ID for this cluster, as well as stores the raw request JSON for updating later
-func (c *CreateClusterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	var capiClusterReq types.CAPIClusterRequest
-	ctx := r.Context()
-
-	if ok := c.DecodeAndValidate(w, r, &capiClusterReq); !ok {
-		return
-	}
-
-	if capiClusterReq.ClusterID == 0 {
-		dbCluster := models.Cluster{
-			ProjectID:                         uint(capiClusterReq.ProjectID),
-			Status:                            types.UpdatingUnavailable,
-			ProvisionedBy:                     "CAPI",
-			CloudProvider:                     "AWS",
-			CloudProviderCredentialIdentifier: capiClusterReq.CloudProviderCredentialsID,
-			Name:                              capiClusterReq.ClusterSettings.ClusterName,
-		}
-		cl, err := c.Config().Repo.Cluster().CreateCluster(&dbCluster)
-		if err != nil {
-			e := fmt.Errorf("error creating new cluster: %w", err)
-			c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
-			return
-		}
-		capiClusterReq.ClusterID = int64(cl.ID)
-	}
-
-	by, err := json.Marshal(capiClusterReq)
-	if err != nil {
-		e := fmt.Errorf("error marshalling capi config: %w", err)
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
-		return
-	}
-	b64 := base64.StdEncoding.EncodeToString(by)
-
-	capiConfig := models.CAPIConfig{
-		ClusterID:         int(capiClusterReq.ClusterID),
-		ProjectID:         int(capiClusterReq.ProjectID),
-		Base64RequestJSON: string(b64),
-	}
-
-	_, err = c.Config().Repo.CAPIConfigRepository().Insert(ctx, capiConfig)
-	if err != nil {
-		e := fmt.Errorf("error creating new capi config: %w", err)
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
-		return
-	}
-
-	capiCluster := porterv1.Kubernetes{
-		ProjectId: int32(capiClusterReq.ProjectID),
-		ClusterId: int32(capiClusterReq.ClusterID),
-	}
-	if capiClusterReq.CloudProvider == "aws" {
-		capiCluster.CloudProvider = porterv1.EnumCloudProvider_ENUM_CLOUD_PROVIDER_AWS
-		capiCluster.Kind = porterv1.EnumKubernetesKind_ENUM_KUBERNETES_KIND_EKS
-		capiCluster.CloudProviderCredentialsId = capiClusterReq.CloudProviderCredentialsID
-
-		var capiNodeGroups []*porterv1.EKSNodeGroup
-		for _, ng := range capiClusterReq.ClusterSettings.NodeGroups {
-			cng := porterv1.EKSNodeGroup{
-				InstanceType:  ng.InstanceType,
-				MinInstances:  uint32(ng.MinInstances),
-				MaxInstances:  uint32(ng.MaxInstances),
-				NodeGroupType: protoNodeGroupTypeLookup(ng.NodeGroupType),
-			}
-			capiNodeGroups = append(capiNodeGroups, &cng)
-		}
-
-		capiCluster.KindValues = &porterv1.Kubernetes_EksKind{
-			EksKind: &porterv1.EKS{
-				ClusterName:    capiClusterReq.ClusterSettings.ClusterName,
-				CidrRange:      capiClusterReq.ClusterSettings.CIDRRange,
-				ClusterVersion: capiClusterReq.ClusterSettings.ClusterVersion,
-				Region:         capiClusterReq.ClusterSettings.Region,
-				NodeGroups:     capiNodeGroups,
-			},
-		}
-	}
-
-	// This gates the cluster actually being provisioned by CAPI
-	// This can be removed whenever we are able to run NATS and CCP locally, easier
-	if !c.Config().DisableCAPIProvisioner {
-		kubeBy, err := proto.Marshal(&capiCluster)
-		if err != nil {
-			e := fmt.Errorf("error marshalling proto: %w", err)
-			c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
-			return
-		}
-
-		subject := "porter.system.infrastructure.update"
-		_, err = c.Config().NATS.JetStream.Publish(subject, kubeBy, nats.Context(ctx))
-		if err != nil {
-			e := fmt.Errorf("error publishing cluster for creation: %w", err)
-			c.HandleAPIError(w, r, apierrors.NewErrInternal(e))
-			return
-		}
-	}
-
-	w.WriteHeader(http.StatusCreated)
-	c.WriteResult(w, r, types.Cluster{
-		ID: uint(capiClusterReq.ClusterID),
-	})
-
-}
-
-var (
-	apiNodeGroupToProtoNodeGroup = map[string]porterv1.NodeGroupType{
-		"SYSTEM":      porterv1.NodeGroupType_NODE_GROUP_TYPE_SYSTEM,
-		"MONITORING":  porterv1.NodeGroupType_NODE_GROUP_TYPE_MONITORING,
-		"APPLICATION": porterv1.NodeGroupType_NODE_GROUP_TYPE_APPLICATION,
-		"CUSTOM":      porterv1.NodeGroupType_NODE_GROUP_TYPE_CUSTOM,
-	}
-)
-
-// protoNodeGroupTypeLookup is a helper function for finding a nodegroup, and returning a default if its not found
-func protoNodeGroupTypeLookup(apiNodeGroup string) porterv1.NodeGroupType {
-	if ngt, ok := apiNodeGroupToProtoNodeGroup[apiNodeGroup]; ok {
-		return ngt
-	}
-	return porterv1.NodeGroupType_NODE_GROUP_TYPE_CUSTOM
-}

+ 35 - 6
api/server/router/project.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 
 	"github.com/go-chi/chi"
+	apiContract "github.com/porter-dev/porter/api/server/handlers/api_contract"
 	"github.com/porter-dev/porter/api/server/handlers/api_token"
 	"github.com/porter-dev/porter/api/server/handlers/billing"
 	"github.com/porter-dev/porter/api/server/handlers/cluster"
@@ -1261,14 +1262,14 @@ func getProjectRoutes(
 		Router:   r,
 	})
 
-	// POST /api/project/{project_id}/provision/cluster -> project.NewProvisionClusterHandler
-	provisionClusterEndpoint := factory.NewAPIEndpoint(
+	// POST /api/project/{project_id}/contract -> apiContract.NewAPIContractUpdateHandler
+	updateAPIContractEndpoint := factory.NewAPIEndpoint(
 		&types.APIRequestMetadata{
 			Verb:   types.APIVerbCreate,
 			Method: types.HTTPVerbPost,
 			Path: &types.Path{
 				Parent:       basePath,
-				RelativePath: relPath + "/provision/cluster",
+				RelativePath: relPath + "/contract",
 			},
 			Scopes: []types.PermissionScope{
 				types.UserScope,
@@ -1277,15 +1278,43 @@ func getProjectRoutes(
 		},
 	)
 
-	provisionClusterHandler := project.NewProvisionClusterHandler(
+	updateAPIContractHandler := apiContract.NewAPIContractUpdateHandler(
 		config,
 		factory.GetDecoderValidator(),
 		factory.GetResultWriter(),
 	)
 
 	routes = append(routes, &router.Route{
-		Endpoint: provisionClusterEndpoint,
-		Handler:  provisionClusterHandler,
+		Endpoint: updateAPIContractEndpoint,
+		Handler:  updateAPIContractHandler,
+		Router:   r,
+	})
+
+	// GET /api/project/{project_id}/contracts -> apiContract.NewAPIContractUpdateHandler
+	listAPIContractRevisionsEndpoint := factory.NewAPIEndpoint(
+		&types.APIRequestMetadata{
+			Verb:   types.APIVerbCreate,
+			Method: types.HTTPVerbPost,
+			Path: &types.Path{
+				Parent:       basePath,
+				RelativePath: relPath + "/contracts",
+			},
+			Scopes: []types.PermissionScope{
+				types.UserScope,
+				types.ProjectScope,
+			},
+		},
+	)
+
+	listAPIContractRevisionHandler := apiContract.NewAPIContractRevisionListHandler(
+		config,
+		factory.GetDecoderValidator(),
+		factory.GetResultWriter(),
+	)
+
+	routes = append(routes, &router.Route{
+		Endpoint: listAPIContractRevisionsEndpoint,
+		Handler:  listAPIContractRevisionHandler,
 		Router:   r,
 	})
 

+ 0 - 26
api/types/cluster.go

@@ -310,29 +310,3 @@ type ListClusterResponse []*Cluster
 type CreateClusterCandidateResponse []*ClusterCandidate
 
 type ListClusterCandidateResponse []*ClusterCandidate
-
-// CAPIClusterRequest is the object that contains all information for creating a CAPI Cluster
-type CAPIClusterRequest struct {
-	ProjectID                  int64           `json:"project_id"`
-	ClusterID                  int64           `json:"cluster_id"`
-	CloudProvider              string          `json:"cloud_provider"`
-	CloudProviderCredentialsID string          `json:"cloud_provider_credentials_id"`
-	ClusterSettings            ClusterSettings `json:"cluster_settings"`
-}
-
-// ClusterSettings contains all EKS cluster settings for a CAPI cluster
-type ClusterSettings struct {
-	ClusterName    string      `json:"cluster_name"`
-	ClusterVersion string      `json:"cluster_version"`
-	CIDRRange      string      `json:"cidr_range"`
-	Region         string      `json:"region"`
-	NodeGroups     []NodeGroup `json:"node_groups"`
-}
-
-// NodeGroup contains all EKS node group settings for a CAPI cluster
-type NodeGroup struct {
-	InstanceType  string `json:"instance_type"`
-	MinInstances  int64  `json:"min_instances"`
-	MaxInstances  int64  `json:"max_instances"`
-	NodeGroupType string `json:"node_group_type"`
-}

+ 1 - 1
go.mod

@@ -74,7 +74,7 @@ require (
 	github.com/glebarez/sqlite v1.6.0
 	github.com/nats-io/nats.go v1.24.0
 	github.com/open-policy-agent/opa v0.44.0
-	github.com/porter-dev/api-contracts v0.0.10
+	github.com/porter-dev/api-contracts v0.0.23
 	github.com/santhosh-tekuri/jsonschema/v5 v5.0.1
 	github.com/stefanmcshane/helm v0.0.0-20221213002717-88a4a2c6e77d
 	github.com/xanzy/go-gitlab v0.68.0

+ 4 - 0
go.sum

@@ -1468,6 +1468,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/polyfloyd/go-errorlint v0.0.0-20210722154253-910bb7978349/go.mod h1:wi9BfjxjF/bwiZ701TzmfKu6UKC357IOAtNr0Td0Lvw=
 github.com/porter-dev/api-contracts v0.0.10 h1:TIlyVtrufoJh9mnbOGlIuf1w99/8YWppBVzFWcRHI8c=
 github.com/porter-dev/api-contracts v0.0.10/go.mod h1:qr2L58mJLr5DUGV5OPw3REiSrQvJq6TgkKyEWP95dyU=
+github.com/porter-dev/api-contracts v0.0.22 h1:71uJjDDFUJ++XR98weglbKHm+ZMaIJB+dLD7ic2drgU=
+github.com/porter-dev/api-contracts v0.0.22/go.mod h1:qr2L58mJLr5DUGV5OPw3REiSrQvJq6TgkKyEWP95dyU=
+github.com/porter-dev/api-contracts v0.0.23 h1:WlVx4usw3zsActtZphEUhkQZijPCZNitH23uCxik/II=
+github.com/porter-dev/api-contracts v0.0.23/go.mod h1:qr2L58mJLr5DUGV5OPw3REiSrQvJq6TgkKyEWP95dyU=
 github.com/porter-dev/switchboard v0.0.0-20221019155755-67ff2bf04935 h1:hfb3nt3AJXIBbevu6ARTg9SdOkMP6WLbKBiG5hT5rcc=
 github.com/porter-dev/switchboard v0.0.0-20221019155755-67ff2bf04935/go.mod h1:xSPzqSFMQ6OSbp42fhCi4AbGbQbsm6nRvOkrblFeXU4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=

+ 34 - 0
internal/models/api_contract_revision.go

@@ -0,0 +1,34 @@
+package models
+
+import (
+	"github.com/google/uuid"
+	"gorm.io/gorm"
+)
+
+// APIContractRevision represents a revision of an API contract
+type APIContractRevision struct {
+	gorm.Model
+
+	// ID is a UUID for the APIContract
+	ID uuid.UUID `gorm:"type:uuid;primaryKey" json:"id"`
+
+	// Base64Contract is the APIContract as json encoded in base64
+	Base64Contract string `json:"base64_contract"`
+
+	// ClusterID is the ID of the cluster that the config created.
+	// This should be a foreign key, but GORM doesnt play well with FKs.
+	ClusterID int `json:"cluster_id"`
+
+	// ProjectID is the ID of the project that the config belongs to.
+	// This should be a foreign key, but GORM doesnt play well with FKs.
+	ProjectID int `json:"project_id"`
+
+	// Condition is the status of the apply that happened for this revision.
+	// Condition will contain any failure reasons for a revision, or "SUCCESS" if the revision was applied successfully.
+	Condition string `json:"condition"`
+}
+
+// TableName overrides the table name
+func (APIContractRevision) TableName() string {
+	return "api_contract_revisions"
+}

+ 0 - 33
internal/models/capi_config.go

@@ -1,33 +0,0 @@
-package models
-
-import (
-	"github.com/google/uuid"
-	"gorm.io/gorm"
-)
-
-// CAPIConfig represents a ClusterAPI base64 encoded config
-type CAPIConfig struct {
-	gorm.Model
-
-	// ID is a UUID for the CAPI Cluster's config
-	ID uuid.UUID `gorm:"type:uuid;primaryKey"`
-
-	// Base64Config is the CAPI config for a cluster, encoded in base64
-	Base64Config string
-
-	// Base64RequestJSON is the JSON submitted by the frontend, encoded in base64
-	Base64RequestJSON string
-
-	// ClusterID is the ID of the cluster that the config created.
-	// This should be a foreign key, but GORM doesnt play well with FKs.
-	ClusterID int
-
-	// ProjectID is the ID of the project that the config belongs to.
-	// This should be a foreign key, but GORM doesnt play well with FKs.
-	ProjectID int
-}
-
-// TableName overrides the table name
-func (CAPIConfig) TableName() string {
-	return "capi_configs"
-}

+ 14 - 0
internal/repository/api_contract.go

@@ -0,0 +1,14 @@
+package repository
+
+import (
+	"context"
+
+	"github.com/porter-dev/porter/internal/models"
+)
+
+// APIContractRevisioner represents queries on the api_contracts table, which stores the all the versions of an applied API contract
+type APIContractRevisioner interface {
+	Insert(ctx context.Context, conf models.APIContractRevision) (models.APIContractRevision, error)
+	// List returns a slice of APIContractRevision, sorted by created_at descending
+	List(ctx context.Context, projectID uint, clusterID uint) ([]models.APIContractRevision, error)
+}

+ 0 - 14
internal/repository/capi_config.go

@@ -1,14 +0,0 @@
-package repository
-
-import (
-	"context"
-
-	"github.com/porter-dev/porter/internal/models"
-)
-
-// CAPIConfigRepository represents queries on the capi_configs table
-type CAPIConfigRepository interface {
-	Insert(ctx context.Context, conf models.CAPIConfig) (models.CAPIConfig, error)
-	// List returns a slice of CAPIConfig, sorted by created_at descending
-	List(ctx context.Context, projectID uint, clusterID uint) ([]models.CAPIConfig, error)
-}

+ 52 - 0
internal/repository/gorm/api_contract.go

@@ -0,0 +1,52 @@
+package gorm
+
+import (
+	"context"
+
+	"github.com/google/uuid"
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
+)
+
+// APIContractRepository uses gorm.DB for querying the database
+type APIContractRepository struct {
+	db *gorm.DB
+}
+
+// NewAPIContractRevisioner creates an APIRevision connection
+func NewAPIContractRevisioner(db *gorm.DB) repository.APIContractRevisioner {
+	return &APIContractRepository{db}
+}
+
+// Insert creates a new record in the api_contract_revisions table
+func (cr APIContractRepository) Insert(ctx context.Context, conf models.APIContractRevision) (models.APIContractRevision, error) {
+	if conf.ID == uuid.Nil {
+		conf.ID = uuid.New()
+	}
+	tx := cr.db.Create(&conf)
+	if tx.Error != nil {
+		return conf, tx.Error
+	}
+	return conf, nil
+}
+
+// List returns a list of api contract revisions sorted by created date for a given projectID.
+// If clusterID is not specified (set to 0), this will return all revisions for a given project
+func (cr APIContractRepository) List(ctx context.Context, projectID uint, clusterID uint) ([]models.APIContractRevision, error) {
+	var confs []models.APIContractRevision
+
+	if clusterID == 0 {
+		tx := cr.db.Preload("api_contract_revisions").Where("project_id = ?", projectID, clusterID).Order("created_at").Find(&confs)
+		if tx.Error != nil {
+			return nil, tx.Error
+		}
+		return confs, nil
+	}
+	tx := cr.db.Preload("api_contract_revisions").Where("project_id = ? and cluster_id = ?", projectID, clusterID).Order("created_at").Find(&confs)
+	if tx.Error != nil {
+		return nil, tx.Error
+	}
+
+	return confs, nil
+}

+ 0 - 44
internal/repository/gorm/capi_config.go

@@ -1,44 +0,0 @@
-package gorm
-
-import (
-	"context"
-
-	"github.com/google/uuid"
-	"github.com/porter-dev/porter/internal/models"
-	"github.com/porter-dev/porter/internal/repository"
-	"gorm.io/gorm"
-)
-
-// CAPIConfigRepository uses gorm.DB for querying the database
-type CAPIConfigRepository struct {
-	db *gorm.DB
-}
-
-// NewCAPIConfigRepository creates a CAPIConfig connection
-func NewCAPIConfigRepository(db *gorm.DB) repository.CAPIConfigRepository {
-	return &CAPIConfigRepository{db}
-}
-
-// Insert creates a new record in the capi_configs table
-func (cr CAPIConfigRepository) Insert(ctx context.Context, conf models.CAPIConfig) (models.CAPIConfig, error) {
-	if conf.ID == uuid.Nil {
-		conf.ID = uuid.New()
-	}
-	tx := cr.db.Create(&conf)
-	if tx.Error != nil {
-		return conf, tx.Error
-	}
-	return conf, nil
-}
-
-// List returns a list of capi configs sorted by created date for a given project and cluster
-func (cr CAPIConfigRepository) List(ctx context.Context, projectID uint, clusterID uint) ([]models.CAPIConfig, error) {
-	var confs []models.CAPIConfig
-
-	tx := cr.db.Preload("capi_configs").Where("project_id = ? and cluster_id = ?", projectID, clusterID).Order("created_at").Find(&confs)
-	if tx.Error != nil {
-		return nil, tx.Error
-	}
-
-	return confs, nil
-}

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

@@ -58,7 +58,7 @@ func AutoMigrate(db *gorm.DB, debug bool) error {
 		&models.StackEnvGroup{},
 		&models.DbMigration{},
 		&models.MonitorTestResult{},
-		&models.CAPIConfig{},
+		&models.APIContractRevision{},
 		&models.AWSAssumeRoleChain{},
 		&ints.KubeIntegration{},
 		&ints.BasicIntegration{},

+ 4 - 4
internal/repository/gorm/repository.go

@@ -49,7 +49,7 @@ type GormRepository struct {
 	tag                       repository.TagRepository
 	stack                     repository.StackRepository
 	monitor                   repository.MonitorTestResultRepository
-	capiConfig                repository.CAPIConfigRepository
+	apiContractRevisions      repository.APIContractRevisioner
 }
 
 func (t *GormRepository) User() repository.UserRepository {
@@ -219,8 +219,8 @@ func (t *GormRepository) Stack() repository.StackRepository {
 func (t *GormRepository) MonitorTestResult() repository.MonitorTestResultRepository {
 	return t.monitor
 }
-func (t *GormRepository) CAPIConfigRepository() repository.CAPIConfigRepository {
-	return t.capiConfig
+func (t *GormRepository) APIContractRevisioner() repository.APIContractRevisioner {
+	return t.apiContractRevisions
 }
 
 // NewRepository returns a Repository which persists users in memory
@@ -269,6 +269,6 @@ func NewRepository(db *gorm.DB, key *[32]byte, storageBackend credentials.Creden
 		tag:                       NewTagRepository(db),
 		stack:                     NewStackRepository(db),
 		monitor:                   NewMonitorTestResultRepository(db),
-		capiConfig:                NewCAPIConfigRepository(db),
+		apiContractRevisions:      NewAPIContractRevisioner(db),
 	}
 }

+ 1 - 1
internal/repository/repository.go

@@ -43,5 +43,5 @@ type Repository interface {
 	Tag() TagRepository
 	Stack() StackRepository
 	MonitorTestResult() MonitorTestResultRepository
-	CAPIConfigRepository() CAPIConfigRepository
+	APIContractRevisioner() APIContractRevisioner
 }

+ 31 - 0
internal/repository/test/api_contract.go

@@ -0,0 +1,31 @@
+package test
+
+import (
+	"context"
+	"errors"
+
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/repository"
+	"gorm.io/gorm"
+)
+
+// APIContractRepository uses gorm.DB for querying the database
+type APIContractRepository struct {
+	db *gorm.DB
+}
+
+// NewAPIContractRevisioner creates an APIRevision connection
+func NewAPIContractRevisioner() repository.APIContractRevisioner {
+	return &APIContractRepository{}
+}
+
+// Insert creates a new record in the api_contract_revisions table
+func (cr APIContractRepository) Insert(ctx context.Context, conf models.APIContractRevision) (models.APIContractRevision, error) {
+	return conf, errors.New("not implemented")
+}
+
+// List returns a list of api contract revisions sorted by created date for a given project and cluster
+func (cr APIContractRepository) List(ctx context.Context, projectID uint, clusterID uint) ([]models.APIContractRevision, error) {
+	var confs []models.APIContractRevision
+	return confs, errors.New("not implemented")
+}

+ 0 - 34
internal/repository/test/capi_config.go

@@ -1,34 +0,0 @@
-package test
-
-import (
-	"context"
-
-	"github.com/porter-dev/porter/internal/models"
-	"github.com/porter-dev/porter/internal/repository"
-	"gorm.io/gorm"
-)
-
-// CAPIConfigRepository uses gorm.DB for querying the database
-type CAPIConfigRepository struct {
-	db *gorm.DB
-}
-
-// NewCAPIConfigRepository creates a CAPIConfig connection
-func NewCAPIConfigRepository(db *gorm.DB) repository.CAPIConfigRepository {
-	return &CAPIConfigRepository{db}
-}
-
-// Insert creates a new record in the capi_configs table
-func (cr CAPIConfigRepository) Insert(ctx context.Context, conf models.CAPIConfig) (models.CAPIConfig, error) {
-	panic("not implemented")
-	return conf, nil
-}
-
-// List returns a list of capi configs sorted by created date for a given project and cluster
-func (cr CAPIConfigRepository) List(ctx context.Context, projectID uint, clusterID uint) ([]models.CAPIConfig, error) {
-	var confs []models.CAPIConfig
-
-	panic("not implemented")
-
-	return confs, nil
-}

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

@@ -47,7 +47,7 @@ type TestRepository struct {
 	tag                       repository.TagRepository
 	stack                     repository.StackRepository
 	monitor                   repository.MonitorTestResultRepository
-	capiConfig                repository.CAPIConfigRepository
+	apiContractRevision       repository.APIContractRevisioner
 }
 
 func (t *TestRepository) User() repository.UserRepository {
@@ -217,8 +217,8 @@ func (t *TestRepository) Stack() repository.StackRepository {
 func (t *TestRepository) MonitorTestResult() repository.MonitorTestResultRepository {
 	return t.monitor
 }
-func (t *TestRepository) CAPIConfigRepository() repository.CAPIConfigRepository {
-	return t.capiConfig
+func (t *TestRepository) APIContractRevisioner() repository.APIContractRevisioner {
+	return t.apiContractRevision
 }
 
 // NewRepository returns a Repository which persists users in memory
@@ -267,6 +267,6 @@ func NewRepository(canQuery bool, failingMethods ...string) repository.Repositor
 		tag:                       NewTagRepository(),
 		stack:                     NewStackRepository(),
 		monitor:                   NewMonitorTestResultRepository(canQuery),
-		capiConfig:                NewCAPIConfigRepository(canQuery),
+		apiContractRevision:       NewAPIContractRevisioner(),
 	}
 }