Repository: GoogleContainerTools/skaffold
Pull request #7332 (2022-04-21 10:24:39)

fix: Update skaffold-kustomize-args.yaml
Modified Kustomize load-restrictor argument and syntax to follow changes implemented in Kustomize v4+ and make the example work in Cloud Shell.

Fixes:  [#7331](https://github.com/GoogleContainerTools/skaffold/issues/7331)

**Description**
This example is designed to work with <4 versions of Kustomize. The `load_restrictor` argument syntax has been changed by `--load-restrictor` and the value should now be `LoadRestrictionsNone` instead of `none`.

**Follow-up Work (remove if N/A)**
[Outdated Kustomize build flags in Examples #7331
](https://github.com/GoogleContainerTools/skaffold/issues/7331)


google-cla[bot]: Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

For more information, open the [CLA check for this pull request](https://github.com/GoogleContainerTools/skaffold/pull/7332/checks?check_run_id=6110337127).
briandealwis: @javiercanadillas did this actually cause problems?  The `none` value is still [explicitly supported in Kustomize](https://github.com/kubernetes-sigs/kustomize/blob/master/kustomize/commands/build/flagloadrestrictor.go#L42).

The `LoadRestrictions*`-style arguments looks to have been [made in 2019](https://github.com/kubernetes-sigs/kustomize/commit/a45eca7e22ba69a6991047c7f10c9a4b33d2e2f1) and is present in Kustomize v3.10.0.  The embedded Kustomize in the embedded kubectl 1.21 in Cloud CLI seems to be v4+, so this should be a safe change.
```
$ ./kustomize version
{Version:kustomize/v3.10.0 GitCommit:602ad8aa98e2e17f6c9119e027a09757e63c8bec BuildDate:2021-02-10T00:00:50Z GoOs:darwin GoArch:amd64}
$ ./kustomize build --help | grep load_restrictor
      --load_restrictor string   if set to 'LoadRestrictionsNone', local kustomizations may load files from outside their root. This does, however, break the relocatability of the kustomization. (default "LoadRestrictionsRootOnly")
```

Patch:
diff --git a/cmd/skaffold/app/cmd/flags.go b/cmd/skaffold/app/cmd/flags.go
index f323a39b7..2a96d3847 100644
--- a/cmd/skaffold/app/cmd/flags.go
+++ b/cmd/skaffold/app/cmd/flags.go
@@ -589,9 +589,9 @@ var flagRegistry = []Flag{
 	},
 	{
 		Name:          "digest-source",
-		Usage:         "Set to 'remote' to skip builds and resolve the digest of images by tag from the remote registry. Set to 'local' to build images locally and use digests from built images. Set to 'tag' to use tags directly from the build. Set to 'none' to use tags directly from the Kubernetes manifests.",
+		Usage:         "Set to 'remote' to skip builds and resolve the digest of images by tag from the remote registry. Set to 'local' to build images locally and use digests from built images. Set to 'tag' to use tags directly from the build. Set to 'none' to use tags directly from the Kubernetes manifests. If unspecified, defaults to 'remote' for remote clusters, and 'tag' for local clusters like kind or minikube.",
 		Value:         &opts.DigestSource,
-		DefValue:      "remote",
+		DefValue:      "",
 		FlagAddMethod: "StringVar",
 		DefinedOn:     []string{"dev", "render", "run"},
 		DeprecatedPerCommand: map[string]interface{}{
diff --git a/docs/content/en/docs/environment/templating.md b/docs/content/en/docs/environment/templating.md
index 24a26be01..5aebb5433 100644
--- a/docs/content/en/docs/environment/templating.md
+++ b/docs/content/en/docs/environment/templating.md
@@ -21,6 +21,7 @@ List of fields that support templating:
 * `deploy.helm.releases.setValueTemplates` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
 * `deploy.helm.releases.name` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
 * `deploy.helm.releases.namespace` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
+* `deploy.helm.releases[].repo` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
 * `deploy.helm.releases.version` (see [Deploying with helm]({{< relref "/docs/pipeline-stages/deployers#deploying-with-helm)" >}}))
 * `deploy.kubectl.defaultNamespace`
 * `deploy.kustomize.defaultNamespace`
diff --git a/docs/content/en/docs/references/cli/_index.md b/docs/content/en/docs/references/cli/_index.md
index 5f3975da6..ebbefe786 100644
--- a/docs/content/en/docs/references/cli/_index.md
+++ b/docs/content/en/docs/references/cli/_index.md
@@ -681,7 +681,7 @@ Options:
   -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config)
   -d, --default-repo='': Default repository value (overrides global config)
       --detect-minikube=true: Use heuristics to detect a minikube cluster
-      --digest-source='remote': Set to 'remote' to skip builds and resolve the digest of images by tag from the remote registry. Set to 'local' to build images locally and use digests from built images. Set to 'tag' to use tags directly from the build. Set to 'none' to use tags directly from the Kubernetes manifests.
+      --digest-source='': Set to 'remote' to skip builds and resolve the digest of images by tag from the remote registry. Set to 'local' to build images locally and use digests from built images. Set to 'tag' to use tags directly from the build. Set to 'none' to use tags directly from the Kubernetes manifests. If unspecified, defaults to 'remote' for remote clusters, and 'tag' for local clusters like kind or minikube.
   -f, --filename='skaffold.yaml': Path or URL to the Skaffold config file
       --force=false: Recreate Kubernetes resources if necessary for deployment, warning: might cause downtime!
       --hydration-dir='.kpt-pipeline': The directory to where the (kpt) hydration takes place. Default to a hidden directory .kpt-pipeline.
@@ -948,7 +948,7 @@ Options:
   -a, --build-artifacts=: File containing build result from a previous 'skaffold build --file-output'
       --cache-artifacts=true: Set to false to disable default caching of artifacts
   -d, --default-repo='': Default repository value (overrides global config)
-      --digest-source='remote': Set to 'remote' to skip builds and resolve the digest of images by tag from the remote registry. Set to 'local' to build images locally and use digests from built images. Set to 'tag' to use tags directly from the build. Set to 'none' to use tags directly from the Kubernetes manifests.
+      --digest-source='': Set to 'remote' to skip builds and resolve the digest of images by tag from the remote registry. Set to 'local' to build images locally and use digests from built images. Set to 'tag' to use tags directly from the build. Set to 'none' to use tags directly from the Kubernetes manifests. If unspecified, defaults to 'remote' for remote clusters, and 'tag' for local clusters like kind or minikube.
   -f, --filename='skaffold.yaml': Path or URL to the Skaffold config file
       --hydration-dir='.kpt-pipeline': The directory to where the (kpt) hydration takes place. Default to a hidden directory .kpt-pipeline.
   -i, --images=: A list of pre-built images to deploy, either tagged images or NAME=TAG pairs
@@ -1022,7 +1022,7 @@ Options:
   -c, --config='': File for global configurations (defaults to $HOME/.skaffold/config)
   -d, --default-repo='': Default repository value (overrides global config)
       --detect-minikube=true: Use heuristics to detect a minikube cluster
-      --digest-source='remote': Set to 'remote' to skip builds and resolve the digest of images by tag from the remote registry. Set to 'local' to build images locally and use digests from built images. Set to 'tag' to use tags directly from the build. Set to 'none' to use tags directly from the Kubernetes manifests.
+      --digest-source='': Set to 'remote' to skip builds and resolve the digest of images by tag from the remote registry. Set to 'local' to build images locally and use digests from built images. Set to 'tag' to use tags directly from the build. Set to 'none' to use tags directly from the Kubernetes manifests. If unspecified, defaults to 'remote' for remote clusters, and 'tag' for local clusters like kind or minikube.
   -f, --filename='skaffold.yaml': Path or URL to the Skaffold config file
       --force=false: Recreate Kubernetes resources if necessary for deployment, warning: might cause downtime!
       --hydration-dir='.kpt-pipeline': The directory to where the (kpt) hydration takes place. Default to a hidden directory .kpt-pipeline.
diff --git a/examples/kustomize/skaffold-kustomize-args.yaml b/examples/kustomize/skaffold-kustomize-args.yaml
index da3ce5b12..9d781518b 100644
--- a/examples/kustomize/skaffold-kustomize-args.yaml
+++ b/examples/kustomize/skaffold-kustomize-args.yaml
@@ -3,4 +3,4 @@ kind: Config
 deploy:
   kustomize:
     buildArgs:
-      - "--load_restrictor none"
+      - "--load-restrictor LoadRestrictionsNone"
diff --git a/integration/examples/kustomize/skaffold-kustomize-args.yaml b/integration/examples/kustomize/skaffold-kustomize-args.yaml
index b079032df..27618da17 100644
--- a/integration/examples/kustomize/skaffold-kustomize-args.yaml
+++ b/integration/examples/kustomize/skaffold-kustomize-args.yaml
@@ -3,4 +3,4 @@ kind: Config
 deploy:
   kustomize:
     buildArgs:
-      - "--load_restrictor none"
+      - "--load-restrictor LoadRestrictionsNone"
diff --git a/pkg/skaffold/build/bazel/dependencies.go b/pkg/skaffold/build/bazel/dependencies.go
index c2459bd2a..d2fcfd61f 100644
--- a/pkg/skaffold/build/bazel/dependencies.go
+++ b/pkg/skaffold/build/bazel/dependencies.go
@@ -51,7 +51,7 @@ func GetDependencies(ctx context.Context, dir string, a *latest.BazelArtifact) (
 		once.Do(func() { log.Entry(ctx).Warn("Retrieving Bazel dependencies can take a long time the first time") })
 	}()
 
-	topLevelFolder, err := findWorkspace(dir)
+	workspaceDir, workspaceFile, err := findWorkspace(dir)
 	if err != nil {
 		return nil, fmt.Errorf("unable to find the WORKSPACE file: %w", err)
 	}
@@ -81,14 +81,14 @@ func GetDependencies(ctx context.Context, dir string, a *latest.BazelArtifact) (
 			continue
 		}
 
-		rel, err := filepath.Rel(absDir, filepath.Join(topLevelFolder, depToPath(l)))
+		rel, err := filepath.Rel(absDir, filepath.Join(workspaceDir, depToPath(l)))
 		if err != nil {
 			return nil, fmt.Errorf("unable to find absolute path: %w", err)
 		}
 		deps = append(deps, rel)
 	}
 
-	rel, err := filepath.Rel(absDir, filepath.Join(topLevelFolder, "WORKSPACE"))
+	rel, err := filepath.Rel(absDir, filepath.Join(workspaceDir, workspaceFile))
 	if err != nil {
 		return nil, fmt.Errorf("unable to find absolute path: %w", err)
 	}
@@ -103,20 +103,24 @@ func depToPath(dep string) string {
 	return strings.TrimPrefix(strings.Replace(strings.TrimPrefix(dep, "//"), ":", "/", 1), "/")
 }
 
-func findWorkspace(workingDir string) (string, error) {
+func findWorkspace(workingDir string) (string, string, error) {
 	dir, err := filepath.Abs(workingDir)
 	if err != nil {
-		return "", fmt.Errorf("invalid working dir: %w", err)
+		return "", "", fmt.Errorf("invalid working dir: %w", err)
 	}
 
 	for {
+		if _, err := os.Stat(filepath.Join(dir, "WORKSPACE.bazel")); err == nil {
+			return dir, "WORKSPACE.bazel", nil
+		}
+
 		if _, err := os.Stat(filepath.Join(dir, "WORKSPACE")); err == nil {
-			return dir, nil
+			return dir, "WORKSPACE", nil
 		}
 
 		parent := filepath.Dir(dir)
 		if parent == dir {
-			return "", errors.New("no WORKSPACE file found")
+			return "", "", errors.New("no WORKSPACE file found")
 		}
 		dir = parent
 	}
diff --git a/pkg/skaffold/build/buildpacks/lifecycle.go b/pkg/skaffold/build/buildpacks/lifecycle.go
index 9e3fe44de..b77c6b4e2 100644
--- a/pkg/skaffold/build/buildpacks/lifecycle.go
+++ b/pkg/skaffold/build/buildpacks/lifecycle.go
@@ -230,20 +230,19 @@ func resolveDependencyImages(artifact *latest.BuildpackArtifact, r ArtifactResol
 
 func containerConfig(artifact *latest.BuildpackArtifact) (pack.ContainerConfig, error) {
 	var vols []string
-	if artifact.Volumes != nil {
-		for _, v := range *artifact.Volumes {
-			if v.Host == "" || v.Target == "" {
-				// in case these slip by the JSON schema
-				return pack.ContainerConfig{}, errors.New("buildpacks volumes must have both host and target")
-			}
-			var spec string
-			if v.Options == "" {
-				spec = fmt.Sprintf("%s:%s", v.Host, v.Target)
-			} else {
-				spec = fmt.Sprintf("%s:%s:%s", v.Host, v.Target, v.Options)
-			}
-			vols = append(vols, spec)
+	for _, v := range artifact.Volumes {
+		if v.Host == "" || v.Target == "" {
+			// in case these slip by the JSON schema
+			return pack.ContainerConfig{}, errors.New("buildpacks volumes must have both host and target")
 		}
+		var spec string
+		if v.Options == "" {
+			spec = fmt.Sprintf("%s:%s", v.Host, v.Target)
+		} else {
+			spec = fmt.Sprintf("%s:%s:%s", v.Host, v.Target, v.Options)
+		}
+		vols = append(vols, spec)
 	}
+
 	return pack.ContainerConfig{Volumes: vols}, nil
 }
diff --git a/pkg/skaffold/constants/constants.go b/pkg/skaffold/constants/constants.go
index 55af92bbf..f08d883e9 100644
--- a/pkg/skaffold/constants/constants.go
+++ b/pkg/skaffold/constants/constants.go
@@ -147,3 +147,12 @@ var Labels = struct {
 	Builder:          "skaffold.dev/builder",
 	DockerAPIVersion: "skaffold.dev/docker-api-version",
 }
+
+const (
+	// RemoteDigestSource skips builds and resolves the digest of images by tag from the remote registry.
+	RemoteDigestSource = "remote"
+	// TagDigestSource to  uses tags directly from the build.
+	TagDigestSource = "tag"
+	// NoneDigestSourceSet uses tags directly from the Kubernetes manifests.
+	NoneDigestSource = "none"
+)
diff --git a/pkg/skaffold/deploy/helm/helm.go b/pkg/skaffold/deploy/helm/helm.go
index edd1ab172..4c7c8fb39 100644
--- a/pkg/skaffold/deploy/helm/helm.go
+++ b/pkg/skaffold/deploy/helm/helm.go
@@ -245,7 +245,12 @@ func (h *Deployer) Deploy(ctx context.Context, out io.Writer, builds []graph.Art
 		if err != nil {
 			return userErr(fmt.Sprintf("cannot expand chart version %q", r.Version), err)
 		}
-		m, results, err := h.deployRelease(ctx, out, releaseName, r, builds, h.bV, chartVersion)
+
+		repo, err := util.ExpandEnvTemplateOrFail(r.Repo, nil)
+		if err != nil {
+			return userErr(fmt.Sprintf("cannot expand repo %q", r.Repo), err)
+		}
+		m, results, err := h.deployRelease(ctx, out, releaseName, r, builds, h.bV, chartVersion, repo)
 		if err != nil {
 			return userErr(fmt.Sprintf("deploying %q", releaseName), err)
 		}
@@ -461,7 +466,7 @@ func (h *Deployer) PostDeployHooks(ctx context.Context, out io.Writer) error {
 }
 
 // deployRelease deploys a single release; returns the deployed manifests, and the artifacts
-func (h *Deployer) deployRelease(ctx context.Context, out io.Writer, releaseName string, r latest.HelmRelease, builds []graph.Artifact, helmVersion semver.Version, chartVersion string) ([]byte, []types.Artifact, error) {
+func (h *Deployer) deployRelease(ctx context.Context, out io.Writer, releaseName string, r latest.HelmRelease, builds []graph.Artifact, helmVersion semver.Version, chartVersion string, repo string) ([]byte, []types.Artifact, error) {
 	var err error
 	opts := installOpts{
 		releaseName: releaseName,
@@ -470,7 +475,7 @@ func (h *Deployer) deployRelease(ctx context.Context, out io.Writer, releaseName
 		force:       h.forceDeploy,
 		chartPath:   chartSource(r),
 		helmVersion: helmVersion,
-		repo:        r.Repo,
+		repo:        repo,
 		version:     chartVersion,
 	}
 
diff --git a/pkg/skaffold/hooks/deploy.go b/pkg/skaffold/hooks/deploy.go
index 0a8760e3f..0aabbafed 100644
--- a/pkg/skaffold/hooks/deploy.go
+++ b/pkg/skaffold/hooks/deploy.go
@@ -50,11 +50,11 @@ func NewDeployEnvOpts(runID string, kubeContext string, namespaces []string) Dep
 
 type deployRunner struct {
 	latest.DeployHooks
-	cli         *kubectl.CLI
-	namespaces  *[]string
-	formatter   logger.Formatter
-	opts        DeployEnvOpts
-	visitedPods *sync.Map // maintain a list of previous iteration pods, so that they can be skipped
+	cli               *kubectl.CLI
+	namespaces        *[]string
+	formatter         logger.Formatter
+	opts              DeployEnvOpts
+	visitedContainers *sync.Map // maintain a list of previous iteration containers, so that they can be skipped
 }
 
 func (r deployRunner) RunPreHooks(ctx context.Context, out io.Writer) error {
@@ -86,7 +86,7 @@ func (r deployRunner) run(ctx context.Context, out io.Writer, hooks []latest.Dep
 			hook := containerHook{
 				cfg:        latest.ContainerHook{Command: h.ContainerHook.Command},
 				cli:        r.cli,
-				selector:   filterPodsSelector(r.visitedPods, phase, namePatternSelector(h.ContainerHook.PodName, h.ContainerHook.ContainerName)),
+				selector:   filterContainersSelector(r.visitedContainers, phase, namePatternSelector(h.ContainerHook.PodName, h.ContainerHook.ContainerName)),
 				namespaces: *r.namespaces,
 				formatter:  r.formatter,
 			}
@@ -101,11 +101,11 @@ func (r deployRunner) run(ctx context.Context, out io.Writer, hooks []latest.Dep
 	return nil
 }
 
-// filterPodsSelector filters the pods that have already been processed from a previous deploy iteration
-func filterPodsSelector(visitedPods *sync.Map, phase phase, selector containerSelector) containerSelector {
+// filterContainersSelector filters the containers that have already been processed from a previous deploy iteration
+func filterContainersSelector(visitedContainers *sync.Map, phase phase, selector containerSelector) containerSelector {
 	return func(p corev1.Pod, c corev1.Container) (bool, error) {
-		key := fmt.Sprintf("%s:%s", phase, p.GetName())
-		if _, found := visitedPods.LoadOrStore(key, struct{}{}); found {
+		key := fmt.Sprintf("%s:%s:%s", phase, p.GetName(), c.Name)
+		if _, found := visitedContainers.LoadOrStore(key, struct{}{}); found {
 			return false, nil
 		}
 		return selector(p, c)
diff --git a/pkg/skaffold/runner/build.go b/pkg/skaffold/runner/build.go
index 809bd97c6..054df2839 100644
--- a/pkg/skaffold/runner/build.go
+++ b/pkg/skaffold/runner/build.go
@@ -73,7 +73,7 @@ func (r *Builder) Build(ctx context.Context, out io.Writer, artifacts []*latest.
 	out, ctx = output.WithEventContext(ctx, out, constants.Build, constants.SubtaskIDNone)
 
 	// Use tags directly from the Kubernetes manifests.
-	if r.runCtx.DigestSource() == NoneDigestSource {
+	if r.runCtx.DigestSource() == constants.NoneDigestSource {
 		return []graph.Artifact{}, nil
 	}
 
@@ -93,10 +93,10 @@ func (r *Builder) Build(ctx context.Context, out io.Writer, artifacts []*latest.
 	case r.runCtx.DryRun():
 		output.Yellow.Fprintln(out, "Skipping build phase since --dry-run=true")
 		return artifactsWithTags(tags, artifacts), nil
-	case r.runCtx.RenderOnly() && r.runCtx.DigestSource() == RemoteDigestSource:
+	case r.runCtx.RenderOnly() && r.runCtx.DigestSource() == constants.RemoteDigestSource:
 		output.Yellow.Fprintln(out, "Skipping build phase since --digest-source=remote")
 		return artifactsWithTags(tags, artifacts), nil
-	case r.runCtx.RenderOnly() && r.runCtx.DigestSource() == TagDigestSource:
+	case r.runCtx.RenderOnly() && r.runCtx.DigestSource() == constants.TagDigestSource:
 		output.Yellow.Fprintln(out, "Skipping build phase since --digest-source=tag")
 		return artifactsWithTags(tags, artifacts), nil
 	default:
diff --git a/pkg/skaffold/runner/runcontext/v2/context.go b/pkg/skaffold/runner/runcontext/v2/context.go
index c0c23fe50..672f9a589 100644
--- a/pkg/skaffold/runner/runcontext/v2/context.go
+++ b/pkg/skaffold/runner/runcontext/v2/context.go
@@ -24,6 +24,7 @@ import (
 	"github.com/google/uuid"
 
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
 	kubectx "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/context"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output/log"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
@@ -222,7 +223,6 @@ func (rc *RunContext) CustomTag() string                             { return rc
 func (rc *RunContext) DefaultRepo() *string                          { return rc.Cluster.DefaultRepo.Value() }
 func (rc *RunContext) MultiLevelRepo() *bool                         { return rc.Opts.MultiLevelRepo }
 func (rc *RunContext) Mode() config.RunMode                          { return rc.Opts.Mode() }
-func (rc *RunContext) DigestSource() string                          { return rc.Opts.DigestSource }
 func (rc *RunContext) DryRun() bool                                  { return rc.Opts.DryRun }
 func (rc *RunContext) ForceDeploy() bool                             { return rc.Opts.Force }
 func (rc *RunContext) GetKubeConfig() string                         { return rc.Opts.KubeConfig }
@@ -269,6 +269,16 @@ func (rc *RunContext) GetRenderConfig() *latest.RenderConfig {
 	return &latest.RenderConfig{}
 }
 
+func (rc *RunContext) DigestSource() string {
+	if rc.Opts.DigestSource != "" {
+		return rc.Opts.DigestSource
+	}
+	if rc.Cluster.Local {
+		return constants.TagDigestSource
+	}
+	return constants.RemoteDigestSource
+}
+
 func GetRunContext(ctx context.Context, opts config.SkaffoldOptions, configs []schemaUtil.VersionedConfig) (*RunContext, error) {
 	var pipelines []latest.Pipeline
 	for _, cfg := range configs {
diff --git a/pkg/skaffold/runner/runner.go b/pkg/skaffold/runner/runner.go
index a402e15e2..e1e7b673d 100644
--- a/pkg/skaffold/runner/runner.go
+++ b/pkg/skaffold/runner/runner.go
@@ -26,12 +26,6 @@ import (
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/util"
 )
 
-const (
-	RemoteDigestSource = "remote"
-	NoneDigestSource   = "none"
-	TagDigestSource    = "tag"
-)
-
 // ErrorConfigurationChanged is a special error that's returned when the skaffold configuration was changed.
 var ErrorConfigurationChanged = errors.New("configuration changed")
 
diff --git a/pkg/skaffold/runner/v2/render.go b/pkg/skaffold/runner/v2/render.go
index 3a07263d5..cb7bfda6b 100644
--- a/pkg/skaffold/runner/v2/render.go
+++ b/pkg/skaffold/runner/v2/render.go
@@ -21,17 +21,17 @@ import (
 	"io"
 
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/graph"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/instrumentation"
 	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
-	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner"
 )
 
 func (r *SkaffoldRunner) Render(ctx context.Context, out io.Writer, builds []graph.Artifact, offline bool, renderOutputFile string) error {
 	if r.runCtx.RenderOnly() {
 		// Fetch the digest and append it to the tag with the format of "tag@digest"
-		if r.runCtx.DigestSource() == runner.RemoteDigestSource {
+		if r.runCtx.DigestSource() == constants.RemoteDigestSource {
 			for i, a := range builds {
 				digest, err := docker.RemoteDigest(a.Tag, r.runCtx)
 				if err != nil {
@@ -40,7 +40,7 @@ func (r *SkaffoldRunner) Render(ctx context.Context, out io.Writer, builds []gra
 				builds[i].Tag = build.TagWithDigest(a.Tag, digest)
 			}
 		}
-		if r.runCtx.DigestSource() == runner.NoneDigestSource {
+		if r.runCtx.DigestSource() == constants.NoneDigestSource {
 			output.Default.Fprintln(out, "--digest-source set to 'none', tags listed in Kubernetes manifests will be used for render")
 		}
 	}


Test patch:
diff --git a/pkg/skaffold/build/bazel/dependencies_test.go b/pkg/skaffold/build/bazel/dependencies_test.go
index 74b7594bb..2cc0b9105 100644
--- a/pkg/skaffold/build/bazel/dependencies_test.go
+++ b/pkg/skaffold/build/bazel/dependencies_test.go
@@ -51,6 +51,20 @@ func TestGetDependencies(t *testing.T) {
 			output:        "@ignored\n//:BUILD\n//external/ignored\n\n//:dep1\n//:dep2\n",
 			expected:      []string{"BUILD", "dep1", "dep2", "WORKSPACE"},
 		},
+		{
+			description: "with WORKSPACE.bazel",
+			workspace:   ".",
+			target:      "target",
+			files: map[string]string{
+				"WORKSPACE.bazel": "",
+				"BUILD":           "",
+				"dep1":            "",
+				"dep2":            "",
+			},
+			expectedQuery: "bazel query kind('source file', deps('target')) union buildfiles(deps('target')) --noimplicit_deps --order_output=no --output=label",
+			output:        "@ignored\n//:BUILD\n//external/ignored\n\n//:dep1\n//:dep2\n",
+			expected:      []string{"BUILD", "dep1", "dep2", "WORKSPACE.bazel"},
+		},
 		{
 			description: "with parent WORKSPACE",
 			workspace:   "./sub/folder",
diff --git a/pkg/skaffold/build/buildpacks/lifecycle_test.go b/pkg/skaffold/build/buildpacks/lifecycle_test.go
index cb6b273f7..94f2e1254 100644
--- a/pkg/skaffold/build/buildpacks/lifecycle_test.go
+++ b/pkg/skaffold/build/buildpacks/lifecycle_test.go
@@ -58,23 +58,23 @@ func TestLifecycleStatusCode(t *testing.T) {
 func TestContainerConfig(t *testing.T) {
 	tests := []struct {
 		description string
-		volumes     []latest.BuildpackVolume
+		volumes     []*latest.BuildpackVolume
 		shouldErr   bool
 		expected    pack.ContainerConfig
 	}{
 		{
 			description: "single volume with no options",
-			volumes:     []latest.BuildpackVolume{{Host: "/foo", Target: "/bar"}},
+			volumes:     []*latest.BuildpackVolume{{Host: "/foo", Target: "/bar"}},
 			expected:    pack.ContainerConfig{Volumes: []string{"/foo:/bar"}},
 		},
 		{
 			description: "single volume with  options",
-			volumes:     []latest.BuildpackVolume{{Host: "/foo", Target: "/bar", Options: "rw"}},
+			volumes:     []*latest.BuildpackVolume{{Host: "/foo", Target: "/bar", Options: "rw"}},
 			expected:    pack.ContainerConfig{Volumes: []string{"/foo:/bar:rw"}},
 		},
 		{
 			description: "multiple volumes",
-			volumes: []latest.BuildpackVolume{
+			volumes: []*latest.BuildpackVolume{
 				{Host: "/foo", Target: "/bar", Options: "rw"},
 				{Host: "/bat", Target: "/baz", Options: "ro"},
 			},
@@ -82,12 +82,12 @@ func TestContainerConfig(t *testing.T) {
 		},
 		{
 			description: "missing host is skipped",
-			volumes:     []latest.BuildpackVolume{{Host: "", Target: "/bar"}},
+			volumes:     []*latest.BuildpackVolume{{Host: "", Target: "/bar"}},
 			shouldErr:   true,
 		},
 		{
 			description: "missing target is skipped",
-			volumes:     []latest.BuildpackVolume{{Host: "/foo", Target: ""}},
+			volumes:     []*latest.BuildpackVolume{{Host: "/foo", Target: ""}},
 			shouldErr:   true,
 		},
 	}
@@ -95,7 +95,7 @@ func TestContainerConfig(t *testing.T) {
 	for _, test := range tests {
 		testutil.Run(t, test.description, func(t *testutil.T) {
 			artifact := latest.BuildpackArtifact{
-				Volumes: &test.volumes,
+				Volumes: test.volumes,
 			}
 			result, err := containerConfig(&artifact)
 			t.CheckErrorAndDeepEqual(test.shouldErr, err, test.expected, result)
diff --git a/pkg/skaffold/deploy/helm/helm_test.go b/pkg/skaffold/deploy/helm/helm_test.go
index e2c8d7175..6c576a148 100644
--- a/pkg/skaffold/deploy/helm/helm_test.go
+++ b/pkg/skaffold/deploy/helm/helm_test.go
@@ -132,6 +132,13 @@ var testDeployConfigVersionTemplated = latest.LegacyHelmDeploy{
 		Version:   "{{.VERSION}}",
 	}},
 }
+var testDeployConfigRepoTemplated = latest.LegacyHelmDeploy{
+	Releases: []latest.HelmRelease{{
+		Name:      "skaffold-helm",
+		ChartPath: "examples/test",
+		Repo:      "https://{{.CHARTUSER}}:{{.CHARTPASS}}@charts.helm.sh/stable",
+	}},
+}
 
 var testDeployConfigSetFiles = latest.LegacyHelmDeploy{
 	Releases: []latest.HelmRelease{{
@@ -835,6 +842,20 @@ func TestHelmDeploy(t *testing.T) {
 			builds:             testBuilds,
 			expectedNamespaces: []string{""},
 		},
+		{
+			description: "deploy with templated repo",
+			commands: testutil.
+				CmdRunWithOutput("helm version --client", version31).
+				AndRun("helm --kube-context kubecontext get all skaffold-helm --kubeconfig kubeconfig").
+				AndRun("helm --kube-context kubecontext dep build examples/test --kubeconfig kubeconfig").
+				AndRunEnv("helm --kube-context kubecontext upgrade skaffold-helm examples/test --post-renderer SKAFFOLD-BINARY --repo https://foo:bar@charts.helm.sh/stable --kubeconfig kubeconfig",
+					[]string{"SKAFFOLD_FILENAME=test.yaml", "SKAFFOLD_CMDLINE=filter --kube-context kubecontext --build-artifacts TMPFILE --kubeconfig kubeconfig"}).
+				AndRunWithOutput("helm --kube-context kubecontext get all skaffold-helm --template {{.Release.Manifest}} --kubeconfig kubeconfig", validDeployYaml),
+			env:                []string{"CHARTUSER=foo", "CHARTPASS=bar"},
+			helm:               testDeployConfigRepoTemplated,
+			builds:             testBuilds,
+			expectedNamespaces: []string{""},
+		},
 		{
 			description: "deploy with setFiles",
 			commands: testutil.
diff --git a/pkg/skaffold/schema/latest/config.go b/pkg/skaffold/schema/latest/config.go
index 6b189fbf3..ae174854c 100644
--- a/pkg/skaffold/schema/latest/config.go
+++ b/pkg/skaffold/schema/latest/config.go
@@ -1057,7 +1057,7 @@ type BuildpackArtifact struct {
 	Dependencies *BuildpackDependencies `yaml:"dependencies,omitempty"`
 
 	// Volumes support mounting host volumes into the container.
-	Volumes *[]BuildpackVolume `yaml:"volumes,omitempty"`
+	Volumes []*BuildpackVolume `yaml:"volumes,omitempty"`
 }
 
 // BuildpackDependencies *alpha* is used to specify dependencies for an artifact built by buildpacks.