Repository: GoogleContainerTools/kpt
Pull request #2644 (2022-01-11 23:21:05)

Update cli-utils to v0.27.0
Update kpt to use version 0.27.0 of cli-utils



Patch:
diff --git a/go.mod b/go.mod
index dc5ecbfd..4dda367e 100644
--- a/go.mod
+++ b/go.mod
@@ -22,7 +22,7 @@ require (
 	k8s.io/klog/v2 v2.10.0
 	k8s.io/kube-openapi v0.0.0-20211109043139-026bd182f079 // indirect
 	k8s.io/kubectl v0.22.2
-	sigs.k8s.io/cli-utils v0.26.1-0.20220111001916-0c9b214db384
+	sigs.k8s.io/cli-utils v0.27.0
 	sigs.k8s.io/kustomize/api v0.8.11
 	sigs.k8s.io/kustomize/kyaml v0.13.1-0.20211203194734-cd2c6a1ad117
 )
diff --git a/go.sum b/go.sum
index bcda51b6..c2f25062 100644
--- a/go.sum
+++ b/go.sum
@@ -1022,8 +1022,8 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
-sigs.k8s.io/cli-utils v0.26.1-0.20220111001916-0c9b214db384 h1:wElBbmlm1HWOxmnn1YWf0hR6BLrFFkszKCBfOWDDYv0=
-sigs.k8s.io/cli-utils v0.26.1-0.20220111001916-0c9b214db384/go.mod h1:8ll2fyx+bzjbwmwUnKBQU+2LDbMDsxy44DiDZ+drALg=
+sigs.k8s.io/cli-utils v0.27.0 h1:BxI7lPNn0fBZa5g4UwR+ShJyL4CCxELA6tLHbr2YrpU=
+sigs.k8s.io/cli-utils v0.27.0/go.mod h1:8ll2fyx+bzjbwmwUnKBQU+2LDbMDsxy44DiDZ+drALg=
 sigs.k8s.io/controller-runtime v0.10.1 h1:+eLHgY/VrJWnfg6iXUqhCUqNXgPH1NZeP9drNAAgWlg=
 sigs.k8s.io/controller-runtime v0.10.1/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
 sigs.k8s.io/kustomize/api v0.8.11 h1:LzQzlq6Z023b+mBtc6v72N2mSHYmN8x7ssgbf/hv0H8=
diff --git a/internal/fnruntime/runner.go b/internal/fnruntime/runner.go
index 8ec6f7f5..051a5330 100644
--- a/internal/fnruntime/runner.go
+++ b/internal/fnruntime/runner.go
@@ -165,6 +165,7 @@ func (fr *FunctionRunner) Filter(input []*yaml.RNode) (output []*yaml.RNode, err
 	if !fr.disableCLIOutput {
 		pr.Printf("[PASS] %q in %v\n", fr.name, time.Since(t0).Truncate(time.Millisecond*100))
 		printFnResult(fr.ctx, fr.fnResult, printer.NewOpt())
+		printFnStderr(fr.ctx, fr.fnResult.Stderr)
 	}
 	return output, err
 }
@@ -345,16 +346,22 @@ func printFnResult(ctx context.Context, fnResult *fnresult.Result, opt *printer.
 // on kpt CLI.
 func printFnExecErr(ctx context.Context, fnErr *ExecError) {
 	pr := printer.FromContextOrDie(ctx)
-	if len(fnErr.Stderr) > 0 {
+	printFnStderr(ctx, fnErr.Stderr)
+	pr.Printf("  Exit code: %d\n\n", fnErr.ExitCode)
+}
+
+// printFnStderr prints given stdErr in a user friendly format on kpt CLI.
+func printFnStderr(ctx context.Context, stdErr string) {
+	pr := printer.FromContextOrDie(ctx)
+	if len(stdErr) > 0 {
 		errLines := &multiLineFormatter{
 			Title:          "Stderr",
-			Lines:          strings.Split(fnErr.Stderr, "\n"),
+			Lines:          strings.Split(stdErr, "\n"),
 			UseQuote:       true,
 			TruncateOutput: printer.TruncateOutput,
 		}
 		pr.Printf("%s", errLines.String())
 	}
-	pr.Printf("  Exit code: %d\n\n", fnErr.ExitCode)
 }
 
 // path (location) of a KRM resources is tracked in a special key in


Test patch:
diff --git a/e2e/testdata/fn-eval/exec-function-stderr/.expected/config.yaml b/e2e/testdata/fn-eval/exec-function-stderr/.expected/config.yaml
new file mode 100644
index 00000000..f45537b8
--- /dev/null
+++ b/e2e/testdata/fn-eval/exec-function-stderr/.expected/config.yaml
@@ -0,0 +1,24 @@
+# Copyright 2021 Google LLC
+#
+# 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.
+
+testType: eval
+stdErr: |
+  [RUNNING] "./function.sh"
+  [PASS] "./function.sh" in 0s
+    Stderr:
+      "Hello world 0!"
+      "Hello world 1!"
+      "Hello world 2!"
+      "Hello world 3!"
+      ...(18 line(s) truncated, use '--truncate-output=false' to disable)
diff --git a/e2e/testdata/fn-eval/exec-function-stderr/.expected/diff.patch b/e2e/testdata/fn-eval/exec-function-stderr/.expected/diff.patch
new file mode 100644
index 00000000..cc985fa3
--- /dev/null
+++ b/e2e/testdata/fn-eval/exec-function-stderr/.expected/diff.patch
@@ -0,0 +1,21 @@
+diff --git a/resources.yaml b/resources.yaml
+index e8ae6bb..297b99f 100644
+--- a/resources.yaml
++++ b/resources.yaml
+@@ -15,7 +15,7 @@ apiVersion: apps/v1
+ kind: Deployment
+ metadata:
+   name: nginx-deployment
+-  namespace: foo
++  namespace: bar
+ spec:
+   replicas: 3
+ ---
+@@ -23,6 +23,6 @@ apiVersion: custom.io/v1
+ kind: Custom
+ metadata:
+   name: custom
+-  namespace: foo
++  namespace: bar
+ spec:
+   image: nginx:1.2.3
diff --git a/e2e/testdata/fn-eval/exec-function-stderr/.expected/exec.sh b/e2e/testdata/fn-eval/exec-function-stderr/.expected/exec.sh
new file mode 100644
index 00000000..4a180de5
--- /dev/null
+++ b/e2e/testdata/fn-eval/exec-function-stderr/.expected/exec.sh
@@ -0,0 +1,19 @@
+#! /bin/bash
+# Copyright 2021 Google LLC
+#
+# 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.
+
+set -eo pipefail
+
+kpt fn source \
+  | kpt fn eval --exec ./function.sh
diff --git a/e2e/testdata/fn-eval/exec-function-stderr/.krmignore b/e2e/testdata/fn-eval/exec-function-stderr/.krmignore
new file mode 100644
index 00000000..9d7a4007
--- /dev/null
+++ b/e2e/testdata/fn-eval/exec-function-stderr/.krmignore
@@ -0,0 +1,1 @@
+.expected
diff --git a/e2e/testdata/fn-eval/exec-function-stderr/function.sh b/e2e/testdata/fn-eval/exec-function-stderr/function.sh
new file mode 100755
index 00000000..c9cb9d7b
--- /dev/null
+++ b/e2e/testdata/fn-eval/exec-function-stderr/function.sh
@@ -0,0 +1,21 @@
+#! /usr/bin/env bash
+# Copyright 2021 Google LLC
+#
+# 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.
+
+sed -e 's/foo/bar/'
+
+for i in {0..20}
+do
+  >&2 echo "Hello world $i!"
+done
diff --git a/e2e/testdata/fn-eval/exec-function-stderr/resources.yaml b/e2e/testdata/fn-eval/exec-function-stderr/resources.yaml
new file mode 100644
index 00000000..e8ae6bba
--- /dev/null
+++ b/e2e/testdata/fn-eval/exec-function-stderr/resources.yaml
@@ -0,0 +1,28 @@
+# Copyright 2021 Google LLC
+#
+# 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.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nginx-deployment
+  namespace: foo
+spec:
+  replicas: 3
+---
+apiVersion: custom.io/v1
+kind: Custom
+metadata:
+  name: custom
+  namespace: foo
+spec:
+  image: nginx:1.2.3
diff --git a/e2e/testdata/fn-render/exec-function-stderr/.expected/config.yaml b/e2e/testdata/fn-render/exec-function-stderr/.expected/config.yaml
new file mode 100644
index 00000000..9183295c
--- /dev/null
+++ b/e2e/testdata/fn-render/exec-function-stderr/.expected/config.yaml
@@ -0,0 +1,24 @@
+# Copyright 2021 Google LLC
+#
+# 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.
+
+allowExec: true
+stdErr: |
+  [RUNNING] "./testdata/fn-render/exec-function-stderr/function.sh"
+  [PASS] "./testdata/fn-render/exec-function-stderr/function.sh" in 0s
+    Stderr:
+      "Hello world 0!"
+      "Hello world 1!"
+      "Hello world 2!"
+      "Hello world 3!"
+      ...(18 line(s) truncated, use '--truncate-output=false' to disable)
diff --git a/e2e/testdata/fn-render/exec-function-stderr/.expected/diff.patch b/e2e/testdata/fn-render/exec-function-stderr/.expected/diff.patch
new file mode 100644
index 00000000..cc985fa3
--- /dev/null
+++ b/e2e/testdata/fn-render/exec-function-stderr/.expected/diff.patch
@@ -0,0 +1,21 @@
+diff --git a/resources.yaml b/resources.yaml
+index e8ae6bb..297b99f 100644
+--- a/resources.yaml
++++ b/resources.yaml
+@@ -15,7 +15,7 @@ apiVersion: apps/v1
+ kind: Deployment
+ metadata:
+   name: nginx-deployment
+-  namespace: foo
++  namespace: bar
+ spec:
+   replicas: 3
+ ---
+@@ -23,6 +23,6 @@ apiVersion: custom.io/v1
+ kind: Custom
+ metadata:
+   name: custom
+-  namespace: foo
++  namespace: bar
+ spec:
+   image: nginx:1.2.3
diff --git a/e2e/testdata/fn-render/exec-function-stderr/.krmignore b/e2e/testdata/fn-render/exec-function-stderr/.krmignore
new file mode 100644
index 00000000..9d7a4007
--- /dev/null
+++ b/e2e/testdata/fn-render/exec-function-stderr/.krmignore
@@ -0,0 +1,1 @@
+.expected
diff --git a/e2e/testdata/fn-render/exec-function-stderr/Kptfile b/e2e/testdata/fn-render/exec-function-stderr/Kptfile
new file mode 100644
index 00000000..6f2fe112
--- /dev/null
+++ b/e2e/testdata/fn-render/exec-function-stderr/Kptfile
@@ -0,0 +1,7 @@
+apiVersion: kpt.dev/v1
+kind: Kptfile
+metadata:
+  name: app
+pipeline:
+  mutators:
+    - exec: "./testdata/fn-render/exec-function-stderr/function.sh"
diff --git a/e2e/testdata/fn-render/exec-function-stderr/function.sh b/e2e/testdata/fn-render/exec-function-stderr/function.sh
new file mode 100755
index 00000000..c9cb9d7b
--- /dev/null
+++ b/e2e/testdata/fn-render/exec-function-stderr/function.sh
@@ -0,0 +1,21 @@
+#! /usr/bin/env bash
+# Copyright 2021 Google LLC
+#
+# 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.
+
+sed -e 's/foo/bar/'
+
+for i in {0..20}
+do
+  >&2 echo "Hello world $i!"
+done
diff --git a/e2e/testdata/fn-render/exec-function-stderr/resources.yaml b/e2e/testdata/fn-render/exec-function-stderr/resources.yaml
new file mode 100644
index 00000000..e8ae6bba
--- /dev/null
+++ b/e2e/testdata/fn-render/exec-function-stderr/resources.yaml
@@ -0,0 +1,28 @@
+# Copyright 2021 Google LLC
+#
+# 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.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nginx-deployment
+  namespace: foo
+spec:
+  replicas: 3
+---
+apiVersion: custom.io/v1
+kind: Custom
+metadata:
+  name: custom
+  namespace: foo
+spec:
+  image: nginx:1.2.3
diff --git a/internal/fnruntime/runner_test.go b/internal/fnruntime/runner_test.go
index 8c3e7494..97fd2b1f 100644
--- a/internal/fnruntime/runner_test.go
+++ b/internal/fnruntime/runner_test.go
@@ -18,12 +18,14 @@ package fnruntime
 
 import (
 	"bytes"
+	"context"
 	"io/ioutil"
 	"os"
 	"path"
 	"strings"
 	"testing"
 
+	"github.com/GoogleContainerTools/kpt/internal/printer"
 	"github.com/GoogleContainerTools/kpt/internal/types"
 	kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
 	"github.com/stretchr/testify/assert"
@@ -577,3 +579,70 @@ file:
 		assert.Equal(t, tc.expected, string(out))
 	}
 }
+
+func TestPrintFnStderr(t *testing.T) {
+	tests := map[string]struct {
+		input          string // input
+		truncateOutput bool   // whether to truncate output
+		expected       string // expected result
+	}{
+		"no output": {
+			input:          ``,
+			truncateOutput: true,
+			expected:       ``,
+		},
+		"truncated output": {
+			input: `0
+1
+2
+3
+4
+5`,
+			truncateOutput: true,
+			expected: `  Stderr:
+    "0"
+    "1"
+    "2"
+    "3"
+    ...(2 line(s) truncated, use '--truncate-output=false' to disable)
+`,
+		},
+		"non-truncated output": {
+			input: `0
+1
+2
+3
+4
+5`,
+			truncateOutput: false,
+			expected: `  Stderr:
+    "0"
+    "1"
+    "2"
+    "3"
+    "4"
+    "5"
+`,
+		},
+	}
+	cleanupFunc := func() func() {
+		origTruncateOutput := printer.TruncateOutput
+		return func() {
+			printer.TruncateOutput = origTruncateOutput
+		}
+	}()
+	defer cleanupFunc()
+	for testName, tc := range tests {
+		t.Run(testName, func(t *testing.T) {
+			printer.TruncateOutput = tc.truncateOutput
+			out := &bytes.Buffer{}
+			err := &bytes.Buffer{}
+			ctx := printer.WithContext(context.Background(), printer.New(out, err))
+
+			printFnStderr(ctx, tc.input)
+
+			assert.Equal(t, tc.expected, err.String())
+			assert.Equal(t, "", out.String())
+		})
+	}
+}