Repository: GoogleContainerTools/skaffold
Pull request #7553 (2022-06-15 19:37:13)

chore: fix flaky test -TestDevAutoSyncAPITrigger
<!-- Thank you for your contribution! -->

<!-- Include if applicable: -->
Fixes: #7551  <!-- tracking issues that this PR will close -->
**Related**:  
 - The same issue as #5615

**Test Flakyness Reason**
 - rpc.ClientAutoSync will invoke /proto.SkaffoldService/AutoSync method which calls [UpdateStateAutoSyncTrigger](https://github.com/ericzzzzzzz/skaffold/blob/TestDevAutoSyncAPITrigger/pkg/skaffold/event/event.go#L765-L769) method, this does deepCopy for handler.state but state.StatusCheckState.Resource will be set to nil if the original Resource is an empty map. 
 - [pollResourceStatus](https://github.com/ericzzzzzzz/skaffold/blob/TestDevAutoSyncAPITrigger/pkg/skaffold/kubernetes/status/status_check.go#L235) emits Event_ResourceStatusCheckEvent, if ``UpdateStateAutoSyncTrigger`` happens first then Resources map will become nil from empty map , so when event handler processes the event it will fail. If Event_ResourceStatusCheckEvent happen first, then things are ok. 

**Description**
 - assign a new map to ev.state.StatusCheckState.Resources if nil when handling Event_ResourceStatusCheckEvent 




Patch:
diff --git a/pkg/skaffold/event/event.go b/pkg/skaffold/event/event.go
index 02b90f732..4ded9b326 100644
--- a/pkg/skaffold/event/event.go
+++ b/pkg/skaffold/event/event.go
@@ -654,6 +654,9 @@ func (ev *eventHandler) handleExec(f firedEvent) {
 		rse := e.ResourceStatusCheckEvent
 		rseName := rse.Resource
 		ev.stateLock.Lock()
+		if ev.state.StatusCheckState.Resources == nil {
+			ev.state.StatusCheckState.Resources = map[string]string{}
+		}
 		ev.state.StatusCheckState.Resources[rseName] = rse.Status
 		ev.stateLock.Unlock()
 		switch rse.Status {
diff --git a/pkg/skaffold/initializer/config.go b/pkg/skaffold/initializer/config.go
index 308389116..49bc7f5a5 100644
--- a/pkg/skaffold/initializer/config.go
+++ b/pkg/skaffold/initializer/config.go
@@ -25,6 +25,7 @@ import (
 
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/build"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/deploy"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/render"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/warnings"
@@ -35,7 +36,7 @@ var (
 	getWd = os.Getwd
 )
 
-func generateSkaffoldConfig(b build.Initializer, d deploy.Initializer) *latest.SkaffoldConfig {
+func generateSkaffoldConfig(b build.Initializer, r render.Initializer, d deploy.Initializer) *latest.SkaffoldConfig {
 	// if we're here, the user has no skaffold yaml so we need to generate one
 	// if the user doesn't have any k8s yamls, generate one for each dockerfile
 	log.Entry(context.TODO()).Info("generating skaffold config")
@@ -45,8 +46,9 @@ func generateSkaffoldConfig(b build.Initializer, d deploy.Initializer) *latest.S
 		warnings.Printf("Couldn't generate default config name: %s", err.Error())
 	}
 
-	deploy, profiles := d.DeployConfig()
-	build, portForward := b.BuildConfig()
+	renderConfig, profiles := r.RenderConfig()
+	deployConfig := d.DeployConfig()
+	buildConfig, portForward := b.BuildConfig()
 
 	return &latest.SkaffoldConfig{
 		APIVersion: latest.Version,
@@ -55,8 +57,9 @@ func generateSkaffoldConfig(b build.Initializer, d deploy.Initializer) *latest.S
 			Name: name,
 		},
 		Pipeline: latest.Pipeline{
-			Build:       build,
-			Deploy:      deploy,
+			Build:       buildConfig,
+			Render:      renderConfig,
+			Deploy:      deployConfig,
 			PortForward: portForward,
 		},
 		Profiles: profiles,
diff --git a/pkg/skaffold/initializer/deploy/helm.go b/pkg/skaffold/initializer/deploy/helm.go
index f14442426..8fb5ca62e 100644
--- a/pkg/skaffold/initializer/deploy/helm.go
+++ b/pkg/skaffold/initializer/deploy/helm.go
@@ -20,16 +20,12 @@ import (
 	"context"
 	"io/ioutil"
 	"os"
-	"os/exec"
 	"path/filepath"
 	"strings"
 
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/analyze"
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/errors"
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/yaml"
 )
 
@@ -39,9 +35,7 @@ const (
 
 // for testing
 var (
-	readFile    = ioutil.ReadFile
-	tempDir     = ioutil.TempDir
-	osRemoveAll = os.RemoveAll
+	readFile = ioutil.ReadFile
 )
 
 // helm implements deploymentInitializer for the helm deployer.
@@ -76,7 +70,7 @@ func newHelmInitializer(chartValuesMap map[string][]string) helm {
 
 // DeployConfig implements the Initializer interface and generates
 // a helm configuration
-func (h helm) DeployConfig() (latest.DeployConfig, []latest.Profile) {
+func (h helm) DeployConfig() latest.DeployConfig {
 	releases := []latest.HelmRelease{}
 	for _, ch := range h.charts {
 		// to make skaffold.yaml more portable across OS-es we should always generate /-delimited filePaths
@@ -100,59 +94,7 @@ func (h helm) DeployConfig() (latest.DeployConfig, []latest.Profile) {
 				Releases: releases,
 			},
 		},
-	}, nil
-}
-
-// Validate implements the Initializer interface and ensures
-// we have at least one manifest before generating a config
-func (h helm) Validate() error {
-	if len(h.charts) == 0 {
-		return errors.NoHelmChartsErr{}
 	}
-	return nil
-}
-
-// we don't generate manifests for helm
-func (h helm) AddManifestForImage(string, string) {}
-
-// GetImages return an empty string for helm.
-func (h helm) GetImages() []string {
-	// Run helm template in each top level dir.
-	// Parse templated manifest files and then get image names.
-	artifacts := []string{}
-	td, err := tempDir("", "skaffold_")
-	if err != nil {
-		log.Entry(context.TODO()).Fatalf("cannot create temporary directory. Encountered error: %s", err)
-	}
-	defer osRemoveAll(td)
-	for _, ch := range h.charts {
-		args := []string{"template", ch.path}
-		for _, v := range ch.valueFiles {
-			args = append(args, "-f", v)
-		}
-		o, err := tempDir(td, ch.name)
-		if err != nil {
-			log.Entry(context.TODO()).Fatalf("cannot create temporary directory. Encountered error: %s", err)
-		}
-		args = append(args, "--output-dir", o)
-		cmd := exec.Command("helm", args...)
-		err = util.RunCmd(context.TODO(), cmd)
-		if err != nil {
-			log.Entry(context.TODO()).Warnf("could not initialize builders for helm chart %q.\nCommand %q encountered error: %s", ch.name, cmd, err)
-			continue
-		}
-		// read all templates generated
-		files := getAllFiles(o)
-		for _, file := range files {
-			images, err := kubernetes.ParseImagesFromKubernetesYaml(file)
-			if err != nil {
-				log.Entry(context.TODO()).Warnf("could not initialize builder for helm chart %q.\nCould not parse %q output due to error: %s", ch.name, cmd, err)
-			} else {
-				artifacts = append(artifacts, images...)
-			}
-		}
-	}
-	return artifacts
 }
 
 func parseChartValues(fp string) (map[string]interface{}, error) {
@@ -193,21 +135,3 @@ func getVersion(m map[string]interface{}) string {
 	}
 	return ""
 }
-
-func getAllFiles(o string) []string {
-	var files []string
-	err := filepath.Walk(o, func(path string, info os.FileInfo, err error) error {
-		if err != nil {
-			return err
-		}
-		if info.IsDir() {
-			return nil
-		}
-		files = append(files, path)
-		return nil
-	})
-	if err != nil {
-		log.Entry(context.TODO()).Fatalf("could not walk directory %q due to error: %s", o, err)
-	}
-	return files
-}
diff --git a/pkg/skaffold/initializer/deploy/init.go b/pkg/skaffold/initializer/deploy/init.go
index b540521f8..1903c8dbd 100644
--- a/pkg/skaffold/initializer/deploy/init.go
+++ b/pkg/skaffold/initializer/deploy/init.go
@@ -19,80 +19,30 @@ package deploy
 import (
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/analyze"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/config"
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/errors"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
 )
 
 // Initializer detects a deployment type and is able to extract image names from it
 type Initializer interface {
-	// deployConfig generates Deploy Config for skaffold configuration.
-	DeployConfig() (latest.DeployConfig, []latest.Profile)
-	// GetImages fetches all the images defined in the manifest files.
-	GetImages() []string
-	// Validate ensures preconditions are met before generating a skaffold config
-	Validate() error
-	// AddManifestForImage adds a provided manifest for a given image to the initializer
-	AddManifestForImage(string, string)
+	// DeployConfig generates Deploy Config for skaffold configuration.
+	DeployConfig() latest.DeployConfig
 }
 
-type cliDeployInit struct {
-	cliKubernetesManifests []string
-}
-
-func (c *cliDeployInit) DeployConfig() (latest.DeployConfig, []latest.Profile) {
-	return latest.DeployConfig{
-		DeployType: latest.DeployType{
-			KubectlDeploy: &latest.KubectlDeploy{
-				Manifests: c.cliKubernetesManifests,
-			},
-		},
-	}, nil
-}
-
-func (c *cliDeployInit) GetImages() []string {
-	return nil
-}
-
-func (c *cliDeployInit) Validate() error {
-	if len(c.cliKubernetesManifests) == 0 {
-		return errors.NoManifestErr{}
-	}
-	return nil
-}
-
-func (c *cliDeployInit) AddManifestForImage(string, string) {}
-
 type emptyDeployInit struct {
 }
 
-func (e *emptyDeployInit) DeployConfig() (latest.DeployConfig, []latest.Profile) {
-	return latest.DeployConfig{}, nil
-}
-
-func (e *emptyDeployInit) GetImages() []string {
-	return nil
+func (e *emptyDeployInit) DeployConfig() latest.DeployConfig {
+	return latest.DeployConfig{}
 }
 
-func (e *emptyDeployInit) Validate() error {
-	return nil
-}
-
-func (e *emptyDeployInit) AddManifestForImage(string, string) {}
-
-// if any CLI manifests are provided, we always use those as part of a kubectl deploy first
-// if not, then if a kustomization yaml is found, we use that next
-// otherwise, default to a kubectl deploy.
-func NewInitializer(manifests, bases, kustomizations []string, h analyze.HelmChartInfo, c config.Config) Initializer {
+// NewInitializer if any helm charts are provided we use HelmInitializer, otherwise we use empty initializer.
+func NewInitializer(h analyze.HelmChartInfo, c config.Config) Initializer {
 	switch {
 	case c.SkipDeploy:
 		return &emptyDeployInit{}
-	case len(c.CliKubernetesManifests) > 0:
-		return &cliDeployInit{c.CliKubernetesManifests}
-	case len(kustomizations) > 0:
-		return newKustomizeInitializer(c.DefaultKustomization, bases, kustomizations, manifests)
 	case len(h.Charts()) > 0:
 		return newHelmInitializer(h.Charts())
 	default:
-		return newKubectlInitializer(manifests)
+		return &emptyDeployInit{}
 	}
 }
diff --git a/pkg/skaffold/initializer/init.go b/pkg/skaffold/initializer/init.go
index 2d23fc4b8..c91b23092 100644
--- a/pkg/skaffold/initializer/init.go
+++ b/pkg/skaffold/initializer/init.go
@@ -28,6 +28,7 @@ import (
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/config"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/deploy"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/prompt"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/render"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/yaml"
 )
@@ -67,8 +68,9 @@ func AnalyzeProject(c config.Config) (*analyze.ProjectAnalysis, error) {
 // Initialize uses the information gathered by the analyzer to create a skaffold config and generate kubernetes manifests.
 // The returned map[string][]byte represents a mapping from generated config name to its respective manifest data held in a []byte
 func Initialize(out io.Writer, c config.Config, a *analyze.ProjectAnalysis) (*latest.SkaffoldConfig, map[string][]byte, error) {
-	deployInitializer := deploy.NewInitializer(a.Manifests(), a.KustomizeBases(), a.KustomizePaths(), a.HelmChartInfo(), c)
-	images := deployInitializer.GetImages()
+	renderInitializer := render.NewInitializer(a.Manifests(), a.KustomizeBases(), a.KustomizePaths(), a.HelmChartInfo(), c)
+	deployInitializer := deploy.NewInitializer(a.HelmChartInfo(), c)
+	images := renderInitializer.GetImages()
 
 	buildInitializer := build.NewInitializer(a.Builders(), c)
 	if err := buildInitializer.ProcessImages(images); err != nil {
@@ -79,19 +81,19 @@ func Initialize(out io.Writer, c config.Config, a *analyze.ProjectAnalysis) (*la
 		return nil, nil, buildInitializer.PrintAnalysis(out)
 	}
 
-	newManifests, err := generateManifests(out, c, buildInitializer, deployInitializer)
+	newManifests, err := generateManifests(out, c, buildInitializer, renderInitializer)
 	if err != nil {
 		return nil, nil, err
 	}
 
-	if errV := deployInitializer.Validate(); errV != nil {
+	if errV := renderInitializer.Validate(); errV != nil {
 		return nil, nil, errV
 	}
 
-	return generateSkaffoldConfig(buildInitializer, deployInitializer), newManifests, nil
+	return generateSkaffoldConfig(buildInitializer, renderInitializer, deployInitializer), newManifests, nil
 }
 
-func generateManifests(out io.Writer, c config.Config, bInitializer build.Initializer, dInitializer deploy.Initializer) (map[string][]byte, error) {
+func generateManifests(out io.Writer, c config.Config, bInitializer build.Initializer, rInitializer render.Initializer) (map[string][]byte, error) {
 	var generatedManifests map[string][]byte
 
 	generatedManifestPairs, err := bInitializer.GenerateManifests(out, c.Force, c.EnableManifestGeneration)
@@ -100,7 +102,7 @@ func generateManifests(out io.Writer, c config.Config, bInitializer build.Initia
 	}
 	generatedManifests = make(map[string][]byte, len(generatedManifestPairs))
 	for pair, manifest := range generatedManifestPairs {
-		dInitializer.AddManifestForImage(pair.ManifestPath, pair.ImageName)
+		rInitializer.AddManifestForImage(pair.ManifestPath, pair.ImageName)
 		generatedManifests[pair.ManifestPath] = manifest
 	}
 
diff --git a/pkg/skaffold/initializer/render/helm.go b/pkg/skaffold/initializer/render/helm.go
new file mode 100644
index 000000000..da451b2f9
--- /dev/null
+++ b/pkg/skaffold/initializer/render/helm.go
@@ -0,0 +1,188 @@
+/*
+Copyright 2022 The Skaffold Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package render
+
+import (
+	"context"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/analyze"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/errors"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/yaml"
+)
+
+const (
+	nameKey = "name"
+)
+
+// for testing
+var (
+	readFile    = ioutil.ReadFile
+	tempDir     = ioutil.TempDir
+	osRemoveAll = os.RemoveAll
+)
+
+// helm implements deploymentInitializer for the helm deployer.
+type helm struct {
+	charts []chart
+}
+
+type chart struct {
+	name        string
+	chartValues map[string]interface{}
+	path        string
+	valueFiles  []string
+	version     string
+}
+
+// newHelmInitializer returns a helm config generator.
+func newHelmInitializer(chartValuesMap map[string][]string) helm {
+	var charts []chart
+	for chDir, vfs := range chartValuesMap {
+		chFile := filepath.Join(chDir, analyze.ChartYaml)
+		parsed, err := parseChartValues(chFile)
+		if err != nil {
+			log.Entry(context.TODO()).Infof("Skipping chart dir %s, as %s could not be parsed as valid yaml", chDir, chFile)
+			continue
+		}
+		charts = append(charts, buildChart(parsed, chDir, vfs))
+	}
+	return helm{
+		charts: charts,
+	}
+}
+
+func (h helm) AddManifestForImage(string, string) {}
+
+// RenderConfig implements the Initializer interface and generates
+// skaffold kubectl render config.
+func (h helm) RenderConfig() (latest.RenderConfig, []latest.Profile) {
+	return latest.RenderConfig{}, nil
+}
+
+// Validate implements the Initializer interface and ensures
+// we have at least one manifest before generating a config
+func (h helm) Validate() error {
+	if len(h.charts) == 0 {
+		return errors.NoHelmChartsErr{}
+	}
+	return nil
+}
+
+// GetImages return an empty string for helm.
+func (h helm) GetImages() []string {
+	// Run helm template in each top level dir.
+	// Parse templated manifest files and then get image names.
+	artifacts := []string{}
+	td, err := tempDir("", "skaffold_")
+	if err != nil {
+		log.Entry(context.TODO()).Fatalf("cannot create temporary directory. Encountered error: %s", err)
+	}
+	defer osRemoveAll(td)
+	for _, ch := range h.charts {
+		args := []string{"template", ch.path}
+		for _, v := range ch.valueFiles {
+			args = append(args, "-f", v)
+		}
+		o, err := tempDir(td, ch.name)
+		if err != nil {
+			log.Entry(context.TODO()).Fatalf("cannot create temporary directory. Encountered error: %s", err)
+		}
+		args = append(args, "--output-dir", o)
+		cmd := exec.Command("helm", args...)
+		err = util.RunCmd(context.TODO(), cmd)
+		if err != nil {
+			log.Entry(context.TODO()).Warnf("could not initialize builders for helm chart %q.\nCommand %q encountered error: %s", ch.name, cmd, err)
+			continue
+		}
+		// read all templates generated
+		files := getAllFiles(o)
+		for _, file := range files {
+			images, err := kubernetes.ParseImagesFromKubernetesYaml(file)
+			if err != nil {
+				log.Entry(context.TODO()).Warnf("could not initialize builder for helm chart %q.\nCould not parse %q output due to error: %s", ch.name, cmd, err)
+			} else {
+				artifacts = append(artifacts, images...)
+			}
+		}
+	}
+	return artifacts
+}
+
+func parseChartValues(fp string) (map[string]interface{}, error) {
+	in, err := readFile(fp)
+	if err != nil {
+		return nil, err
+	}
+	m := map[string]interface{}{}
+	if errY := yaml.UnmarshalStrict(in, &m); errY != nil {
+		return nil, errY
+	}
+	return m, nil
+}
+
+func getChartName(parsed map[string]interface{}, chDir string) string {
+	if v, ok := parsed[nameKey]; ok {
+		return v.(string)
+	}
+	return filepath.Base(chDir)
+}
+
+func buildChart(parsed map[string]interface{}, chDir string, vfs []string) chart {
+	ch := chart{
+		chartValues: parsed,
+		name:        getChartName(parsed, chDir),
+		path:        chDir,
+		valueFiles:  vfs,
+	}
+	if v := getVersion(parsed); v != "" {
+		ch.version = v
+	}
+	return ch
+}
+
+func getVersion(m map[string]interface{}) string {
+	if v, ok := m["version"]; ok {
+		return v.(string)
+	}
+	return ""
+}
+
+func getAllFiles(o string) []string {
+	var files []string
+	err := filepath.Walk(o, func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		if info.IsDir() {
+			return nil
+		}
+		files = append(files, path)
+		return nil
+	})
+	if err != nil {
+		log.Entry(context.TODO()).Fatalf("could not walk directory %q due to error: %s", o, err)
+	}
+	return files
+}
diff --git a/pkg/skaffold/initializer/render/init.go b/pkg/skaffold/initializer/render/init.go
new file mode 100644
index 000000000..4ce9d2dcd
--- /dev/null
+++ b/pkg/skaffold/initializer/render/init.go
@@ -0,0 +1,75 @@
+/*
+Copyright 2022 The Skaffold Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package render
+
+import (
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/analyze"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/config"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/errors"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
+)
+
+// Initializer detects a deployment type and is able to extract image names from it
+type Initializer interface {
+	// renderConfig generates Render Config for skaffold configuration.
+	RenderConfig() (latest.RenderConfig, []latest.Profile)
+	// GetImages fetches all the images defined in the manifest files.
+	GetImages() []string
+	// Validate ensures preconditions are met before generating a skaffold config
+	Validate() error
+	// AddManifestForImage adds a provided manifest for a given image to the initializer
+	AddManifestForImage(string, string)
+}
+
+type cliManifestsInit struct {
+	cliKubernetesManifests []string
+}
+
+func (c *cliManifestsInit) RenderConfig() (latest.RenderConfig, []latest.Profile) {
+	return latest.RenderConfig{
+		Generate: latest.Generate{RawK8s: c.cliKubernetesManifests},
+	}, nil
+}
+
+func (c *cliManifestsInit) GetImages() []string {
+	return nil
+}
+
+func (c *cliManifestsInit) Validate() error {
+	if len(c.cliKubernetesManifests) == 0 {
+		return errors.NoManifestErr{}
+	}
+	return nil
+}
+
+func (c *cliManifestsInit) AddManifestForImage(string, string) {}
+
+// if any CLI manifests are provided, we always use those as part of a kubectl render first
+// if not, then if a kustomization yaml is found, we use that next
+// otherwise, default to a kubectl render.
+func NewInitializer(manifests, bases, kustomizations []string, h analyze.HelmChartInfo, c config.Config) Initializer {
+	switch {
+	case len(c.CliKubernetesManifests) > 0:
+		return &cliManifestsInit{c.CliKubernetesManifests}
+	case len(kustomizations) > 0:
+		return newKustomizeInitializer(c.DefaultKustomization, bases, kustomizations, manifests)
+	case len(h.Charts()) > 0:
+		return newHelmInitializer(h.Charts())
+	default:
+		return newKubectlInitializer(manifests)
+	}
+}
diff --git a/pkg/skaffold/initializer/deploy/kubectl.go b/pkg/skaffold/initializer/render/kubectl.go
similarity index 81%
rename from pkg/skaffold/initializer/deploy/kubectl.go
rename to pkg/skaffold/initializer/render/kubectl.go
index 7c732e6b0..c3ffa32fa 100644
--- a/pkg/skaffold/initializer/deploy/kubectl.go
+++ b/pkg/skaffold/initializer/render/kubectl.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2019 The Skaffold Authors
+Copyright 2022 The Skaffold Authors
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package deploy
+package render
 
 import (
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/errors"
@@ -22,7 +22,7 @@ import (
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
 )
 
-// kubectl implements deploymentInitializer for the kubectl deployer.
+// kubectl implements render Initializer for the kubectl renderer.
 type kubectl struct {
 	configs []string // the k8s manifest files present in the project
 	images  []string // the images parsed from the k8s manifest files
@@ -44,14 +44,12 @@ func newKubectlInitializer(potentialConfigs []string) *kubectl {
 	}
 }
 
-// deployConfig implements the Initializer interface and generates
-// skaffold kubectl deployment config.
-func (k *kubectl) DeployConfig() (latest.DeployConfig, []latest.Profile) {
-	return latest.DeployConfig{
-		DeployType: latest.DeployType{
-			KubectlDeploy: &latest.KubectlDeploy{
-				Manifests: k.configs,
-			},
+// RenderConfig implements the Initializer interface and generates
+// skaffold kubectl render config.
+func (k *kubectl) RenderConfig() (latest.RenderConfig, []latest.Profile) {
+	return latest.RenderConfig{
+		Generate: latest.Generate{
+			RawK8s: k.configs,
 		},
 	}, nil
 }
diff --git a/pkg/skaffold/initializer/deploy/kustomize.go b/pkg/skaffold/initializer/render/kustomize.go
similarity index 74%
rename from pkg/skaffold/initializer/deploy/kustomize.go
rename to pkg/skaffold/initializer/render/kustomize.go
index 1903e978c..f67a59c10 100644
--- a/pkg/skaffold/initializer/deploy/kustomize.go
+++ b/pkg/skaffold/initializer/render/kustomize.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2020 The Skaffold Authors
+Copyright 2022 The Skaffold Authors
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -14,13 +14,12 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package deploy
+package render
 
 import (
 	"context"
 	"path/filepath"
 
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy/kustomize/constants"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/initializer/errors"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
@@ -52,25 +51,20 @@ func newKustomizeInitializer(defaultKustomization string, bases, kustomizations,
 	}
 }
 
-// deployConfig implements the Initializer interface and generates
+// RenderConfig implements the Initializer interface and generates
 // a kustomize deployment config.
-func (k *kustomize) DeployConfig() (latest.DeployConfig, []latest.Profile) {
-	var kustomizeConfig *latest.KustomizeDeploy
+func (k *kustomize) RenderConfig() (latest.RenderConfig, []latest.Profile) {
+	var kustomizeConfig *latest.Kustomize
 	var profiles []latest.Profile
 
-	// if there's only one kustomize path, either leave it blank (if it's the default path),
-	// or generate a config with that single path and return it
+	// if there's only one kustomize path, generate a config with that single path and return it
 	if len(k.kustomizations) == 1 {
-		if k.kustomizations[0] == constants.DefaultKustomizePath {
-			kustomizeConfig = &latest.KustomizeDeploy{}
-		} else {
-			kustomizeConfig = &latest.KustomizeDeploy{
-				KustomizePaths: k.kustomizations,
-			}
+		kustomizeConfig = &latest.Kustomize{
+			Paths: k.kustomizations,
 		}
-		return latest.DeployConfig{
-			DeployType: latest.DeployType{
-				KustomizeDeploy: kustomizeConfig,
+		return latest.RenderConfig{
+			Generate: latest.Generate{
+				Kustomize: kustomizeConfig,
 			},
 		}, nil
 	}
@@ -105,17 +99,17 @@ func (k *kustomize) DeployConfig() (latest.DeployConfig, []latest.Profile) {
 
 	for _, kustomization := range k.kustomizations {
 		if kustomization == defaultKustomization {
-			kustomizeConfig = &latest.KustomizeDeploy{
-				KustomizePaths: []string{defaultKustomization},
+			kustomizeConfig = &latest.Kustomize{
+				Paths: []string{defaultKustomization},
 			}
 		} else {
 			profiles = append(profiles, latest.Profile{
 				Name: filepath.Base(kustomization),
 				Pipeline: latest.Pipeline{
-					Deploy: latest.DeployConfig{
-						DeployType: latest.DeployType{
-							KustomizeDeploy: &latest.KustomizeDeploy{
-								KustomizePaths: []string{kustomization},
+					Render: latest.RenderConfig{
+						Generate: latest.Generate{
+							Kustomize: &latest.Kustomize{
+								Paths: []string{kustomization},
 							},
 						},
 					},
@@ -124,9 +118,9 @@ func (k *kustomize) DeployConfig() (latest.DeployConfig, []latest.Profile) {
 		}
 	}
 
-	return latest.DeployConfig{
-		DeployType: latest.DeployType{
-			KustomizeDeploy: kustomizeConfig,
+	return latest.RenderConfig{
+		Generate: latest.Generate{
+			Kustomize: kustomizeConfig,
 		},
 	}, profiles
 }
@@ -146,5 +140,4 @@ func (k *kustomize) Validate() error {
 	return nil
 }
 
-// we don't generate k8s manifests for a kustomize deploy
 func (k *kustomize) AddManifestForImage(string, string) {}


Test patch:
diff --git a/pkg/skaffold/event/event_test.go b/pkg/skaffold/event/event_test.go
index f2795d190..6b7e23c52 100644
--- a/pkg/skaffold/event/event_test.go
+++ b/pkg/skaffold/event/event_test.go
@@ -237,6 +237,24 @@ func TestPortForwarded_handleNil(t *testing.T) {
 	wait(t, func() bool { return handler.getState().ForwardedPorts[8080] != nil })
 }
 
+func TestResourceCheckEvent_handleNil(t *testing.T) {
+	defer func() { handler = newHandler() }()
+
+	handler = newHandler()
+	handler.state = emptyState(mockCfg([]latest.Pipeline{{}}, "test"))
+	handler.setState(handler.getState())
+
+	if handler.getState().StatusCheckState.Resources != nil {
+		t.Error("Resources should be a nil map")
+	}
+	resourceStatusCheckEventSucceeded("pods")
+	// Resources will be reset to map[string]string{} in handleExec
+	wait(t, func() bool {
+		_, ok := handler.getState().StatusCheckState.Resources["pods"]
+		return ok
+	})
+}
+
 func TestStatusCheckEventStarted(t *testing.T) {
 	defer func() { handler = newHandler() }()
 
diff --git a/pkg/skaffold/initializer/config_test.go b/pkg/skaffold/initializer/config_test.go
index defe805dc..37fa54c10 100644
--- a/pkg/skaffold/initializer/config_test.go
+++ b/pkg/skaffold/initializer/config_test.go
@@ -29,23 +29,30 @@ import (
 )
 
 type stubDeploymentInitializer struct {
-	config   latest.DeployConfig
+	config latest.DeployConfig
+}
+
+func (s stubDeploymentInitializer) DeployConfig() latest.DeployConfig {
+	return s.config
+}
+
+type stubRendererInitializer struct {
+	config   latest.RenderConfig
 	profiles []latest.Profile
 }
 
-func (s stubDeploymentInitializer) DeployConfig() (latest.DeployConfig, []latest.Profile) {
+func (s stubRendererInitializer) RenderConfig() (latest.RenderConfig, []latest.Profile) {
 	return s.config, s.profiles
 }
-
-func (s stubDeploymentInitializer) GetImages() []string {
+func (s stubRendererInitializer) GetImages() []string {
 	panic("implement me")
 }
 
-func (s stubDeploymentInitializer) Validate() error {
+func (s stubRendererInitializer) Validate() error {
 	panic("no thanks")
 }
 
-func (s stubDeploymentInitializer) AddManifestForImage(string, string) {
+func (s stubRendererInitializer) AddManifestForImage(string, string) {
 	panic("don't call me")
 }
 
@@ -76,6 +83,7 @@ func TestGenerateSkaffoldConfig(t *testing.T) {
 		name                   string
 		expectedSkaffoldConfig *latest.SkaffoldConfig
 		deployConfig           latest.DeployConfig
+		renderConfig           latest.RenderConfig
 		profiles               []latest.Profile
 		builderConfigInfos     []build.ArtifactInfo
 		getWd                  func() (string, error)
@@ -84,6 +92,7 @@ func TestGenerateSkaffoldConfig(t *testing.T) {
 			name:               "empty",
 			builderConfigInfos: []build.ArtifactInfo{},
 			deployConfig:       latest.DeployConfig{},
+			renderConfig:       latest.RenderConfig{},
 			getWd: func() (s string, err error) {
 				return filepath.Join("rootDir", "testConfig"), nil
 			},
@@ -92,7 +101,7 @@ func TestGenerateSkaffoldConfig(t *testing.T) {
 				Kind:       "Config",
 				Metadata:   latest.Metadata{Name: "testconfig"},
 				Pipeline: latest.Pipeline{
-					Deploy: latest.DeployConfig{},
+					Render: latest.RenderConfig{},
 				},
 			},
 		},
@@ -107,6 +116,7 @@ func TestGenerateSkaffoldConfig(t *testing.T) {
 				},
 			},
 			deployConfig: latest.DeployConfig{},
+			renderConfig: latest.RenderConfig{},
 			getWd: func() (s string, err error) {
 				return string(filepath.Separator), nil
 			},
@@ -126,6 +136,7 @@ func TestGenerateSkaffoldConfig(t *testing.T) {
 							},
 						},
 					},
+					Render: latest.RenderConfig{},
 					Deploy: latest.DeployConfig{},
 				},
 			},
@@ -134,6 +145,7 @@ func TestGenerateSkaffoldConfig(t *testing.T) {
 			name:               "error working dir",
 			builderConfigInfos: []build.ArtifactInfo{},
 			deployConfig:       latest.DeployConfig{},
+			renderConfig:       latest.RenderConfig{},
 			getWd: func() (s string, err error) {
 				return "", errors.New("testError")
 			},
@@ -149,13 +161,16 @@ func TestGenerateSkaffoldConfig(t *testing.T) {
 		testutil.Run(t, test.name, func(t *testutil.T) {
 			deploymentInitializer := stubDeploymentInitializer{
 				test.deployConfig,
-				test.profiles,
 			}
 			buildInitializer := stubBuildInitializer{
 				test.builderConfigInfos,
 			}
+			rendererInitializer := stubRendererInitializer{
+				test.renderConfig,
+				test.profiles,
+			}
 			t.Override(&getWd, test.getWd)
-			config := generateSkaffoldConfig(buildInitializer, deploymentInitializer)
+			config := generateSkaffoldConfig(buildInitializer, rendererInitializer, deploymentInitializer)
 			t.CheckDeepEqual(config, test.expectedSkaffoldConfig)
 		})
 	}
diff --git a/pkg/skaffold/initializer/deploy/helm_test.go b/pkg/skaffold/initializer/deploy/helm_test.go
index 5fb671ac4..1500cb43b 100644
--- a/pkg/skaffold/initializer/deploy/helm_test.go
+++ b/pkg/skaffold/initializer/deploy/helm_test.go
@@ -17,15 +17,9 @@ limitations under the License.
 package deploy
 
 import (
-	"errors"
-	"fmt"
 	"testing"
 
-	logrustest "github.com/sirupsen/logrus/hooks/test"
-
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
 	"github.com/GoogleContainerTools/skaffold/testutil"
 )
 
@@ -79,118 +73,8 @@ func TestDeployConfig(t *testing.T) {
 				return []byte{}, nil
 			})
 			h := newHelmInitializer(test.input)
-			d, _ := h.DeployConfig()
+			d := h.DeployConfig()
 			CheckHelmInitStruct(t, test.expected, d.LegacyHelmDeploy.Releases)
 		})
 	}
 }
-
-func TestGetImages(t *testing.T) {
-	tests := []struct {
-		description string
-		values      []string
-		templates   []string
-		cmd         string
-		err         error
-		shouldMatch string
-		expected    []string
-	}{
-		{
-			description: "helm templates multiple value files",
-			templates:   []string{backendTemp},
-			values:      []string{"backend/val.yml", "backend/values.yaml"},
-			cmd:         "helm template backend -f backend/val.yml -f backend/values.yaml",
-			expected:    []string{"go-guestbook-backend"},
-		},
-		{
-			description: "no values files",
-			values:      []string{},
-			cmd:         "helm template backend",
-			templates:   []string{backendTemp},
-			expected:    []string{"go-guestbook-backend"},
-		},
-		{
-			description: "err parsing template",
-			values:      []string{"backend/values.yaml"},
-			cmd:         "helm template backend -f backend/values.yaml",
-			templates:   []string{"invalid"},
-			shouldMatch: "reading Kubernetes YAML: yaml: unmarshal errors:\n  line 1: cannot unmarshal !!str `invalid` into kubernetes.yamlObject",
-		},
-		{
-			description: "err when running helm template",
-			values:      []string{"backend/values.yaml"},
-			cmd:         "helm template backend -f backend/values.yaml",
-			err:         errors.New("invalid"),
-			shouldMatch: "encountered error: invalid",
-			expected:    []string{},
-		},
-	}
-	for _, test := range tests {
-		testutil.Run(t, test.description, func(t *testutil.T) {
-			t.Override(&readFile, func(_ string) ([]byte, error) {
-				return []byte{}, nil
-			})
-			h := newHelmInitializer(map[string][]string{"backend": test.values})
-			hook := &logrustest.Hook{}
-			log.AddHook(hook)
-			tmpDir := t.NewTempDir()
-			for i, contents := range test.templates {
-				tmpDir.Write(fmt.Sprintf("template/template_%d.yaml", i), contents)
-			}
-			cmd := fmt.Sprintf("%s --output-dir %s", test.cmd, tmpDir.Path("template"))
-			t.Override(&util.DefaultExecCommand, testutil.CmdRunErr(cmd, test.err))
-			t.Override(&tempDir, func(dir, pattern string) (name string, err error) {
-				return tmpDir.Path("template"), nil
-			})
-			images := h.GetImages()
-			t.CheckElementsMatch(test.expected, images)
-			t.CheckMatches(test.shouldMatch, lastEntryHook(hook))
-		})
-	}
-}
-
-func lastEntryHook(hook *logrustest.Hook) string {
-	for _, entry := range hook.AllEntries() {
-		return entry.Message
-	}
-	return ""
-}
-
-var backendTemp = `---
-# Source: backend/templates/service.yaml
-apiVersion: v1
-kind: Service
-metadata:
-  name: backend
-  labels:
-    app: backend
-    tier: backend
-spec:
-  type: ClusterIP
-  selector:
-    app: backend
-    tier: backend
-  ports:
-  - port: 8080
-    targetPort: http-server
----
-# Source: backend/templates/deployment.yaml
-apiVersion: apps/v1
-kind: Deployment
-metadata:
-  name: backend
-  labels:
-    app: backend
-spec:
-  selector:
-    matchLabels:
-      app: backend
-  replicas: 2
-  template:
-    metadata:
-      labels:
-        app: backend
-    spec:
-      containers:
-      - name: backend
-        image: go-guestbook-backend`
diff --git a/pkg/skaffold/initializer/helm_test.go b/pkg/skaffold/initializer/helm_test.go
index cf02fec67..c4423ada1 100644
--- a/pkg/skaffold/initializer/helm_test.go
+++ b/pkg/skaffold/initializer/helm_test.go
@@ -109,8 +109,8 @@ spec:
 			a := analyze.NewAnalyzer(config)
 			err := a.Analyze(".")
 			t.CheckError(test.shouldErr, err)
-			d := deploy.NewInitializer(a.Manifests(), a.KustomizeBases(), a.KustomizePaths(), a.HelmChartInfo(), config)
-			dc, _ := d.DeployConfig()
+			d := deploy.NewInitializer(a.HelmChartInfo(), config)
+			dc := d.DeployConfig()
 			deploy.CheckHelmInitStruct(t, test.expected, dc.LegacyHelmDeploy.Releases)
 		})
 	}
diff --git a/pkg/skaffold/initializer/render/helm_test.go b/pkg/skaffold/initializer/render/helm_test.go
new file mode 100644
index 000000000..f06734caa
--- /dev/null
+++ b/pkg/skaffold/initializer/render/helm_test.go
@@ -0,0 +1,139 @@
+/*
+Copyright 2022 The Skaffold Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package render
+
+import (
+	"errors"
+	"fmt"
+	"testing"
+
+	logrustest "github.com/sirupsen/logrus/hooks/test"
+
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
+	"github.com/GoogleContainerTools/skaffold/testutil"
+)
+
+func TestGetImages(t *testing.T) {
+	tests := []struct {
+		description string
+		values      []string
+		templates   []string
+		cmd         string
+		err         error
+		shouldMatch string
+		expected    []string
+	}{
+		{
+			description: "helm templates multiple value files",
+			templates:   []string{backendTemp},
+			values:      []string{"backend/val.yml", "backend/values.yaml"},
+			cmd:         "helm template backend -f backend/val.yml -f backend/values.yaml",
+			expected:    []string{"go-guestbook-backend"},
+		},
+		{
+			description: "no values files",
+			values:      []string{},
+			cmd:         "helm template backend",
+			templates:   []string{backendTemp},
+			expected:    []string{"go-guestbook-backend"},
+		},
+		{
+			description: "err parsing template",
+			values:      []string{"backend/values.yaml"},
+			cmd:         "helm template backend -f backend/values.yaml",
+			templates:   []string{"invalid"},
+			shouldMatch: "reading Kubernetes YAML: yaml: unmarshal errors:\n  line 1: cannot unmarshal !!str `invalid` into kubernetes.yamlObject",
+		},
+		{
+			description: "err when running helm template",
+			values:      []string{"backend/values.yaml"},
+			cmd:         "helm template backend -f backend/values.yaml",
+			err:         errors.New("invalid"),
+			shouldMatch: "encountered error: invalid",
+			expected:    []string{},
+		},
+	}
+	for _, test := range tests {
+		testutil.Run(t, test.description, func(t *testutil.T) {
+			t.Override(&readFile, func(_ string) ([]byte, error) {
+				return []byte{}, nil
+			})
+			h := newHelmInitializer(map[string][]string{"backend": test.values})
+			hook := &logrustest.Hook{}
+			log.AddHook(hook)
+			tmpDir := t.NewTempDir()
+			for i, contents := range test.templates {
+				tmpDir.Write(fmt.Sprintf("template/template_%d.yaml", i), contents)
+			}
+			cmd := fmt.Sprintf("%s --output-dir %s", test.cmd, tmpDir.Path("template"))
+			t.Override(&util.DefaultExecCommand, testutil.CmdRunErr(cmd, test.err))
+			t.Override(&tempDir, func(dir, pattern string) (name string, err error) {
+				return tmpDir.Path("template"), nil
+			})
+			images := h.GetImages()
+			t.CheckElementsMatch(test.expected, images)
+			t.CheckMatches(test.shouldMatch, lastEntryHook(hook))
+		})
+	}
+}
+
+func lastEntryHook(hook *logrustest.Hook) string {
+	for _, entry := range hook.AllEntries() {
+		return entry.Message
+	}
+	return ""
+}
+
+var backendTemp = `---
+# Source: backend/templates/service.yaml
+apiVersion: v1
+kind: Service
+metadata:
+  name: backend
+  labels:
+    app: backend
+    tier: backend
+spec:
+  type: ClusterIP
+  selector:
+    app: backend
+    tier: backend
+  ports:
+  - port: 8080
+    targetPort: http-server
+---
+# Source: backend/templates/deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: backend
+  labels:
+    app: backend
+spec:
+  selector:
+    matchLabels:
+      app: backend
+  replicas: 2
+  template:
+    metadata:
+      labels:
+        app: backend
+    spec:
+      containers:
+      - name: backend
+        image: go-guestbook-backend`
diff --git a/pkg/skaffold/initializer/deploy/kubectl_test.go b/pkg/skaffold/initializer/render/kubectl_test.go
similarity index 93%
rename from pkg/skaffold/initializer/deploy/kubectl_test.go
rename to pkg/skaffold/initializer/render/kubectl_test.go
index 311a44e1f..9c487e112 100644
--- a/pkg/skaffold/initializer/deploy/kubectl_test.go
+++ b/pkg/skaffold/initializer/render/kubectl_test.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2019 The Skaffold Authors
+Copyright 2022 The Skaffold Authors
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package deploy
+package render
 
 import (
 	"testing"
@@ -40,15 +40,13 @@ spec:
 
 	k := newKubectlInitializer([]string{filename})
 
-	expectedConfig := latest.DeployConfig{
-		DeployType: latest.DeployType{
-			KubectlDeploy: &latest.KubectlDeploy{
-				Manifests: []string{filename},
-			},
+	expectedConfig := latest.RenderConfig{
+		Generate: latest.Generate{
+			RawK8s: []string{filename},
 		},
 	}
-	deployConfig, profiles := k.DeployConfig()
-	testutil.CheckDeepEqual(t, expectedConfig, deployConfig)
+	renderConfig, profiles := k.RenderConfig()
+	testutil.CheckDeepEqual(t, expectedConfig, renderConfig)
 	if profiles != nil {
 		t.Errorf("generated profiles should be nil, but got: %+v\n", profiles)
 	}
diff --git a/pkg/skaffold/initializer/deploy/kustomize_test.go b/pkg/skaffold/initializer/render/kustomize_test.go
similarity index 79%
rename from pkg/skaffold/initializer/deploy/kustomize_test.go
rename to pkg/skaffold/initializer/render/kustomize_test.go
index 27f34f04e..a8611e17f 100644
--- a/pkg/skaffold/initializer/deploy/kustomize_test.go
+++ b/pkg/skaffold/initializer/render/kustomize_test.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package deploy
+package render
 
 import (
 	"path/filepath"
@@ -80,10 +80,10 @@ func TestGenerateKustomizePipeline(t *testing.T) {
 			overlays:          []overlay{{"dev", overlayDeployment, overlayKustomization}},
 			expectedConfig: latest.SkaffoldConfig{
 				Pipeline: latest.Pipeline{
-					Deploy: latest.DeployConfig{
-						DeployType: latest.DeployType{
-							KustomizeDeploy: &latest.KustomizeDeploy{
-								KustomizePaths: []string{filepath.Join("overlays", "dev")},
+					Render: latest.RenderConfig{
+						Generate: latest.Generate{
+							Kustomize: &latest.Kustomize{
+								Paths: []string{filepath.Join("overlays", "dev")},
 							},
 						},
 					},
@@ -101,10 +101,10 @@ func TestGenerateKustomizePipeline(t *testing.T) {
 			},
 			expectedConfig: latest.SkaffoldConfig{
 				Pipeline: latest.Pipeline{
-					Deploy: latest.DeployConfig{
-						DeployType: latest.DeployType{
-							KustomizeDeploy: &latest.KustomizeDeploy{
-								KustomizePaths: []string{filepath.Join("overlays", "foo")},
+					Render: latest.RenderConfig{
+						Generate: latest.Generate{
+							Kustomize: &latest.Kustomize{
+								Paths: []string{filepath.Join("overlays", "foo")},
 							},
 						},
 					},
@@ -113,10 +113,10 @@ func TestGenerateKustomizePipeline(t *testing.T) {
 					{
 						Name: "bar",
 						Pipeline: latest.Pipeline{
-							Deploy: latest.DeployConfig{
-								DeployType: latest.DeployType{
-									KustomizeDeploy: &latest.KustomizeDeploy{
-										KustomizePaths: []string{filepath.Join("overlays", "bar")},
+							Render: latest.RenderConfig{
+								Generate: latest.Generate{
+									Kustomize: &latest.Kustomize{
+										Paths: []string{filepath.Join("overlays", "bar")},
 									},
 								},
 							},
@@ -125,10 +125,10 @@ func TestGenerateKustomizePipeline(t *testing.T) {
 					{
 						Name: "baz",
 						Pipeline: latest.Pipeline{
-							Deploy: latest.DeployConfig{
-								DeployType: latest.DeployType{
-									KustomizeDeploy: &latest.KustomizeDeploy{
-										KustomizePaths: []string{filepath.Join("overlays", "baz")},
+							Render: latest.RenderConfig{
+								Generate: latest.Generate{
+									Kustomize: &latest.Kustomize{
+										Paths: []string{filepath.Join("overlays", "baz")},
 									},
 								},
 							},
@@ -157,8 +157,8 @@ func TestGenerateKustomizePipeline(t *testing.T) {
 
 			k := newKustomizeInitializer("", []string{test.base}, overlays, manifests)
 
-			deployConfig, profiles := k.DeployConfig()
-			testutil.CheckDeepEqual(t, test.expectedConfig.Pipeline.Deploy, deployConfig)
+			renderConfig, profiles := k.RenderConfig()
+			testutil.CheckDeepEqual(t, test.expectedConfig.Pipeline.Render, renderConfig)
 			testutil.CheckDeepEqual(t, test.expectedConfig.Profiles, profiles)
 		})
 	}
diff --git a/pkg/skaffold/initializer/testdata/init/allcli/skaffold.yaml b/pkg/skaffold/initializer/testdata/init/allcli/skaffold.yaml
index 1d485f15b..9a75d7433 100644
--- a/pkg/skaffold/initializer/testdata/init/allcli/skaffold.yaml
+++ b/pkg/skaffold/initializer/testdata/init/allcli/skaffold.yaml
@@ -7,8 +7,7 @@ build:
     - image: passed-in-artifact
       docker:
         dockerfile: Dockerfile
-deploy:
-  kubectl:
-    manifests:
-      - manifest-placeholder1.yaml
-      - manifest-placeholder2.yaml
+manifests:
+  rawYaml:
+    - manifest-placeholder1.yaml
+    - manifest-placeholder2.yaml
diff --git a/pkg/skaffold/initializer/testdata/init/getting-started-kustomize/skaffold.yaml b/pkg/skaffold/initializer/testdata/init/getting-started-kustomize/skaffold.yaml
index b20f3507f..7c8fd6c9e 100644
--- a/pkg/skaffold/initializer/testdata/init/getting-started-kustomize/skaffold.yaml
+++ b/pkg/skaffold/initializer/testdata/init/getting-started-kustomize/skaffold.yaml
@@ -7,5 +7,8 @@ build:
   - image: hello-world
     docker:
       dockerfile: Dockerfile
-deploy:
-  kustomize: {}
+manifests:
+  kustomize:
+    paths:
+      - "."
+
diff --git a/pkg/skaffold/initializer/testdata/init/hello/skaffold.yaml b/pkg/skaffold/initializer/testdata/init/hello/skaffold.yaml
index 0dd247b6a..c771e01bc 100644
--- a/pkg/skaffold/initializer/testdata/init/hello/skaffold.yaml
+++ b/pkg/skaffold/initializer/testdata/init/hello/skaffold.yaml
@@ -7,7 +7,6 @@ build:
   - image: skaffold-example
     docker:
       dockerfile: Dockerfile
-deploy:
-  kubectl:
-    manifests:
-    - k8s-pod.yaml
+manifests:
+  rawYaml:
+  - k8s-pod.yaml
diff --git a/pkg/skaffold/initializer/testdata/init/ignore-tags/skaffold.yaml b/pkg/skaffold/initializer/testdata/init/ignore-tags/skaffold.yaml
index 9b218f5ca..21f5d75a7 100644
--- a/pkg/skaffold/initializer/testdata/init/ignore-tags/skaffold.yaml
+++ b/pkg/skaffold/initializer/testdata/init/ignore-tags/skaffold.yaml
@@ -7,7 +7,6 @@ build:
   - image: gcr.io/k8s-skaffold/skaffold-example
     docker:
       dockerfile: Dockerfile
-deploy:
-  kubectl:
-    manifests:
+manifests:
+  rawYaml:
     - k8s-pod.yaml
diff --git a/pkg/skaffold/initializer/testdata/init/microservices/skaffold.yaml b/pkg/skaffold/initializer/testdata/init/microservices/skaffold.yaml
index 737ea4393..8290f5064 100644
--- a/pkg/skaffold/initializer/testdata/init/microservices/skaffold.yaml
+++ b/pkg/skaffold/initializer/testdata/init/microservices/skaffold.yaml
@@ -12,8 +12,7 @@ build:
     context: leeroy-web
     docker:
       dockerfile: Dockerfile
-deploy:
-  kubectl:
-    manifests:
+manifests:
+  rawYaml:
     - leeroy-app/kubernetes/deployment.yaml
     - leeroy-web/kubernetes/deployment.yaml
diff --git a/pkg/skaffold/initializer/testdata/init/windows/skaffold.yaml b/pkg/skaffold/initializer/testdata/init/windows/skaffold.yaml
index e35ebace4..78541ddeb 100644
--- a/pkg/skaffold/initializer/testdata/init/windows/skaffold.yaml
+++ b/pkg/skaffold/initializer/testdata/init/windows/skaffold.yaml
@@ -8,7 +8,6 @@ build:
     context: apps/web
     docker:
       dockerfile: build/Dockerfile
-deploy:
-  kubectl:
-    manifests:
+manifests:
+  rawYaml:
     - apps/web/deployment.yaml