From 08fc12a8c3cb278e90ca0a44460faf91ca9affb7 Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Mon, 23 Sep 2019 11:29:24 -0600 Subject: [PATCH 1/3] Adds post-render support Signed-off-by: Taylor Thomas --- cmd/helm/flags.go | 32 ++++++++++++ cmd/helm/install.go | 1 + cmd/helm/upgrade.go | 2 + pkg/action/install.go | 17 ++++++- pkg/action/upgrade.go | 4 +- pkg/postrender/exec.go | 99 ++++++++++++++++++++++++++++++++++++ pkg/postrender/postrender.go | 29 +++++++++++ 7 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 pkg/postrender/exec.go create mode 100644 pkg/postrender/postrender.go diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index 65575a5c1..dfaef04a1 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -27,9 +27,11 @@ import ( "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/cli/output" "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/postrender" ) const outputFlag = "output" +const postRenderFlag = "post-renderer" func addValueOptionsFlags(f *pflag.FlagSet, v *values.Options) { f.StringSliceVarP(&v.ValueFiles, "values", "f", []string{}, "specify values in a YAML file or a URL (can specify multiple)") @@ -94,3 +96,33 @@ func (o *outputValue) Set(s string) error { *o = outputValue(outfmt) return nil } + +func bindPostRenderFlag(cmd *cobra.Command, varRef *postrender.PostRenderer) { + cmd.Flags().Var(&postRenderer{varRef}, postRenderFlag, "the path to an executable to be used for post rendering. If a non-absolute path is provided, the plugin directory and $PATH will be searched") + // Setup shell completion for the flag + cmd.MarkFlagCustom(outputFlag, "__helm_output_options") +} + +type postRenderer struct { + renderer *postrender.PostRenderer +} + +func (p postRenderer) String() string { + return "exec" +} + +func (p postRenderer) Type() string { + return "postrenderer" +} + +func (p postRenderer) Set(s string) error { + if s == "" { + return nil + } + pr, err := postrender.NewExec(s) + if err != nil { + return err + } + *p.renderer = pr + return nil +} diff --git a/cmd/helm/install.go b/cmd/helm/install.go index dbdfb3418..ec2c75a12 100644 --- a/cmd/helm/install.go +++ b/cmd/helm/install.go @@ -130,6 +130,7 @@ func newInstallCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { addInstallFlags(cmd.Flags(), client, valueOpts) bindOutputFlag(cmd, &outfmt) + bindPostRenderFlag(cmd, &client.PostRenderer) return cmd } diff --git a/cmd/helm/upgrade.go b/cmd/helm/upgrade.go index 6c967b796..54badb32c 100644 --- a/cmd/helm/upgrade.go +++ b/cmd/helm/upgrade.go @@ -108,6 +108,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { instClient.Devel = client.Devel instClient.Namespace = client.Namespace instClient.Atomic = client.Atomic + instClient.PostRenderer = client.PostRenderer rel, err := runInstall(args, instClient, valueOpts, out) if err != nil { @@ -176,6 +177,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { addChartPathOptionsFlags(f, &client.ChartPathOptions) addValueOptionsFlags(f, valueOpts) bindOutputFlag(cmd, &outfmt) + bindPostRenderFlag(cmd, &client.PostRenderer) return cmd } diff --git a/pkg/action/install.go b/pkg/action/install.go index 55a44aaed..49c9b5728 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -39,6 +39,7 @@ import ( "helm.sh/helm/v3/pkg/engine" "helm.sh/helm/v3/pkg/getter" kubefake "helm.sh/helm/v3/pkg/kube/fake" + "helm.sh/helm/v3/pkg/postrender" "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/releaseutil" "helm.sh/helm/v3/pkg/repo" @@ -94,6 +95,7 @@ type Install struct { // Used by helm template to add the release as part of OutputDir path // OutputDir/ UseReleaseName bool + PostRenderer postrender.PostRenderer } // ChartPathOptions captures common options used for controlling chart paths @@ -225,7 +227,7 @@ func (i *Install) Run(chrt *chart.Chart, vals map[string]interface{}) (*release. rel := i.createRelease(chrt, vals) var manifestDoc *bytes.Buffer - rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs) + rel.Hooks, manifestDoc, rel.Info.Notes, err = i.cfg.renderResources(chrt, valuesToRender, i.ReleaseName, i.OutputDir, i.SubNotes, i.UseReleaseName, i.IncludeCRDs, i.PostRenderer) // Even for errors, attach this if available if manifestDoc != nil { rel.Manifest = manifestDoc.String() @@ -429,7 +431,7 @@ func (i *Install) replaceRelease(rel *release.Release) error { } // renderResources renders the templates in a chart -func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName string, outputDir string, subNotes, useReleaseName bool, includeCrds bool) ([]*release.Hook, *bytes.Buffer, string, error) { +func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values, releaseName, outputDir string, subNotes, useReleaseName, includeCrds bool, pr postrender.PostRenderer) ([]*release.Hook, *bytes.Buffer, string, error) { hs := []*release.Hook{} b := bytes.NewBuffer(nil) @@ -525,6 +527,10 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values if useReleaseName { newDir = filepath.Join(outputDir, releaseName) } + // NOTE: We do not have to worry about the post-renderer because + // output dir is only used by `helm template`. In the next major + // release, we should move this logic to template only as it is not + // used by install or upgrade err = writeToFile(newDir, m.Name, m.Content, fileWritten[m.Name]) if err != nil { return hs, b, "", err @@ -533,6 +539,13 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values } } + if pr != nil { + b, err = pr.Run(b) + if err != nil { + return hs, b, notes, errors.Wrap(err, "error while running post render on files") + } + } + return hs, b, notes, nil } diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 3e8a04a56..825920793 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -29,6 +29,7 @@ import ( "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" "helm.sh/helm/v3/pkg/kube" + "helm.sh/helm/v3/pkg/postrender" "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/releaseutil" ) @@ -59,6 +60,7 @@ type Upgrade struct { CleanupOnFail bool SubNotes bool Description string + PostRenderer postrender.PostRenderer } // NewUpgrade creates a new Upgrade object with the given configuration. @@ -161,7 +163,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chart.Chart, vals map[strin return nil, nil, err } - hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false) + hooks, manifestDoc, notesTxt, err := u.cfg.renderResources(chart, valuesToRender, "", "", u.SubNotes, false, false, u.PostRenderer) if err != nil { return nil, nil, err } diff --git a/pkg/postrender/exec.go b/pkg/postrender/exec.go new file mode 100644 index 000000000..dde30f6e3 --- /dev/null +++ b/pkg/postrender/exec.go @@ -0,0 +1,99 @@ +/* +Copyright The Helm 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 postrender + +import ( + "bytes" + "io" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/pkg/errors" + + "helm.sh/helm/v3/pkg/helmpath" +) + +type execRender struct { + binaryPath string +} + +// NewExec returns a PostRenderer implementation that calls the provided binary. +// It returns an error if the binary cannot be found. If the provided path does +// not contain any separators, it will search first in the plugins directory, +// then in $PATH, otherwise it will resolve any relative paths to a fully +// qualified path +func NewExec(binaryPath string) (PostRenderer, error) { + fullPath, err := getFullPath(binaryPath) + if err != nil { + return nil, err + } + return &execRender{fullPath}, nil +} + +// Run the configured binary for the post render +func (p *execRender) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) { + cmd := exec.Command(p.binaryPath) + stdin, err := cmd.StdinPipe() + if err != nil { + return nil, err + } + + var postRendered = &bytes.Buffer{} + var stderr = &bytes.Buffer{} + cmd.Stdout = postRendered + cmd.Stderr = stderr + + go func() { + defer stdin.Close() + io.Copy(stdin, renderedManifests) + }() + err = cmd.Run() + if err != nil { + return nil, errors.Wrapf(err, "error while running command %s. error output:\n%s", p.binaryPath, stderr.String()) + } + + return postRendered, nil +} + +// getFullPath returns the full filepath to the binary to execute. If the path +// does not contain any separators, it will search first in the plugins +// directory, then in $PATH, otherwise it will resolve any relative paths to a +// fully qualified path +func getFullPath(binaryPath string) (string, error) { + // Manually check the plugin dir first + if !strings.Contains(binaryPath, string(filepath.Separator)) { + // First check the plugin dir + pluginDir := helmpath.DataPath("plugins") + _, err := os.Stat(filepath.Join(pluginDir, binaryPath)) + if err != nil && !os.IsNotExist(err) { + return "", err + } else if err == nil { + binaryPath = filepath.Join(pluginDir, binaryPath) + } + } + + // Now check for the binary using the given path or check if it exists in + // the path and is executable + checkedPath, err := exec.LookPath(binaryPath) + if err != nil { + return "", errors.Wrapf(err, "unable to find binary at %s", binaryPath) + } + + return filepath.Abs(checkedPath) +} diff --git a/pkg/postrender/postrender.go b/pkg/postrender/postrender.go new file mode 100644 index 000000000..76f0f5a74 --- /dev/null +++ b/pkg/postrender/postrender.go @@ -0,0 +1,29 @@ +/* +Copyright The Helm 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 postrender contains an interface that can be implemented for custom +// post-renderers and an exec implementation that can be used for arbitrary +// binaries and scripts +package postrender + +import "bytes" + +type PostRenderer interface { + // Run expects a single buffer filled with Helm rendered manifests. It + // expects the modified results to be returned on a separate buffer or an + // error if there was an issue or failure while running the post render step + Run(renderedManifests *bytes.Buffer) (modifiedManifests *bytes.Buffer, err error) +} From 7a3049a418bd78f3cbfc0e479797865e895261af Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Tue, 28 Jan 2020 12:55:17 +0100 Subject: [PATCH 2/3] chore(postrender): Adds unit tests for exec post renderer Signed-off-by: Taylor Thomas --- cmd/helm/template.go | 1 + pkg/postrender/exec.go | 25 ++++-- pkg/postrender/exec_test.go | 152 ++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 pkg/postrender/exec_test.go diff --git a/cmd/helm/template.go b/cmd/helm/template.go index 5c1ba33d1..320718344 100644 --- a/cmd/helm/template.go +++ b/cmd/helm/template.go @@ -132,6 +132,7 @@ func newTemplateCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { f.BoolVar(&client.IsUpgrade, "is-upgrade", false, "set .Release.IsUpgrade instead of .Release.IsInstall") f.StringArrayVarP(&extraAPIs, "api-versions", "a", []string{}, "Kubernetes api versions used for Capabilities.APIVersions") f.BoolVar(&client.UseReleaseName, "release-name", false, "use release name in the output-dir path.") + bindPostRenderFlag(cmd, &client.PostRenderer) return cmd } diff --git a/pkg/postrender/exec.go b/pkg/postrender/exec.go index dde30f6e3..bcf3ef64d 100644 --- a/pkg/postrender/exec.go +++ b/pkg/postrender/exec.go @@ -73,18 +73,27 @@ func (p *execRender) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) // getFullPath returns the full filepath to the binary to execute. If the path // does not contain any separators, it will search first in the plugins -// directory, then in $PATH, otherwise it will resolve any relative paths to a -// fully qualified path +// directory (or directories if multiple are specified. In which case, it will +// return the first result), then in $PATH, otherwise it will resolve any +// relative paths to a fully qualified path func getFullPath(binaryPath string) (string, error) { // Manually check the plugin dir first if !strings.Contains(binaryPath, string(filepath.Separator)) { // First check the plugin dir - pluginDir := helmpath.DataPath("plugins") - _, err := os.Stat(filepath.Join(pluginDir, binaryPath)) - if err != nil && !os.IsNotExist(err) { - return "", err - } else if err == nil { - binaryPath = filepath.Join(pluginDir, binaryPath) + pluginDir := helmpath.DataPath("plugins") // Default location + // If location for plugins is explicitly set, check there + if v, ok := os.LookupEnv("HELM_PLUGINS"); ok { + pluginDir = v + } + // The plugins variable can actually contain multple paths, so loop through those + for _, p := range filepath.SplitList(pluginDir) { + _, err := os.Stat(filepath.Join(p, binaryPath)) + if err != nil && !os.IsNotExist(err) { + return "", err + } else if err == nil { + binaryPath = filepath.Join(p, binaryPath) + break + } } } diff --git a/pkg/postrender/exec_test.go b/pkg/postrender/exec_test.go new file mode 100644 index 000000000..684a0642b --- /dev/null +++ b/pkg/postrender/exec_test.go @@ -0,0 +1,152 @@ +/* +Copyright The Helm 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 postrender + +import ( + "bytes" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "helm.sh/helm/v3/internal/test/ensure" +) + +const testingScript = `#!/bin/sh +sed s/FOOTEST/BARTEST/g <&0 +` + +func TestGetFullPath(t *testing.T) { + is := assert.New(t) + t.Run("full path resolves correctly", func(t *testing.T) { + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + fullPath, err := getFullPath(testpath) + is.NoError(err) + is.Equal(testpath, fullPath) + }) + + t.Run("relative path resolves correctly", func(t *testing.T) { + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + currentDir, err := os.Getwd() + require.NoError(t, err) + relative, err := filepath.Rel(currentDir, testpath) + require.NoError(t, err) + fullPath, err := getFullPath(relative) + is.NoError(err) + is.Equal(testpath, fullPath) + }) + + t.Run("binary in PATH resolves correctly", func(t *testing.T) { + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + realPath := os.Getenv("PATH") + os.Setenv("PATH", filepath.Dir(testpath)) + defer func() { + os.Setenv("PATH", realPath) + }() + + fullPath, err := getFullPath(filepath.Base(testpath)) + is.NoError(err) + is.Equal(testpath, fullPath) + }) + + t.Run("binary in plugin path resolves correctly", func(t *testing.T) { + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + realPath := os.Getenv("HELM_PLUGINS") + os.Setenv("HELM_PLUGINS", filepath.Dir(testpath)) + defer func() { + os.Setenv("HELM_PLUGINS", realPath) + }() + + fullPath, err := getFullPath(filepath.Base(testpath)) + is.NoError(err) + is.Equal(testpath, fullPath) + }) + + t.Run("binary in multiple plugin paths resolves correctly", func(t *testing.T) { + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + realPath := os.Getenv("HELM_PLUGINS") + os.Setenv("HELM_PLUGINS", filepath.Dir(testpath)+string(os.PathListSeparator)+"/another/dir") + defer func() { + os.Setenv("HELM_PLUGINS", realPath) + }() + + fullPath, err := getFullPath(filepath.Base(testpath)) + is.NoError(err) + is.Equal(testpath, fullPath) + }) +} + +func TestExecRun(t *testing.T) { + if runtime.GOOS == "windows" { + // the actual Run test uses a basic sed example, so skip this test on windows + t.Skip("skipping on windows") + } + is := assert.New(t) + testpath, cleanup := setupTestingScript(t) + defer cleanup() + + renderer, err := NewExec(testpath) + require.NoError(t, err) + + output, err := renderer.Run(bytes.NewBufferString("FOOTEST")) + is.NoError(err) + is.Contains(output.String(), "BARTEST") +} + +func setupTestingScript(t *testing.T) (filepath string, cleanup func()) { + t.Helper() + + tempdir := ensure.TempDir(t) + + f, err := ioutil.TempFile(tempdir, "post-render-test.sh") + if err != nil { + t.Fatalf("unable to create tempfile for testing: %s", err) + } + + _, err = f.WriteString(testingScript) + if err != nil { + t.Fatalf("unable to write tempfile for testing: %s", err) + } + + err = f.Chmod(0755) + if err != nil { + t.Fatalf("unable to make tempfile executable for testing: %s", err) + } + + err = f.Close() + if err != nil { + t.Fatalf("unable to close tempfile after writing: %s", err) + } + + return f.Name(), func() { + os.RemoveAll(tempdir) + } +} From cf7a02fac75415c22e420072ed3c17dbd7b53cae Mon Sep 17 00:00:00 2001 From: Taylor Thomas Date: Thu, 6 Feb 2020 12:14:22 -0700 Subject: [PATCH 3/3] chore(*): Removes support for searching the plugin dir Signed-off-by: Taylor Thomas --- cmd/helm/flags.go | 2 +- pkg/postrender/exec.go | 60 ++++++++++++++++++------------------- pkg/postrender/exec_test.go | 51 ++++++++++++++++--------------- 3 files changed, 58 insertions(+), 55 deletions(-) diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index dfaef04a1..86ed53d51 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -98,7 +98,7 @@ func (o *outputValue) Set(s string) error { } func bindPostRenderFlag(cmd *cobra.Command, varRef *postrender.PostRenderer) { - cmd.Flags().Var(&postRenderer{varRef}, postRenderFlag, "the path to an executable to be used for post rendering. If a non-absolute path is provided, the plugin directory and $PATH will be searched") + cmd.Flags().Var(&postRenderer{varRef}, postRenderFlag, "the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path") // Setup shell completion for the flag cmd.MarkFlagCustom(outputFlag, "__helm_output_options") } diff --git a/pkg/postrender/exec.go b/pkg/postrender/exec.go index bcf3ef64d..0860e7c35 100644 --- a/pkg/postrender/exec.go +++ b/pkg/postrender/exec.go @@ -19,14 +19,10 @@ package postrender import ( "bytes" "io" - "os" "os/exec" "path/filepath" - "strings" "github.com/pkg/errors" - - "helm.sh/helm/v3/pkg/helmpath" ) type execRender struct { @@ -34,10 +30,9 @@ type execRender struct { } // NewExec returns a PostRenderer implementation that calls the provided binary. -// It returns an error if the binary cannot be found. If the provided path does -// not contain any separators, it will search first in the plugins directory, -// then in $PATH, otherwise it will resolve any relative paths to a fully -// qualified path +// It returns an error if the binary cannot be found. If the path does not +// contain any separators, it will search in $PATH, otherwise it will resolve +// any relative paths to a fully qualified path func NewExec(binaryPath string) (PostRenderer, error) { fullPath, err := getFullPath(binaryPath) if err != nil { @@ -72,30 +67,35 @@ func (p *execRender) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) } // getFullPath returns the full filepath to the binary to execute. If the path -// does not contain any separators, it will search first in the plugins -// directory (or directories if multiple are specified. In which case, it will -// return the first result), then in $PATH, otherwise it will resolve any -// relative paths to a fully qualified path +// does not contain any separators, it will search in $PATH, otherwise it will +// resolve any relative paths to a fully qualified path func getFullPath(binaryPath string) (string, error) { + // NOTE(thomastaylor312): I am leaving this code commented out here. During + // the implementation of post-render, it was brought up that if we are + // relying on plguins, we should actually use the plugin system so it can + // properly handle multiple OSs. This will be a feature add in the future, + // so I left this code for reference. It can be deleted or reused once the + // feature is implemented + // Manually check the plugin dir first - if !strings.Contains(binaryPath, string(filepath.Separator)) { - // First check the plugin dir - pluginDir := helmpath.DataPath("plugins") // Default location - // If location for plugins is explicitly set, check there - if v, ok := os.LookupEnv("HELM_PLUGINS"); ok { - pluginDir = v - } - // The plugins variable can actually contain multple paths, so loop through those - for _, p := range filepath.SplitList(pluginDir) { - _, err := os.Stat(filepath.Join(p, binaryPath)) - if err != nil && !os.IsNotExist(err) { - return "", err - } else if err == nil { - binaryPath = filepath.Join(p, binaryPath) - break - } - } - } + // if !strings.Contains(binaryPath, string(filepath.Separator)) { + // // First check the plugin dir + // pluginDir := helmpath.DataPath("plugins") // Default location + // // If location for plugins is explicitly set, check there + // if v, ok := os.LookupEnv("HELM_PLUGINS"); ok { + // pluginDir = v + // } + // // The plugins variable can actually contain multple paths, so loop through those + // for _, p := range filepath.SplitList(pluginDir) { + // _, err := os.Stat(filepath.Join(p, binaryPath)) + // if err != nil && !os.IsNotExist(err) { + // return "", err + // } else if err == nil { + // binaryPath = filepath.Join(p, binaryPath) + // break + // } + // } + // } // Now check for the binary using the given path or check if it exists in // the path and is executable diff --git a/pkg/postrender/exec_test.go b/pkg/postrender/exec_test.go index 684a0642b..ef0956949 100644 --- a/pkg/postrender/exec_test.go +++ b/pkg/postrender/exec_test.go @@ -73,35 +73,38 @@ func TestGetFullPath(t *testing.T) { is.Equal(testpath, fullPath) }) - t.Run("binary in plugin path resolves correctly", func(t *testing.T) { - testpath, cleanup := setupTestingScript(t) - defer cleanup() + // NOTE(thomastaylor312): See note in getFullPath for more details why this + // is here - realPath := os.Getenv("HELM_PLUGINS") - os.Setenv("HELM_PLUGINS", filepath.Dir(testpath)) - defer func() { - os.Setenv("HELM_PLUGINS", realPath) - }() + // t.Run("binary in plugin path resolves correctly", func(t *testing.T) { + // testpath, cleanup := setupTestingScript(t) + // defer cleanup() - fullPath, err := getFullPath(filepath.Base(testpath)) - is.NoError(err) - is.Equal(testpath, fullPath) - }) + // realPath := os.Getenv("HELM_PLUGINS") + // os.Setenv("HELM_PLUGINS", filepath.Dir(testpath)) + // defer func() { + // os.Setenv("HELM_PLUGINS", realPath) + // }() - t.Run("binary in multiple plugin paths resolves correctly", func(t *testing.T) { - testpath, cleanup := setupTestingScript(t) - defer cleanup() + // fullPath, err := getFullPath(filepath.Base(testpath)) + // is.NoError(err) + // is.Equal(testpath, fullPath) + // }) - realPath := os.Getenv("HELM_PLUGINS") - os.Setenv("HELM_PLUGINS", filepath.Dir(testpath)+string(os.PathListSeparator)+"/another/dir") - defer func() { - os.Setenv("HELM_PLUGINS", realPath) - }() + // t.Run("binary in multiple plugin paths resolves correctly", func(t *testing.T) { + // testpath, cleanup := setupTestingScript(t) + // defer cleanup() - fullPath, err := getFullPath(filepath.Base(testpath)) - is.NoError(err) - is.Equal(testpath, fullPath) - }) + // realPath := os.Getenv("HELM_PLUGINS") + // os.Setenv("HELM_PLUGINS", filepath.Dir(testpath)+string(os.PathListSeparator)+"/another/dir") + // defer func() { + // os.Setenv("HELM_PLUGINS", realPath) + // }() + + // fullPath, err := getFullPath(filepath.Base(testpath)) + // is.NoError(err) + // is.Equal(testpath, fullPath) + // }) } func TestExecRun(t *testing.T) {