Quellcode durchsuchen

Refactor stacks (#2947)

Feroze Mohideen vor 3 Jahren
Ursprung
Commit
392d174226

+ 15 - 7
api/server/handlers/stacks/create.go

@@ -1,6 +1,7 @@
 package stacks
 
 import (
+	"encoding/base64"
 	"fmt"
 	"net/http"
 
@@ -41,6 +42,19 @@ func (c *CreateStackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	}
 	stackName := request.StackName
 	namespace := fmt.Sprintf("porter-stack-%s", stackName)
+	porterYamlBase64 := request.PorterYAMLBase64
+	porterYaml, err := base64.StdEncoding.DecodeString(porterYamlBase64)
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error decoding porter yaml: %w", err)))
+		return
+	}
+
+	imageInfo := request.ImageInfo
+	chart, values, err := parse(porterYaml, &imageInfo, c.Config(), cluster.ProjectID)
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error with test: %w", err)))
+		return
+	}
 
 	helmAgent, err := c.GetHelmAgent(r, cluster, namespace)
 	if err != nil {
@@ -61,12 +75,6 @@ func (c *CreateStackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	chart, err := createChartFromDependencies(request.Dependencies)
-	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error creating chart: %w", err)))
-		return
-	}
-
 	registries, err := c.Repo().Registry().ListRegistriesByProjectID(cluster.ProjectID)
 	if err != nil {
 		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error listing registries: %w", err)))
@@ -77,7 +85,7 @@ func (c *CreateStackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		Chart:      chart,
 		Name:       stackName,
 		Namespace:  namespace,
-		Values:     request.Values,
+		Values:     values,
 		Cluster:    cluster,
 		Repo:       c.Repo(),
 		Registries: registries,

+ 176 - 0
api/server/handlers/stacks/parse.go

@@ -0,0 +1,176 @@
+package stacks
+
+import (
+	"fmt"
+
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	stack "github.com/porter-dev/porter/cli/cmd/stack"
+	"github.com/porter-dev/porter/internal/helm/loader"
+	"github.com/porter-dev/porter/internal/templater/utils"
+	"github.com/stefanmcshane/helm/pkg/chart"
+	"gopkg.in/yaml.v2"
+)
+
+func parse(porterYaml []byte, imageInfo *types.ImageInfo, config *config.Config, projectID uint) (*chart.Chart, map[string]interface{}, error) {
+	parsed := &stack.PorterStackYAML{}
+
+	err := yaml.Unmarshal(porterYaml, parsed)
+	if err != nil {
+		return nil, nil, fmt.Errorf("%s: %w", "error parsing porter.yaml", err)
+	}
+
+	values, err := buildStackValues(parsed, imageInfo)
+	if err != nil {
+		return nil, nil, fmt.Errorf("%s: %w", "error building values from porter.yaml", err)
+	}
+	convertedValues := convertMap(values)
+
+	chart, err := buildStackChart(parsed, config, projectID)
+	if err != nil {
+		return nil, nil, fmt.Errorf("%s: %w", "error building chart from porter.yaml", err)
+	}
+
+	return chart, convertedValues.(map[string]interface{}), nil
+}
+
+func buildStackValues(parsed *stack.PorterStackYAML, imageInfo *types.ImageInfo) (map[string]interface{}, error) {
+	values := make(map[string]interface{})
+
+	for name, app := range parsed.Apps {
+		defaultValues := getDefaultValues(app, parsed.Env, imageInfo)
+		helm_values := utils.CoalesceValues(defaultValues, app.Config)
+		values[name] = helm_values
+	}
+
+	return values, nil
+}
+
+func getDefaultValues(app *stack.App, env map[string]string, imageInfo *types.ImageInfo) map[string]interface{} {
+	var defaultValues map[string]interface{}
+	if *app.Type == "web" {
+		defaultValues = map[string]interface{}{
+			"ingress": map[string]interface{}{
+				"enabled": false,
+			},
+			"container": map[string]interface{}{
+				"command": *app.Run,
+				"env": map[string]interface{}{
+					"normal": stack.CopyEnv(env),
+				},
+			},
+		}
+	} else {
+		defaultValues = map[string]interface{}{
+			"container": map[string]interface{}{
+				"command": *app.Run,
+				"env": map[string]interface{}{
+					"normal": stack.CopyEnv(env),
+				},
+			},
+		}
+	}
+	if imageInfo != nil {
+		defaultValues["image"] = map[string]interface{}{
+			"repository": imageInfo.Repository,
+			"tag":        imageInfo.Tag,
+		}
+	}
+	return defaultValues
+}
+
+func buildStackChart(parsed *stack.PorterStackYAML, config *config.Config, projectID uint) (*chart.Chart, error) {
+	deps := make([]*chart.Dependency, 0)
+
+	for alias, app := range parsed.Apps {
+		selectedRepo := "https://charts.getporter.dev"
+		selectedVersion, err := getLatestTemplateVersion(*app.Type, config, projectID)
+		if err != nil {
+			return nil, err
+		}
+		deps = append(deps, &chart.Dependency{
+			Name:       *app.Type,
+			Alias:      alias,
+			Version:    selectedVersion,
+			Repository: selectedRepo,
+		})
+	}
+
+	chart, err := createChartFromDependencies(deps)
+	if err != nil {
+		return nil, err
+	}
+
+	return chart, nil
+}
+
+func createChartFromDependencies(deps []*chart.Dependency) (*chart.Chart, error) {
+	metadata := &chart.Metadata{
+		Name:        "umbrella",
+		Description: "Web application that is exposed to external traffic.",
+		Version:     "0.96.0",
+		APIVersion:  "v2",
+		Home:        "https://getporter.dev/",
+		Icon:        "https://user-images.githubusercontent.com/65516095/111255214-07d3da80-85ed-11eb-99e2-fddcbdb99bdb.png",
+		Keywords: []string{
+			"porter",
+			"application",
+			"service",
+			"umbrella",
+		},
+		Type:         "application",
+		Dependencies: deps,
+	}
+
+	// create a new chart object with the metadata
+	c := &chart.Chart{
+		Metadata: metadata,
+	}
+	return c, nil
+}
+
+func getLatestTemplateVersion(templateName string, config *config.Config, projectID uint) (string, error) {
+	repoIndex, err := loader.LoadRepoIndexPublic(config.ServerConf.DefaultApplicationHelmRepoURL)
+	if err != nil {
+		return "", fmt.Errorf("%s: %w", "unable to load porter chart repo", err)
+	}
+	templates := loader.RepoIndexToPorterChartList(repoIndex, config.ServerConf.DefaultApplicationHelmRepoURL)
+	if err != nil {
+		return "", fmt.Errorf("%s: %w", "unable to load porter chart list", err)
+	}
+
+	var version string
+	// find the matching template name
+	for _, template := range templates {
+		if templateName == template.Name {
+			version = template.Versions[0]
+			break
+		}
+	}
+
+	if version == "" {
+		return "", fmt.Errorf("matching template version not found")
+	}
+
+	return version, nil
+}
+
+func convertMap(m interface{}) interface{} {
+	switch m := m.(type) {
+	case map[string]interface{}:
+		for k, v := range m {
+			m[k] = convertMap(v)
+		}
+	case map[interface{}]interface{}:
+		result := map[string]interface{}{}
+		for k, v := range m {
+			result[k.(string)] = convertMap(v)
+		}
+		return result
+	case []interface{}:
+		for i, v := range m {
+			m[i] = convertMap(v)
+		}
+	}
+	return m
+}

+ 14 - 44
api/server/handlers/stacks/update.go

@@ -1,6 +1,7 @@
 package stacks
 
 import (
+	"encoding/base64"
 	"fmt"
 	"net/http"
 
@@ -12,7 +13,6 @@ import (
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/helm"
 	"github.com/porter-dev/porter/internal/models"
-	"github.com/stefanmcshane/helm/pkg/chart"
 )
 
 type UpdateStackHandler struct {
@@ -43,15 +43,23 @@ func (c *UpdateStackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 
 	stackName := request.StackName
 	namespace := fmt.Sprintf("porter-stack-%s", stackName)
-	helmAgent, err := c.GetHelmAgent(r, cluster, namespace)
+	porterYamlBase64 := request.PorterYAMLBase64
+	porterYaml, err := base64.StdEncoding.DecodeString(porterYamlBase64)
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error getting helm agent: %w", err)))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error decoding porter yaml: %w", err)))
+		return
+	}
+
+	imageInfo := request.ImageInfo
+	chart, values, err := parse(porterYaml, &imageInfo, c.Config(), cluster.ProjectID)
+	if err != nil {
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error with test: %w", err)))
 		return
 	}
 
-	chart, err := createChartFromDependencies(request.Dependencies)
+	helmAgent, err := c.GetHelmAgent(r, cluster, namespace)
 	if err != nil {
-		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error creating chart: %w", err)))
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error getting helm agent: %w", err)))
 		return
 	}
 
@@ -65,7 +73,7 @@ func (c *UpdateStackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		Chart:      chart,
 		Name:       stackName,
 		Namespace:  namespace,
-		Values:     request.Values,
+		Values:     values,
 		Cluster:    cluster,
 		Repo:       c.Repo(),
 		Registries: registries,
@@ -82,41 +90,3 @@ func (c *UpdateStackHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	}
 	w.WriteHeader(http.StatusCreated)
 }
-
-func createChartFromDependencies(deps []types.Dependency) (*chart.Chart, error) {
-	metadata := &chart.Metadata{
-		Name:        "umbrella",
-		Description: "Web application that is exposed to external traffic.",
-		Version:     "0.96.0",
-		APIVersion:  "v2",
-		Home:        "https://getporter.dev/",
-		Icon:        "https://user-images.githubusercontent.com/65516095/111255214-07d3da80-85ed-11eb-99e2-fddcbdb99bdb.png",
-		Keywords: []string{
-			"porter",
-			"application",
-			"service",
-			"umbrella",
-		},
-		Type:         "application",
-		Dependencies: createChartDependencies(deps),
-	}
-
-	// create a new chart object with the metadata
-	c := &chart.Chart{
-		Metadata: metadata,
-	}
-	return c, nil
-}
-
-func createChartDependencies(deps []types.Dependency) []*chart.Dependency {
-	var chartDependencies []*chart.Dependency
-	for _, d := range deps {
-		chartDependencies = append(chartDependencies, &chart.Dependency{
-			Name:       d.Name,
-			Alias:      d.Alias,
-			Version:    d.Version,
-			Repository: d.Repository,
-		})
-	}
-	return chartDependencies
-}

+ 0 - 15
api/types/release.go

@@ -218,18 +218,3 @@ type UpdateGitActionConfigRequest struct {
 type UpdateCanonicalNameRequest struct {
 	CanonicalName string `json:"canonical_name"`
 }
-
-type CreateStackReleaseRequest struct {
-	// The Helm values for this release
-	Values map[string]interface{} `json:"values"`
-	// Used to construct the Chart.yaml
-	Dependencies []Dependency `json:"dependencies form:"required"`
-	StackName    string       `json:"stack_name" form:"required,dns1123"`
-}
-
-type Dependency struct {
-	Name       string `json:"name" form:"required"`
-	Alias      string `json:"alias" form:"required"`
-	Version    string `json:"version" form:"required"`
-	Repository string `json:"repository" form:"required"`
-}

+ 12 - 0
api/types/stack.go

@@ -0,0 +1,12 @@
+package types
+
+type CreateStackReleaseRequest struct {
+	StackName        string    `json:"stack_name" form:"required,dns1123"`
+	PorterYAMLBase64 string    `json:"porter_yaml" form:"required"`
+	ImageInfo        ImageInfo `json:"image_info" form:"omitempty"`
+}
+
+type ImageInfo struct {
+	Repository string `json:"repository"`
+	Tag        string `json:"tag"`
+}

+ 1 - 6
cli/cmd/apply.go

@@ -162,18 +162,13 @@ func apply(_ *types.GetAuthenticatedUserResponse, client *api.Client, _ []string
 			return fmt.Errorf("error parsing porter.yaml for build resources: %w", err)
 		}
 
-		appResGroup, err := stack.CreateV1ApplicationResources(client, fileBytes)
-		if err != nil {
-			return fmt.Errorf("error parsing porter.yaml for application resources: %w", err)
-		}
-
 		deployStackHook := &stack.DeployStackHook{
 			Client:               client,
 			StackName:            stackName,
 			ProjectID:            cliConf.Project,
 			ClusterID:            cliConf.Cluster,
-			AppResourceGroup:     appResGroup,
 			BuildImageDriverName: stack.GetBuildImageDriverName(),
+			PorterYAML:           fileBytes,
 		}
 		worker.RegisterHook("deploy-stack", deployStackHook)
 	} else {

+ 0 - 74
cli/cmd/stack/app.go

@@ -1,74 +0,0 @@
-package stack
-
-import (
-	"fmt"
-
-	"github.com/mitchellh/mapstructure"
-	"github.com/porter-dev/porter/cli/cmd/deploy"
-	"github.com/porter-dev/porter/internal/integrations/preview"
-	"github.com/porter-dev/porter/internal/templater/utils"
-	"github.com/porter-dev/switchboard/pkg/types"
-)
-
-func (a *App) GetType() string {
-	return *a.Type
-}
-
-func (a *App) GetDefaultValues() map[string]interface{} {
-	var defaultValues map[string]interface{}
-	if *a.Type == "web" {
-		defaultValues = map[string]interface{}{
-			"ingress": map[string]interface{}{
-				"enabled": false,
-			},
-			"container": map[string]interface{}{
-				"command": *a.Run,
-				"env":     map[string]interface{}{},
-			},
-		}
-	} else {
-		defaultValues = map[string]interface{}{
-			"container": map[string]interface{}{
-				"command": *a.Run,
-				"env":     map[string]interface{}{},
-			},
-		}
-	}
-	return defaultValues
-}
-
-func (a *App) getV1Resource(name string, b *Build, env map[string]string) (*types.Resource, error) {
-	config := &preview.ApplicationConfig{}
-
-	if a.Config == nil {
-		a.Config = make(map[string]interface{})
-	}
-	config.Build.Method = "registry"
-	config.Build.Image = fmt.Sprintf("{ .%s.image }", b.GetName())
-	config.Build.Env = CopyEnv(env)
-
-	defaultValues := a.GetDefaultValues()
-	containerDefaultValues, err := deploy.GetNestedMap(defaultValues, "container", "env")
-	if err != nil {
-		return nil, err
-	}
-	containerDefaultValues["normal"] = CopyEnv(env)
-	config.Values = utils.CoalesceValues(defaultValues, a.Config)
-
-	rawConfig := make(map[string]any)
-
-	err = mapstructure.Decode(config, &rawConfig)
-	if err != nil {
-		return nil, err
-	}
-
-	return &types.Resource{
-		Name:      name,
-		DependsOn: []string{"get-env", b.GetName()},
-		Source: map[string]any{
-			"name": a.GetType(),
-		},
-		Config: rawConfig,
-		Driver: "",
-	}, nil
-}

+ 0 - 24
cli/cmd/stack/apply.go

@@ -68,27 +68,3 @@ func createStackConf(client *api.Client, raw []byte) (*StackConf, error) {
 		parsed:    parsed,
 	}, nil
 }
-
-func CreateV1ApplicationResources(client *api.Client, raw []byte) (*types.ResourceGroup, error) {
-	stackConf, err := createStackConf(client, raw)
-	if err != nil {
-		return nil, err
-	}
-
-	v1File := &types.ResourceGroup{}
-
-	for name, app := range stackConf.parsed.Apps {
-		if app == nil {
-			continue
-		}
-
-		ai, err := app.getV1Resource(name, stackConf.parsed.Build, stackConf.parsed.Env)
-		if err != nil {
-			return nil, err
-		}
-
-		v1File.Resources = append(v1File.Resources, ai)
-	}
-
-	return v1File, nil
-}

+ 39 - 125
cli/cmd/stack/hooks.go

@@ -2,6 +2,7 @@ package stack
 
 import (
 	"context"
+	"encoding/base64"
 	"fmt"
 	"strings"
 
@@ -9,23 +10,22 @@ import (
 	api "github.com/porter-dev/porter/api/client"
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/cli/cmd/config"
-	switchboardTypes "github.com/porter-dev/switchboard/pkg/types"
 )
 
 type DeployStackHook struct {
 	Client               *api.Client
 	StackName            string
 	ProjectID, ClusterID uint
-	AppResourceGroup     *switchboardTypes.ResourceGroup
 	BuildImageDriverName string
-}
-
-type StackConfig struct {
-	Values       map[string]interface{}
-	Dependencies []types.Dependency
+	PorterYAML           []byte
 }
 
 func (t *DeployStackHook) PreApply() error {
+	err := config.ValidateCLIEnvironment()
+	if err != nil {
+		errMsg := composePreviewMessage("porter CLI is not configured correctly", Error)
+		return fmt.Errorf("%s: %w", errMsg, err)
+	}
 	return nil
 }
 
@@ -57,41 +57,47 @@ func (t *DeployStackHook) PostApply(driverOutput map[string]interface{}) error {
 		color.New(color.FgGreen).Printf("Found release for stack %s: attempting update\n", t.StackName)
 	}
 
-	return t.applyStack(t.AppResourceGroup, client, shouldCreate, driverOutput)
+	return t.applyStack(client, shouldCreate, driverOutput)
 }
 
-func (t *DeployStackHook) applyStack(applications *switchboardTypes.ResourceGroup, client *api.Client, shouldCreate bool, driverOutput map[string]interface{}) error {
-	if applications == nil {
-		return fmt.Errorf("no applications found")
-	}
-
-	err := insertImageInfoIntoApps(applications, driverOutput)
-	if err != nil {
-		return fmt.Errorf("unable to insert image info into apps: %w", err)
-	}
-
-	values, err := buildStackValues(applications)
-	if err != nil {
-		return err
-	}
-
-	deps, err := buildStackDependencies(applications, client, t.ProjectID)
-	if err != nil {
-		return err
-	}
-
-	stackConf := StackConfig{
-		Values:       values,
-		Dependencies: deps,
+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
+		imageSpl := strings.Split(image, ":")
+		imageInfo = types.ImageInfo{
+			Repository: imageSpl[0],
+			Tag:        imageSpl[1],
+		}
 	}
 
 	if shouldCreate {
-		err := t.createStack(client, stackConf)
+		err := client.CreateStack(
+			context.Background(),
+			t.ProjectID,
+			t.ClusterID,
+			&types.CreateStackReleaseRequest{
+				StackName:        t.StackName,
+				PorterYAMLBase64: base64.StdEncoding.EncodeToString(t.PorterYAML),
+				ImageInfo:        imageInfo,
+			},
+		)
 		if err != nil {
 			return fmt.Errorf("error creating stack %s: %w", t.StackName, err)
 		}
 	} else {
-		err := t.updateStack(client, stackConf)
+		err := client.UpdateStack(
+			context.Background(),
+			t.ProjectID,
+			t.ClusterID,
+			t.StackName,
+			&types.CreateStackReleaseRequest{
+				StackName:        t.StackName,
+				PorterYAMLBase64: base64.StdEncoding.EncodeToString(t.PorterYAML),
+				ImageInfo:        imageInfo,
+			},
+		)
 		if err != nil {
 			return fmt.Errorf("error updating stack %s: %w", t.StackName, err)
 		}
@@ -100,97 +106,5 @@ func (t *DeployStackHook) applyStack(applications *switchboardTypes.ResourceGrou
 	return nil
 }
 
-func insertImageInfoIntoApps(applications *switchboardTypes.ResourceGroup, driverOutput map[string]interface{}) error {
-	image, ok := driverOutput["image"].(string)
-	if !ok || image == "" {
-		return fmt.Errorf("unable to find image in driver output")
-	}
-
-	// split image into image-path:tag format
-	imageSpl := strings.Split(image, ":")
-
-	if len(imageSpl) != 2 {
-		return fmt.Errorf("invalid image format: must be image-path:tag format")
-	}
-
-	for _, resource := range applications.Resources {
-		if resource.Config == nil {
-			resource.Config = make(map[string]interface{})
-		}
-		values, ok := resource.Config["Values"].(map[string]interface{})
-		if !ok {
-			values = make(map[string]interface{})
-			resource.Config["Values"] = values
-		}
-		image, ok := values["image"].(map[string]interface{})
-		if !ok {
-			image = make(map[string]interface{})
-			values["image"] = image
-		}
-		image["repository"] = imageSpl[0]
-		image["tag"] = imageSpl[1]
-	}
-
-	return nil
-}
-
-func (t *DeployStackHook) createStack(client *api.Client, stackConf StackConfig) error {
-	err := client.CreateStack(
-		context.Background(),
-		t.ProjectID,
-		t.ClusterID,
-		&types.CreateStackReleaseRequest{
-			StackName:    t.StackName,
-			Values:       convertMap(stackConf.Values).(map[string]interface{}),
-			Dependencies: stackConf.Dependencies,
-		},
-	)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (t *DeployStackHook) updateStack(client *api.Client, stackConf StackConfig) error {
-	err := client.UpdateStack(
-		context.Background(),
-		t.ProjectID,
-		t.ClusterID,
-		t.StackName,
-		&types.CreateStackReleaseRequest{
-			StackName:    t.StackName,
-			Values:       convertMap(stackConf.Values).(map[string]interface{}),
-			Dependencies: stackConf.Dependencies,
-		},
-	)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// this is necessary to marshal the resulting object during the request
-func convertMap(m interface{}) interface{} {
-	switch m := m.(type) {
-	case map[string]interface{}:
-		for k, v := range m {
-			m[k] = convertMap(v)
-		}
-	case map[interface{}]interface{}:
-		result := map[string]interface{}{}
-		for k, v := range m {
-			result[k.(string)] = convertMap(v)
-		}
-		return result
-	case []interface{}:
-		for i, v := range m {
-			m[i] = convertMap(v)
-		}
-	}
-	return m
-}
-
 func (t *DeployStackHook) OnConsolidatedErrors(map[string]error) {}
 func (t *DeployStackHook) OnError(error)                         {}

+ 0 - 79
cli/cmd/stack/utils.go

@@ -1,12 +1,7 @@
 package stack
 
 import (
-	"context"
 	"fmt"
-
-	api "github.com/porter-dev/porter/api/client"
-	"github.com/porter-dev/porter/api/types"
-	switchboardTypes "github.com/porter-dev/switchboard/pkg/types"
 )
 
 type MessageLevel string
@@ -21,77 +16,3 @@ const (
 func composePreviewMessage(msg string, level MessageLevel) string {
 	return fmt.Sprintf("[porter.yaml stack][%s] -- %s", level, msg)
 }
-
-func buildStackValues(apps *switchboardTypes.ResourceGroup) (map[string]interface{}, error) {
-	values := make(map[string]interface{})
-
-	for _, app := range apps.Resources {
-		if app.Config == nil {
-			continue
-		}
-
-		if helm_values, ok := app.Config["Values"]; ok {
-			values[app.Name] = helm_values
-		}
-	}
-
-	return values, nil
-}
-
-func buildStackDependencies(apps *switchboardTypes.ResourceGroup, client *api.Client, projectID uint) ([]types.Dependency, error) {
-	deps := make([]types.Dependency, 0)
-
-	for _, app := range apps.Resources {
-		source, ok := app.Source["name"]
-		if !ok {
-			return nil, fmt.Errorf("app %s does not have a source", app.Name)
-		}
-		chartName, ok := source.(string)
-		if !ok {
-			return nil, fmt.Errorf("unable to parse source name for app %s", app.Name)
-		}
-		selectedRepo := "https://charts.getporter.dev"
-		selectedVersion, err := getLatestTemplateVersion(chartName, client, projectID)
-		if err != nil {
-			return nil, err
-		}
-		deps = append(deps, types.Dependency{
-			Name:       chartName,
-			Alias:      app.Name,
-			Version:    selectedVersion,
-			Repository: selectedRepo,
-		})
-	}
-
-	return deps, nil
-}
-
-// getLatestTemplateVersion retrieves the latest template version for a specific
-// Porter template from the chart repository.
-func getLatestTemplateVersion(templateName string, client *api.Client, projectID uint) (string, error) {
-	resp, err := client.ListTemplates(
-		context.Background(),
-		projectID,
-		&types.ListTemplatesRequest{},
-	)
-	if err != nil {
-		return "", err
-	}
-
-	templates := *resp
-
-	var version string
-	// find the matching template name
-	for _, template := range templates {
-		if templateName == template.Name {
-			version = template.Versions[0]
-			break
-		}
-	}
-
-	if version == "" {
-		return "", fmt.Errorf("matching template version not found")
-	}
-
-	return version, nil
-}