diff --git a/cmd/helm/flags.go b/cmd/helm/flags.go index aefa836c7..cdd8f9dd5 100644 --- a/cmd/helm/flags.go +++ b/cmd/helm/flags.go @@ -36,8 +36,11 @@ import ( "helm.sh/helm/v3/pkg/repo" ) -const outputFlag = "output" -const postRenderFlag = "post-renderer" +const ( + outputFlag = "output" + postRenderFlag = "post-renderer" + postRenderArgsFlag = "post-renderer-args" +) 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)") @@ -112,30 +115,70 @@ 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 it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path") + p := &postRendererOptions{varRef, "", []string{}} + cmd.Flags().Var(&postRendererExecFlag{p}, 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") + cmd.Flags().Var(&postRendererArgsFlag{p}, postRenderArgsFlag, "the args to an executable to be used for post rendering. (can specify multiple)") +} + +type postRendererOptions struct { + renderer *postrender.PostRenderer + binaryPath string + args []string } -type postRenderer struct { - renderer *postrender.PostRenderer +type postRendererExecFlag struct { + options *postRendererOptions } -func (p postRenderer) String() string { - return "exec" +func (p postRendererExecFlag) String() string { + return "" } -func (p postRenderer) Type() string { - return "postrenderer" +func (p postRendererExecFlag) Type() string { + return "postrenderer-exec" } -func (p postRenderer) Set(s string) error { +func (p postRendererExecFlag) Set(s string) error { if s == "" { return nil } - pr, err := postrender.NewExec(s) + p.options.binaryPath = s + pr, err := postrender.NewExec(p.options.binaryPath, p.options.args) if err != nil { return err } - *p.renderer = pr + *p.options.renderer = pr + return nil +} + +type postRendererArgsFlag struct { + options *postRendererOptions +} + +func (p postRendererArgsFlag) String() string { + return "" +} + +func (p postRendererArgsFlag) Type() string { + return "postrenderer-args" +} + +func (p postRendererArgsFlag) Set(s string) error { + if s == "" { + return nil + } + p.options.args = append(p.options.args, s) + // skip if postRenderFlag not set or parsed + if len(p.options.binaryPath) == 0 { + return nil + } + // update if already create PostRenderer + pr, err := postrender.NewExec(p.options.binaryPath, p.options.args) + if err != nil { + return err + } + + *p.options.renderer = pr return nil } diff --git a/pkg/postrender/exec.go b/pkg/postrender/exec.go index 1de70b024..8cb7760d3 100644 --- a/pkg/postrender/exec.go +++ b/pkg/postrender/exec.go @@ -27,23 +27,24 @@ import ( type execRender struct { binaryPath string + args []string } // NewExec returns a PostRenderer implementation that calls the provided binary. // 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) { +func NewExec(binaryPath string, args []string) (PostRenderer, error) { fullPath, err := getFullPath(binaryPath) if err != nil { return nil, err } - return &execRender{fullPath}, nil + return &execRender{fullPath, args}, nil } // Run the configured binary for the post render func (p *execRender) Run(renderedManifests *bytes.Buffer) (*bytes.Buffer, error) { - cmd := exec.Command(p.binaryPath) + cmd := exec.Command(p.binaryPath, p.args...) stdin, err := cmd.StdinPipe() if err != nil { return nil, err diff --git a/pkg/postrender/exec_test.go b/pkg/postrender/exec_test.go index ef0956949..4b753db63 100644 --- a/pkg/postrender/exec_test.go +++ b/pkg/postrender/exec_test.go @@ -116,7 +116,7 @@ func TestExecRun(t *testing.T) { testpath, cleanup := setupTestingScript(t) defer cleanup() - renderer, err := NewExec(testpath) + renderer, err := NewExec(testpath, []string{}) require.NoError(t, err) output, err := renderer.Run(bytes.NewBufferString("FOOTEST"))