diff --git a/kyaml/runfn/runfn.go b/kyaml/runfn/runfn.go index 0620369f6..bb669ce09 100644 --- a/kyaml/runfn/runfn.go +++ b/kyaml/runfn/runfn.go @@ -92,6 +92,14 @@ type RunFns struct { // Env contains environment variables that will be exported to container Env []string + + // ContinueOnEmptyResult configures what happens when the underlying pipeline + // returns an empty result. + // If it is false (default), subsequent functions will be skipped and the + // result will be returned immediately. + // If it is true, the empty result will be provided as input to the next + // function in the list. + ContinueOnEmptyResult bool } // Execute runs the command @@ -183,9 +191,10 @@ func (r RunFns) runFunctions( var err error pipeline := kio.Pipeline{ - Inputs: []kio.Reader{input}, - Filters: fltrs, - Outputs: outputs, + Inputs: []kio.Reader{input}, + Filters: fltrs, + Outputs: outputs, + ContinueOnEmptyResult: r.ContinueOnEmptyResult, } if r.LogSteps { err = pipeline.ExecuteWithCallback(func(op kio.Filter) { diff --git a/kyaml/runfn/runfn_test.go b/kyaml/runfn/runfn_test.go index 057e45416..80fabc9a2 100644 --- a/kyaml/runfn/runfn_test.go +++ b/kyaml/runfn/runfn_test.go @@ -1080,6 +1080,73 @@ func TestCmd_Execute_enableLogSteps(t *testing.T) { assert.Equal(t, "Running unknown-type function\n", logs.String()) } +func getGeneratorFilterProvider(t *testing.T) func(runtimeutil.FunctionSpec, *yaml.RNode, currentUserFunc) (kio.Filter, error) { + return func(f runtimeutil.FunctionSpec, node *yaml.RNode, currentUser currentUserFunc) (kio.Filter, error) { + return kio.FilterFunc(func(items []*yaml.RNode) ([]*yaml.RNode, error) { + if f.Container.Image == "generate" { + node, err := yaml.Parse("kind: generated") + if !assert.NoError(t, err) { + t.FailNow() + } + return append(items, node), nil + } + return items, nil + }), nil + } +} +func TestRunFns_ContinueOnEmptyResult(t *testing.T) { + fn1, err := yaml.Parse(` +kind: fakefn +metadata: + annotations: + config.kubernetes.io/function: | + container: + image: pass +`) + if !assert.NoError(t, err) { + t.FailNow() + } + fn2, err := yaml.Parse(` +kind: fakefn +metadata: + annotations: + config.kubernetes.io/function: | + container: + image: generate +`) + if !assert.NoError(t, err) { + t.FailNow() + } + + var test = []struct { + ContinueOnEmptyResult bool + ExpectedOutput string + }{ + { + ContinueOnEmptyResult: false, + ExpectedOutput: "", + }, + { + ContinueOnEmptyResult: true, + ExpectedOutput: "kind: generated\n", + }, + } + for i := range test { + ouputBuffer := bytes.Buffer{} + instance := RunFns{ + Input: bytes.NewReader([]byte{}), + Output: &ouputBuffer, + Functions: []*yaml.RNode{fn1, fn2}, + functionFilterProvider: getGeneratorFilterProvider(t), + ContinueOnEmptyResult: test[i].ContinueOnEmptyResult, + } + if !assert.NoError(t, instance.Execute()) { + t.FailNow() + } + assert.Equal(t, test[i].ExpectedOutput, ouputBuffer.String()) + } +} + // setupTest initializes a temp test directory containing test data func setupTest(t *testing.T) string { dir, err := ioutil.TempDir("", "kustomize-kyaml-test")