diff --git a/README.md b/README.md index 94267846..db9e5da0 100644 --- a/README.md +++ b/README.md @@ -1124,6 +1124,16 @@ mysetting: | The possibility is endless. Try importing values from your golang app, bash script, jsonnet, or anything! +Then `execEnvs` same as `exec`, but it can receive a dict as the envs. + +A usual usage of `execEnvs` would look like this: + +```yaml +mysetting: | +{{ execEnvs (dict "envkey" "envValue") "./mycmd" (list "arg1" "arg2" "--flag1") | indent 2 }} +``` + + ## Hooks A Helmfile hook is a per-release extension point that is composed of: diff --git a/pkg/tmpl/context_funcs.go b/pkg/tmpl/context_funcs.go index 574be4d4..c2f00159 100644 --- a/pkg/tmpl/context_funcs.go +++ b/pkg/tmpl/context_funcs.go @@ -20,6 +20,7 @@ type Values = map[string]interface{} func (c *Context) createFuncMap() template.FuncMap { funcMap := template.FuncMap{ + "execEnvs": c.ExecEnvs, "exec": c.Exec, "isFile": c.IsFile, "readFile": c.ReadFile, @@ -48,7 +49,8 @@ func (c *Context) createFuncMap() template.FuncMap { return funcMap } -func (c *Context) Exec(command string, args []interface{}, inputs ...string) (string, error) { +// TODO: in the next major version, remove this function. +func (c *Context) ExecEnvs(envs map[string]string, command string, args []interface{}, inputs ...string) (string, error) { var input string if len(inputs) > 0 { input = inputs[0] @@ -66,6 +68,12 @@ func (c *Context) Exec(command string, args []interface{}, inputs ...string) (st cmd := exec.Command(command, strArgs...) cmd.Dir = c.basePath + if envs != nil { + cmd.Env = os.Environ() + for k, v := range envs { + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) + } + } g := errgroup.Group{} @@ -119,6 +127,10 @@ func (c *Context) Exec(command string, args []interface{}, inputs ...string) (st return string(bytes), nil } +func (c *Context) Exec(command string, args []interface{}, inputs ...string) (string, error) { + return c.ExecEnvs(nil, command, args, inputs...) +} + func (c *Context) IsFile(filename string) (bool, error) { var path string if filepath.IsAbs(filename) { diff --git a/pkg/tmpl/context_funcs_test.go b/pkg/tmpl/context_funcs_test.go index 83dd43d2..ed1a2116 100644 --- a/pkg/tmpl/context_funcs_test.go +++ b/pkg/tmpl/context_funcs_test.go @@ -267,3 +267,35 @@ func TestExec(t *testing.T) { _, err = ctx.Exec("bash", []interface{}{"-c", "exit 1"}, "") require.Error(t, err, "Expected error to be returned when executing command with non-zero exit code") } + +// TestExecEnvs tests that ExecEnvs returns the expected output. +// TODO: in the next major version, this test should be removed. +func TestExecEnvs(t *testing.T) { + ctx := &Context{basePath: "."} + + expected := "foo" + + testKey := "testkey" + + // test that the command is executed with environment variables + output, err := ctx.ExecEnvs(map[string]string{testKey: "foo"}, "bash", []interface{}{"-c", fmt.Sprintf("echo -n $%s", testKey)}, "") + + require.Nilf(t, err, "Expected no error to be returned when executing command with environment variables") + + require.Equalf(t, expected, output, "Expected %s to be returned when executing command with environment variables", expected) + + // test that the command is executed with no environment variables + output, err = ctx.ExecEnvs(nil, "bash", []interface{}{"-c", fmt.Sprintf("echo -n $%s", testKey)}, "") + require.Nilf(t, err, "Expected no error to be returned when executing command with no environment variables") + + require.Emptyf(t, output, "Expected empty string to be returned when executing command with no environment variables") + + // test that the command is executed with os environment variables + os.Setenv(testKey, "foo") + defer os.Unsetenv(testKey) + output, err = ctx.ExecEnvs(nil, "bash", []interface{}{"-c", fmt.Sprintf("echo -n $%s", testKey)}, "") + + require.Nilf(t, err, "Expected no error to be returned when executing command with environment variables") + + require.Equalf(t, expected, output, "Expected %s to be returned when executing command with environment variables", expected) +}