Преглед изворни кода

downgrade to v1 build image driver

Mohammed Nafees пре 3 година
родитељ
комит
5dd5a819f3

+ 13 - 23
cli/cmd/preview/v2beta1/apply.go

@@ -9,7 +9,6 @@ import (
 	api "github.com/porter-dev/porter/api/client"
 	apiTypes "github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/cli/cmd/config"
-	"github.com/porter-dev/switchboard/pkg/worker"
 	"gopkg.in/yaml.v3"
 )
 
@@ -122,33 +121,24 @@ func (a *PreviewApplier) Apply() error {
 		a.namespace),
 	)
 
-	err = a.readOSEnv()
+	// err = a.readOSEnv()
 
-	if err != nil {
-		errMsg := composePreviewMessage("error reading OS environment variables", Error)
-		return fmt.Errorf("%s: %w", errMsg, err)
-	}
-
-	err = a.processVariables()
+	// if err != nil {
+	// 	errMsg := composePreviewMessage("error reading OS environment variables", Error)
+	// 	return fmt.Errorf("%s: %w", errMsg, err)
+	// }
 
-	if err != nil {
-		return err
-	}
+	// err = a.processVariables()
 
-	err = a.processEnvGroups()
+	// if err != nil {
+	// 	return err
+	// }
 
-	if err != nil {
-		return err
-	}
+	// err = a.processEnvGroups()
 
-	w := worker.NewWorker()
-	w.RegisterDriver("default", &DefaultDriver{
-		Vars:      a.variablesMap,
-		Env:       a.osEnv,
-		APIClient: a.apiClient,
-		Namespace: a.namespace,
-	})
-	w.SetDefaultDriver("default")
+	// if err != nil {
+	// 	return err
+	// }
 
 	return nil
 }

+ 170 - 0
cli/cmd/preview/v2beta1/build.go

@@ -0,0 +1,170 @@
+package v2beta1
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/mitchellh/mapstructure"
+	apiTypes "github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/integrations/preview"
+	"github.com/porter-dev/switchboard/pkg/types"
+)
+
+func (b *Build) GetName() string {
+	if b == nil || b.Name == nil {
+		return ""
+	}
+
+	return *b.Name
+}
+
+func (b *Build) GetContext() string {
+	if b == nil || b.Context == nil || *b.Context == "" {
+		return "."
+	}
+
+	return *b.Context
+}
+
+func (b *Build) GetMethod() string {
+	if b == nil || b.Method == nil {
+		return ""
+	}
+
+	return *b.Method
+}
+
+func (b *Build) GetBuilder() string {
+	if b == nil || b.Builder == nil {
+		return ""
+	}
+
+	return *b.Builder
+}
+
+func (b *Build) GetBuildpacks() []string {
+	if b == nil || b.Buildpacks == nil {
+		return []string{}
+	}
+
+	var bp []string
+
+	for _, b := range b.Buildpacks {
+		if b == nil {
+			continue
+		}
+
+		bp = append(bp, *b)
+	}
+
+	return bp
+}
+
+func (b *Build) GetDockerfile() string {
+	if b == nil || b.Dockerfile == nil {
+		return ""
+	}
+
+	return *b.Dockerfile
+}
+
+func (b *Build) GetImage() string {
+	if b == nil || b.Image == nil {
+		return ""
+	}
+
+	return *b.Image
+}
+
+func (b *Build) GetRawEnv() map[string]string {
+	env := make(map[string]string)
+
+	if b == nil || b.Env == nil {
+		return env
+	}
+
+	for k, v := range b.Env.Raw {
+		if k == nil || v == nil {
+			continue
+		}
+
+		env[*k] = *v
+	}
+
+	return env
+}
+
+func (b *Build) GetEnvGroups() []string {
+	var eg []string
+
+	if b == nil || b.Env == nil {
+		return eg
+	}
+
+	for _, g := range b.Env.ImportFrom {
+		if g == nil {
+			continue
+		}
+
+		ns, name, valid := strings.Cut(*g, "/")
+
+		if !valid || ns == "" || name == "" {
+			printWarningMessage(fmt.Sprintf("ignoring invalid env group name: %s", *g))
+			continue
+		}
+
+		eg = append(eg, *g)
+	}
+
+	return eg
+}
+
+func (b *Build) getV1Build() (*types.Resource, error) {
+	config := &preview.BuildDriverConfig{}
+
+	if b.GetMethod() == "pack" {
+		config.Build.Method = "pack"
+		config.Build.Builder = b.GetBuilder()
+		config.Build.Buildpacks = b.GetBuildpacks()
+	} else if b.GetMethod() == "docker" {
+		config.Build.Method = "docker"
+		config.Build.Dockerfile = b.GetDockerfile()
+	} else if b.GetMethod() == "registry" {
+		config.Build.Method = "registry"
+		config.Build.Image = b.GetImage()
+	} else {
+		return nil, fmt.Errorf("invalid build method: %s", b.GetMethod())
+	}
+
+	config.Build.Context = b.GetContext()
+	config.Build.Env = b.GetRawEnv()
+
+	for _, eg := range b.GetEnvGroups() {
+		ns, name, _ := strings.Cut(eg, "/")
+
+		config.EnvGroups = append(config.EnvGroups, apiTypes.EnvGroupMeta{
+			Namespace: ns,
+			Name:      name,
+		})
+	}
+
+	rawConfig := make(map[string]any)
+
+	err := mapstructure.Decode(config, &rawConfig)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return &types.Resource{
+		Name:   b.GetName(),
+		Driver: "build-image",
+		Source: map[string]any{
+			"name": "web",
+		},
+		Target: map[string]any{
+			"app_name": b.GetName(),
+		},
+		Config: rawConfig,
+	}, nil
+}

+ 373 - 373
cli/cmd/preview/v2beta1/default_driver.go

@@ -1,375 +1,375 @@
 package v2beta1
 
-import (
-	"context"
-	"fmt"
-	"os"
-	"strings"
-
-	"github.com/cli/cli/git"
-	"github.com/fatih/color"
-	"github.com/mitchellh/mapstructure"
-	api "github.com/porter-dev/porter/api/client"
-	apiTypes "github.com/porter-dev/porter/api/types"
-	"github.com/porter-dev/porter/cli/cmd/config"
-	"github.com/porter-dev/porter/cli/cmd/deploy"
-	"github.com/porter-dev/switchboard/v2/pkg/types"
-)
-
-type DefaultDriver struct {
-	Vars      map[string]string
-	Env       map[string]string
-	Builds    []*types.Build
-	APIClient *api.Client
-	Namespace string
-
-	allErrors []error
-}
-
-func (d *DefaultDriver) PreApply(resource *types.YAMLNode[*types.Resource]) error {
-	return nil
-}
-
-func (d *DefaultDriver) Apply(resource *types.YAMLNode[*types.Resource]) error {
-	if isPorterApp(resource) {
-		return d.applyPorterApp(resource)
-	}
-
-	// everything else is an addon
-	return d.applyAddon(resource)
-}
-
-func (d *DefaultDriver) PostApply(resource *types.YAMLNode[*types.Resource]) error {
-	return nil
-}
-
-func (d *DefaultDriver) OnError(resource *types.YAMLNode[*types.Resource], errs []error) {
-
-}
-
-func isPorterApp(resource *types.YAMLNode[*types.Resource]) bool {
-	if resource.GetValue().ChartURL.GetValue() == "https://charts.getporter.dev" &&
-		(resource.GetValue().Type.GetValue() == "web" ||
-			resource.GetValue().Type.GetValue() == "worker" ||
-			resource.GetValue().Type.GetValue() == "job") {
-		return true
-	}
-
-	return false
-}
-
-func (d *DefaultDriver) applyPorterApp(resource *types.YAMLNode[*types.Resource]) error {
-	appBuild := &porterAppBuild{}
-	appDeploy := &porterAppDeploy{}
-	buildNode := resource.GetValue().Build.GetRawYAMLNode()
-	deployNode := resource.GetValue().Deploy.GetRawYAMLNode()
-
-	err := buildNode.Decode(appBuild)
-
-	if err != nil {
-		return err // FIXME: descriptive error
-	}
-
-	err = deployNode.Decode(appDeploy)
-
-	if err != nil {
-		return err // FIXME: descriptive error
-	}
-
-	var buildConfig *types.Build
-
-	if appBuild.Ref != "" {
-		for _, b := range d.Builds {
-			if b.Name.GetValue() == appBuild.Ref {
-				buildConfig = b
-				break
-			}
-		}
-
-		if buildConfig == nil {
-			// this should not happen
-			return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
-				"error:\n-----\nERROR: invalid build ref given for app '%s'", resource.GetValue().Name.GetValue())
-		}
-	} else {
-		buildConfig = appBuild.Build
-	}
-
-	if buildConfig == nil {
-		// this should not happen
-		return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
-			"error:\n-----\nERROR: neither build ref nor build body given for app '%s'", resource.GetValue().Name.GetValue())
-	}
-
-	if resource.GetValue().Type.GetValue() == "job" {
-		jobConfig := &porterJob{}
-		jobNode := resource.GetRawYAMLNode()
-
-		err := jobNode.Decode(jobConfig)
-
-		if err != nil {
-			return err // FIXME: descriptive error
-		}
-
-		return d.applyJob(resource, buildConfig, appDeploy, jobConfig)
-	} else if oneOf(resource.GetValue().Type.GetValue(), "web", "worker") {
-
-	} else {
-		// this should not happen
-		return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
-			"error:\n-----\nERROR: app '%s' is not one of 'web', 'worker', 'job'", resource.GetValue().Name.GetValue())
-	}
-
-	return nil
-}
-
-func (d *DefaultDriver) applyAddon(resource *types.YAMLNode[*types.Resource]) error {
-	return nil
-}
-
-func (d *DefaultDriver) applyJob(
-	resource *types.YAMLNode[*types.Resource],
-	buildConfig *types.Build,
-	appDeploy *porterAppDeploy,
-	jobConfig *porterJob,
-) error {
-	_, err := d.APIClient.GetRelease(
-		context.Background(),
-		config.GetCLIConfig().Project,
-		config.GetCLIConfig().Cluster,
-		d.Namespace,
-		resource.GetValue().Name.GetValue(),
-	)
-
-	exists := err == nil
-
-	flattenedBuildEnv := make(map[string]string)
-
-	for k, v := range buildConfig.Env {
-		flattenedBuildEnv[k.GetValue()] = v.GetValue()
-	}
-
-	var flattenedBuildEnvGroup []apiTypes.EnvGroupMeta
-
-	for _, egName := range buildConfig.EnvGroups {
-		flattenedBuildEnvGroup = append(flattenedBuildEnvGroup, apiTypes.EnvGroupMeta{
-			Name:      egName.GetValue(),
-			Namespace: d.Namespace,
-		})
-	}
-
-	tag := getImageTag()
-
-	sharedOpts := &deploy.SharedOpts{
-		ProjectID:       config.GetCLIConfig().Project,
-		ClusterID:       config.GetCLIConfig().Cluster,
-		Namespace:       d.Namespace,
-		LocalPath:       buildConfig.Context.GetValue(),
-		LocalDockerfile: buildConfig.Dockerfile.GetValue(),
-		OverrideTag:     tag,
-		Method:          deploy.DeployBuildType(buildConfig.Method.GetValue()),
-		AdditionalEnv:   flattenedBuildEnv,
-		EnvGroups:       flattenedBuildEnvGroup,
-	}
-
-	if buildConfig.Method.GetValue() == "pack" && buildConfig.UseCache != nil {
-		sharedOpts.UseCache = buildConfig.UseCache.GetValue()
-	}
-
-	if exists {
-		if jobConfig.Once {
-			// since the job already exists and was marked 'once', simply return
-			return nil
-		}
-
-		updateAgent, err := deploy.NewDeployAgent(d.APIClient, resource.GetValue().Name.GetValue(), &deploy.DeployOpts{
-			SharedOpts: sharedOpts,
-			Local:      buildConfig.Method.GetValue() != "registry",
-		})
-
-		if err != nil {
-			return fmt.Errorf("[porter.yaml v2][app:%s] error creating deploy agent to update app: %w",
-				resource.GetValue().Name.GetValue(), err)
-		}
-
-		// if the build method is registry, we do not trigger a build
-		if buildConfig.Method.GetValue() != "registry" {
-			buildEnv, err := updateAgent.GetBuildEnv(&deploy.GetBuildEnvOpts{
-				UseNewConfig: true,
-				// NewConfig:    appConf.Values,
-			})
-
-			if err != nil {
-				return err // FIXME
-			}
-
-			err = updateAgent.SetBuildEnv(buildEnv)
-
-			if err != nil {
-				return err // FIXME
-			}
-
-			var bc *apiTypes.BuildConfig
-
-			if buildConfig.Method.GetValue() == "pack" {
-				// FIXME: temporary fix
-				var bp []string
-
-				for _, b := range buildConfig.Buildpacks {
-					bp = append(bp, b.GetValue())
-				}
-
-				bc = &apiTypes.BuildConfig{
-					Builder:    buildConfig.Builder.GetValue(),
-					Buildpacks: bp,
-				}
-			}
-
-			err = updateAgent.Build(bc)
-
-			if err != nil {
-				return err // FIXME
-			}
-
-			// if !appConf.Build.UseCache { // FIXME
-			err = updateAgent.Push()
-
-			if err != nil {
-				return err // FIXME
-			}
-			// }
-		}
-
-		// err = updateAgent.UpdateImageAndValues(appConf.Values) // FIXME
-
-		// if err != nil {
-		// 	return err // FIXME
-		// }
-	} else { // create the job
-		// attempt to get repo suffix from environment variables
-		var repoSuffix string
-
-		if repoName := os.Getenv("PORTER_REPO_NAME"); repoName != "" {
-			if repoOwner := os.Getenv("PORTER_REPO_OWNER"); repoOwner != "" {
-				repoSuffix = strings.ToLower(strings.ReplaceAll(fmt.Sprintf("%s-%s", repoOwner, repoName), "_", "-"))
-			}
-		}
-
-		var registryURL string
-
-		if buildConfig.ImageRepoURI != nil {
-			registryURL = buildConfig.ImageRepoURI.GetValue()
-		}
-
-		if registryURL == "" {
-			regList, err := d.APIClient.ListRegistries(context.Background(), config.GetCLIConfig().Project)
-
-			if err != nil {
-				return fmt.Errorf("error fetching list of registries while trying to choose registry to deploy new"+
-					" image for app '%s': %w", resource.GetValue().Name.GetValue(), err)
-			}
-
-			if len(*regList) == 0 {
-				return fmt.Errorf("no registries linked with project, needed to deploy new image for app '%s'",
-					resource.GetValue().Name.GetValue())
-			} else {
-				registryURL = (*regList)[0].URL
-			}
-		}
-
-		createAgent := &deploy.CreateAgent{
-			Client: d.APIClient,
-			CreateOpts: &deploy.CreateOpts{
-				SharedOpts:  sharedOpts,
-				Kind:        resource.GetValue().Type.GetValue(),
-				ReleaseName: resource.GetValue().Name.GetValue(),
-				RegistryURL: registryURL,
-				RepoSuffix:  repoSuffix,
-			},
-		}
-
-		if buildConfig.Method.GetValue() == "registry" {
-			flattenedDeployMap := make(map[string]any)
-
-			for k, v := range resource.GetValue().Deploy.GetValue() {
-				flattenedDeployMap[k.GetValue()] = v.GetValue()
-			}
-
-			values := &porterWebChartValues{}
-
-			// delete the aliases from the deploy section
-			delete(flattenedDeployMap, "command")
-			delete(flattenedDeployMap, "cpu")
-			delete(flattenedDeployMap, "memory")
-
-			// replace alias values to the original expect yaml values
-			values.Container.Command = appDeploy.Command
-			values.Container.Env.Build = flattenedBuildEnv
-			values.Container.Env.Normal = appDeploy.Env
-			// values.Container.Env.Synced
-			values.Resources.Requests.CPU = appDeploy.CPU
-			values.Resources.Requests.Memory = appDeploy.Memory
-			if len(appDeploy.Hosts) > 0 {
-				values.Ingress.CustomDomain = true
-				values.Ingress.Hosts = appDeploy.Hosts
-			}
-
-			overrideValues := make(map[string]any)
-
-			err = mapstructure.Decode(values, &overrideValues)
-
-			if err != nil {
-				return err // FIXME
-			}
-
-			_, err := createAgent.CreateFromRegistry("", overrideValues)
-
-			if err != nil {
-				return fmt.Errorf("[porter.yaml v2][app:%s] error creating job: %w", resource.GetValue().Name.GetValue(), err)
-			}
-		} else if oneOf(buildConfig.Method.GetValue(), "pack", "docker") {
-			_, err := createAgent.CreateFromDocker(nil, "", nil)
-
-			if err != nil {
-				return fmt.Errorf("[porter.yaml v2][app:%s] error creating job: %w", resource.GetValue().Name.GetValue(), err)
-			}
-		} else {
-			// this should not happen
-			return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
-				"error:\n-----\nERROR: build method was not one of 'pack', 'docker', 'registry' for app '%s'",
-				resource.GetValue().Name.GetValue())
-		}
-	}
-
-	return nil
-}
-
-// fetching the image tag works in 3 steps
-//   - read PORTER_TAG env var
-//   - read the git SHA from the current directory
-//   - default to 'latest' tag
-func getImageTag() string {
-	tag := os.Getenv("PORTER_TAG")
-
-	if tag == "" {
-		commit, err := git.LastCommit()
-
-		if err == nil {
-			tag = commit.Sha[:7]
-
-			color.New(color.FgBlue).Printf("[porter.yaml v2] PORTER_TAG not defined, falling back to image tag '%s'"+
-				" from git SHA\n", tag)
-		}
-	} else {
-		color.New(color.FgBlue).Printf("[porter.yaml v2] Using image tag '%s' from PORTER_TAG environment variable\n", tag)
-	}
-
-	if tag == "" {
-		color.New(color.FgBlue).Println("[porter.yaml v2] PORTER_TAG not defined, not a git repository, falling back" +
-			" to image tag 'latest'")
-
-		tag = "latest"
-	}
-
-	return tag
-}
+// import (
+// 	"context"
+// 	"fmt"
+// 	"os"
+// 	"strings"
+
+// 	"github.com/cli/cli/git"
+// 	"github.com/fatih/color"
+// 	"github.com/mitchellh/mapstructure"
+// 	api "github.com/porter-dev/porter/api/client"
+// 	apiTypes "github.com/porter-dev/porter/api/types"
+// 	"github.com/porter-dev/porter/cli/cmd/config"
+// 	"github.com/porter-dev/porter/cli/cmd/deploy"
+// 	"github.com/porter-dev/switchboard/v2/pkg/types"
+// )
+
+// type DefaultDriver struct {
+// 	Vars      map[string]string
+// 	Env       map[string]string
+// 	Builds    []*types.Build
+// 	APIClient *api.Client
+// 	Namespace string
+
+// 	allErrors []error
+// }
+
+// func (d *DefaultDriver) PreApply(resource *types.YAMLNode[*types.Resource]) error {
+// 	return nil
+// }
+
+// func (d *DefaultDriver) Apply(resource *types.YAMLNode[*types.Resource]) error {
+// 	if isPorterApp(resource) {
+// 		return d.applyPorterApp(resource)
+// 	}
+
+// 	// everything else is an addon
+// 	return d.applyAddon(resource)
+// }
+
+// func (d *DefaultDriver) PostApply(resource *types.YAMLNode[*types.Resource]) error {
+// 	return nil
+// }
+
+// func (d *DefaultDriver) OnError(resource *types.YAMLNode[*types.Resource], errs []error) {
+
+// }
+
+// func isPorterApp(resource *types.YAMLNode[*types.Resource]) bool {
+// 	if resource.GetValue().ChartURL.GetValue() == "https://charts.getporter.dev" &&
+// 		(resource.GetValue().Type.GetValue() == "web" ||
+// 			resource.GetValue().Type.GetValue() == "worker" ||
+// 			resource.GetValue().Type.GetValue() == "job") {
+// 		return true
+// 	}
+
+// 	return false
+// }
+
+// func (d *DefaultDriver) applyPorterApp(resource *types.YAMLNode[*types.Resource]) error {
+// 	appBuild := &porterAppBuild{}
+// 	appDeploy := &porterAppDeploy{}
+// 	buildNode := resource.GetValue().Build.GetRawYAMLNode()
+// 	deployNode := resource.GetValue().Deploy.GetRawYAMLNode()
+
+// 	err := buildNode.Decode(appBuild)
+
+// 	if err != nil {
+// 		return err // FIXME: descriptive error
+// 	}
+
+// 	err = deployNode.Decode(appDeploy)
+
+// 	if err != nil {
+// 		return err // FIXME: descriptive error
+// 	}
+
+// 	var buildConfig *types.Build
+
+// 	if appBuild.Ref != "" {
+// 		for _, b := range d.Builds {
+// 			if b.Name.GetValue() == appBuild.Ref {
+// 				buildConfig = b
+// 				break
+// 			}
+// 		}
+
+// 		if buildConfig == nil {
+// 			// this should not happen
+// 			return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
+// 				"error:\n-----\nERROR: invalid build ref given for app '%s'", resource.GetValue().Name.GetValue())
+// 		}
+// 	} else {
+// 		buildConfig = appBuild.Build
+// 	}
+
+// 	if buildConfig == nil {
+// 		// this should not happen
+// 		return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
+// 			"error:\n-----\nERROR: neither build ref nor build body given for app '%s'", resource.GetValue().Name.GetValue())
+// 	}
+
+// 	if resource.GetValue().Type.GetValue() == "job" {
+// 		jobConfig := &porterJob{}
+// 		jobNode := resource.GetRawYAMLNode()
+
+// 		err := jobNode.Decode(jobConfig)
+
+// 		if err != nil {
+// 			return err // FIXME: descriptive error
+// 		}
+
+// 		return d.applyJob(resource, buildConfig, appDeploy, jobConfig)
+// 	} else if oneOf(resource.GetValue().Type.GetValue(), "web", "worker") {
+
+// 	} else {
+// 		// this should not happen
+// 		return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
+// 			"error:\n-----\nERROR: app '%s' is not one of 'web', 'worker', 'job'", resource.GetValue().Name.GetValue())
+// 	}
+
+// 	return nil
+// }
+
+// func (d *DefaultDriver) applyAddon(resource *types.YAMLNode[*types.Resource]) error {
+// 	return nil
+// }
+
+// func (d *DefaultDriver) applyJob(
+// 	resource *types.YAMLNode[*types.Resource],
+// 	buildConfig *types.Build,
+// 	appDeploy *porterAppDeploy,
+// 	jobConfig *porterJob,
+// ) error {
+// 	_, err := d.APIClient.GetRelease(
+// 		context.Background(),
+// 		config.GetCLIConfig().Project,
+// 		config.GetCLIConfig().Cluster,
+// 		d.Namespace,
+// 		resource.GetValue().Name.GetValue(),
+// 	)
+
+// 	exists := err == nil
+
+// 	flattenedBuildEnv := make(map[string]string)
+
+// 	for k, v := range buildConfig.Env {
+// 		flattenedBuildEnv[k.GetValue()] = v.GetValue()
+// 	}
+
+// 	var flattenedBuildEnvGroup []apiTypes.EnvGroupMeta
+
+// 	for _, egName := range buildConfig.EnvGroups {
+// 		flattenedBuildEnvGroup = append(flattenedBuildEnvGroup, apiTypes.EnvGroupMeta{
+// 			Name:      egName.GetValue(),
+// 			Namespace: d.Namespace,
+// 		})
+// 	}
+
+// 	tag := getImageTag()
+
+// 	sharedOpts := &deploy.SharedOpts{
+// 		ProjectID:       config.GetCLIConfig().Project,
+// 		ClusterID:       config.GetCLIConfig().Cluster,
+// 		Namespace:       d.Namespace,
+// 		LocalPath:       buildConfig.Context.GetValue(),
+// 		LocalDockerfile: buildConfig.Dockerfile.GetValue(),
+// 		OverrideTag:     tag,
+// 		Method:          deploy.DeployBuildType(buildConfig.Method.GetValue()),
+// 		AdditionalEnv:   flattenedBuildEnv,
+// 		EnvGroups:       flattenedBuildEnvGroup,
+// 	}
+
+// 	if buildConfig.Method.GetValue() == "pack" && buildConfig.UseCache != nil {
+// 		sharedOpts.UseCache = buildConfig.UseCache.GetValue()
+// 	}
+
+// 	if exists {
+// 		if jobConfig.Once {
+// 			// since the job already exists and was marked 'once', simply return
+// 			return nil
+// 		}
+
+// 		updateAgent, err := deploy.NewDeployAgent(d.APIClient, resource.GetValue().Name.GetValue(), &deploy.DeployOpts{
+// 			SharedOpts: sharedOpts,
+// 			Local:      buildConfig.Method.GetValue() != "registry",
+// 		})
+
+// 		if err != nil {
+// 			return fmt.Errorf("[porter.yaml v2][app:%s] error creating deploy agent to update app: %w",
+// 				resource.GetValue().Name.GetValue(), err)
+// 		}
+
+// 		// if the build method is registry, we do not trigger a build
+// 		if buildConfig.Method.GetValue() != "registry" {
+// 			buildEnv, err := updateAgent.GetBuildEnv(&deploy.GetBuildEnvOpts{
+// 				UseNewConfig: true,
+// 				// NewConfig:    appConf.Values,
+// 			})
+
+// 			if err != nil {
+// 				return err // FIXME
+// 			}
+
+// 			err = updateAgent.SetBuildEnv(buildEnv)
+
+// 			if err != nil {
+// 				return err // FIXME
+// 			}
+
+// 			var bc *apiTypes.BuildConfig
+
+// 			if buildConfig.Method.GetValue() == "pack" {
+// 				// FIXME: temporary fix
+// 				var bp []string
+
+// 				for _, b := range buildConfig.Buildpacks {
+// 					bp = append(bp, b.GetValue())
+// 				}
+
+// 				bc = &apiTypes.BuildConfig{
+// 					Builder:    buildConfig.Builder.GetValue(),
+// 					Buildpacks: bp,
+// 				}
+// 			}
+
+// 			err = updateAgent.Build(bc)
+
+// 			if err != nil {
+// 				return err // FIXME
+// 			}
+
+// 			// if !appConf.Build.UseCache { // FIXME
+// 			err = updateAgent.Push()
+
+// 			if err != nil {
+// 				return err // FIXME
+// 			}
+// 			// }
+// 		}
+
+// 		// err = updateAgent.UpdateImageAndValues(appConf.Values) // FIXME
+
+// 		// if err != nil {
+// 		// 	return err // FIXME
+// 		// }
+// 	} else { // create the job
+// 		// attempt to get repo suffix from environment variables
+// 		var repoSuffix string
+
+// 		if repoName := os.Getenv("PORTER_REPO_NAME"); repoName != "" {
+// 			if repoOwner := os.Getenv("PORTER_REPO_OWNER"); repoOwner != "" {
+// 				repoSuffix = strings.ToLower(strings.ReplaceAll(fmt.Sprintf("%s-%s", repoOwner, repoName), "_", "-"))
+// 			}
+// 		}
+
+// 		var registryURL string
+
+// 		if buildConfig.ImageRepoURI != nil {
+// 			registryURL = buildConfig.ImageRepoURI.GetValue()
+// 		}
+
+// 		if registryURL == "" {
+// 			regList, err := d.APIClient.ListRegistries(context.Background(), config.GetCLIConfig().Project)
+
+// 			if err != nil {
+// 				return fmt.Errorf("error fetching list of registries while trying to choose registry to deploy new"+
+// 					" image for app '%s': %w", resource.GetValue().Name.GetValue(), err)
+// 			}
+
+// 			if len(*regList) == 0 {
+// 				return fmt.Errorf("no registries linked with project, needed to deploy new image for app '%s'",
+// 					resource.GetValue().Name.GetValue())
+// 			} else {
+// 				registryURL = (*regList)[0].URL
+// 			}
+// 		}
+
+// 		createAgent := &deploy.CreateAgent{
+// 			Client: d.APIClient,
+// 			CreateOpts: &deploy.CreateOpts{
+// 				SharedOpts:  sharedOpts,
+// 				Kind:        resource.GetValue().Type.GetValue(),
+// 				ReleaseName: resource.GetValue().Name.GetValue(),
+// 				RegistryURL: registryURL,
+// 				RepoSuffix:  repoSuffix,
+// 			},
+// 		}
+
+// 		if buildConfig.Method.GetValue() == "registry" {
+// 			flattenedDeployMap := make(map[string]any)
+
+// 			for k, v := range resource.GetValue().Deploy.GetValue() {
+// 				flattenedDeployMap[k.GetValue()] = v.GetValue()
+// 			}
+
+// 			values := &porterWebChartValues{}
+
+// 			// delete the aliases from the deploy section
+// 			delete(flattenedDeployMap, "command")
+// 			delete(flattenedDeployMap, "cpu")
+// 			delete(flattenedDeployMap, "memory")
+
+// 			// replace alias values to the original expect yaml values
+// 			values.Container.Command = appDeploy.Command
+// 			values.Container.Env.Build = flattenedBuildEnv
+// 			values.Container.Env.Normal = appDeploy.Env
+// 			// values.Container.Env.Synced
+// 			values.Resources.Requests.CPU = appDeploy.CPU
+// 			values.Resources.Requests.Memory = appDeploy.Memory
+// 			if len(appDeploy.Hosts) > 0 {
+// 				values.Ingress.CustomDomain = true
+// 				values.Ingress.Hosts = appDeploy.Hosts
+// 			}
+
+// 			overrideValues := make(map[string]any)
+
+// 			err = mapstructure.Decode(values, &overrideValues)
+
+// 			if err != nil {
+// 				return err // FIXME
+// 			}
+
+// 			_, err := createAgent.CreateFromRegistry("", overrideValues)
+
+// 			if err != nil {
+// 				return fmt.Errorf("[porter.yaml v2][app:%s] error creating job: %w", resource.GetValue().Name.GetValue(), err)
+// 			}
+// 		} else if oneOf(buildConfig.Method.GetValue(), "pack", "docker") {
+// 			_, err := createAgent.CreateFromDocker(nil, "", nil)
+
+// 			if err != nil {
+// 				return fmt.Errorf("[porter.yaml v2][app:%s] error creating job: %w", resource.GetValue().Name.GetValue(), err)
+// 			}
+// 		} else {
+// 			// this should not happen
+// 			return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
+// 				"error:\n-----\nERROR: build method was not one of 'pack', 'docker', 'registry' for app '%s'",
+// 				resource.GetValue().Name.GetValue())
+// 		}
+// 	}
+
+// 	return nil
+// }
+
+// // fetching the image tag works in 3 steps
+// //   - read PORTER_TAG env var
+// //   - read the git SHA from the current directory
+// //   - default to 'latest' tag
+// func getImageTag() string {
+// 	tag := os.Getenv("PORTER_TAG")
+
+// 	if tag == "" {
+// 		commit, err := git.LastCommit()
+
+// 		if err == nil {
+// 			tag = commit.Sha[:7]
+
+// 			color.New(color.FgBlue).Printf("[porter.yaml v2] PORTER_TAG not defined, falling back to image tag '%s'"+
+// 				" from git SHA\n", tag)
+// 		}
+// 	} else {
+// 		color.New(color.FgBlue).Printf("[porter.yaml v2] Using image tag '%s' from PORTER_TAG environment variable\n", tag)
+// 	}
+
+// 	if tag == "" {
+// 		color.New(color.FgBlue).Println("[porter.yaml v2] PORTER_TAG not defined, not a git repository, falling back" +
+// 			" to image tag 'latest'")
+
+// 		tag = "latest"
+// 	}
+
+// 	return tag
+// }

+ 14 - 11
cli/cmd/preview/v2beta1/types.go

@@ -13,18 +13,21 @@ type EnvGroup struct {
 	CloneFrom *string `yaml:"clone_from" validate:"required"`
 }
 
+type BuildEnv struct {
+	Raw        map[*string]*string `yaml:"raw"`
+	ImportFrom []*string           `yaml:"import_from"`
+}
+
 type Build struct {
-	Name         *string             `yaml:"name" validate:"required"`
-	Context      *string             `yaml:"context" validate:"dir"`
-	Method       *string             `yaml:"method" validate:"required,oneof=pack docker registry"`
-	Builder      *string             `yaml:"builder" validate:"required_if=Method pack"`
-	Buildpacks   []*string           `yaml:"buildpacks"`
-	Dockerfile   *string             `yaml:"dockerfile" validate:"required_if=Method docker"`
-	Image        *string             `yaml:"image" validate:"required_if=Method registry"`
-	Env          map[*string]*string `yaml:"env"`
-	EnvGroups    []*string           `yaml:"env_groups"`
-	UseCache     *bool               `yaml:"use_cache"`
-	ImageRepoURI *string             `yaml:"image_repo_uri"`
+	Name       *string   `yaml:"name" validate:"required"`
+	Context    *string   `yaml:"context" validate:"dir"`
+	Method     *string   `yaml:"method" validate:"required,oneof=pack docker registry"`
+	Builder    *string   `yaml:"builder" validate:"required_if=Method pack"`
+	Buildpacks []*string `yaml:"buildpacks"`
+	Dockerfile *string   `yaml:"dockerfile" validate:"required_if=Method docker"`
+	Image      *string   `yaml:"image" validate:"required_if=Method registry"`
+	Env        *BuildEnv `yaml:"env"`
+	// UseCache   *bool     `yaml:"use_cache"`
 }
 
 type Resource struct {