mirror of
https://github.com/helm/helm.git
synced 2026-04-20 21:56:55 -04:00
Merge pull request #10514 from tanguofu/main
fea(#10511): add --post-renderer-args to support assign args to PostR…
This commit is contained in:
commit
df7c1c39bc
3 changed files with 110 additions and 16 deletions
|
|
@ -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)")
|
||||
|
|
@ -110,33 +113,85 @@ 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(&postRendererString{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(&postRendererArgsSlice{p}, postRenderArgsFlag, "an argument to the post-renderer (can specify multiple)")
|
||||
}
|
||||
|
||||
type postRenderer struct {
|
||||
renderer *postrender.PostRenderer
|
||||
type postRendererOptions struct {
|
||||
renderer *postrender.PostRenderer
|
||||
binaryPath string
|
||||
args []string
|
||||
}
|
||||
|
||||
func (p postRenderer) String() string {
|
||||
return "exec"
|
||||
type postRendererString struct {
|
||||
options *postRendererOptions
|
||||
}
|
||||
|
||||
func (p postRenderer) Type() string {
|
||||
return "postrenderer"
|
||||
func (p *postRendererString) String() string {
|
||||
return p.options.binaryPath
|
||||
}
|
||||
|
||||
func (p postRenderer) Set(s string) error {
|
||||
if s == "" {
|
||||
func (p *postRendererString) Type() string {
|
||||
return "postRendererString"
|
||||
}
|
||||
|
||||
func (p *postRendererString) Set(val string) error {
|
||||
if val == "" {
|
||||
return nil
|
||||
}
|
||||
pr, err := postrender.NewExec(s)
|
||||
p.options.binaryPath = val
|
||||
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 postRendererArgsSlice struct {
|
||||
options *postRendererOptions
|
||||
}
|
||||
|
||||
func (p *postRendererArgsSlice) String() string {
|
||||
return "[" + strings.Join(p.options.args, ",") + "]"
|
||||
}
|
||||
|
||||
func (p *postRendererArgsSlice) Type() string {
|
||||
return "postRendererArgsSlice"
|
||||
}
|
||||
|
||||
func (p *postRendererArgsSlice) Set(val string) error {
|
||||
|
||||
// a post-renderer defined by a user may accept empty arguments
|
||||
p.options.args = append(p.options.args, val)
|
||||
|
||||
if p.options.binaryPath == "" {
|
||||
return nil
|
||||
}
|
||||
// overwrite if already create PostRenderer by `post-renderer` flags
|
||||
pr, err := postrender.NewExec(p.options.binaryPath, p.options.args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*p.options.renderer = pr
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *postRendererArgsSlice) Append(val string) error {
|
||||
p.options.args = append(p.options.args, val)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *postRendererArgsSlice) Replace(val []string) error {
|
||||
p.options.args = val
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *postRendererArgsSlice) GetSlice() []string {
|
||||
return p.options.args
|
||||
}
|
||||
|
||||
func compVersionFlag(chartRef string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||
chartInfo := strings.Split(chartRef, "/")
|
||||
if len(chartInfo) != 2 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -31,7 +31,11 @@ import (
|
|||
)
|
||||
|
||||
const testingScript = `#!/bin/sh
|
||||
if [ $# -eq 0 ]; then
|
||||
sed s/FOOTEST/BARTEST/g <&0
|
||||
else
|
||||
sed s/FOOTEST/"$*"/g <&0
|
||||
fi
|
||||
`
|
||||
|
||||
func TestGetFullPath(t *testing.T) {
|
||||
|
|
@ -124,6 +128,40 @@ func TestExecRun(t *testing.T) {
|
|||
is.Contains(output.String(), "BARTEST")
|
||||
}
|
||||
|
||||
func TestNewExecWithOneArgsRun(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, "ARG1")
|
||||
require.NoError(t, err)
|
||||
|
||||
output, err := renderer.Run(bytes.NewBufferString("FOOTEST"))
|
||||
is.NoError(err)
|
||||
is.Contains(output.String(), "ARG1")
|
||||
}
|
||||
|
||||
func TestNewExecWithTwoArgsRun(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, "ARG1", "ARG2")
|
||||
require.NoError(t, err)
|
||||
|
||||
output, err := renderer.Run(bytes.NewBufferString("FOOTEST"))
|
||||
is.NoError(err)
|
||||
is.Contains(output.String(), "ARG1 ARG2")
|
||||
}
|
||||
|
||||
func setupTestingScript(t *testing.T) (filepath string, cleanup func()) {
|
||||
t.Helper()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue