Repository: helm/helm (go)

Issue:
helm lint to lint also dependent charts
<!-- If you need help or think you have found a bug, please help us with your issue by entering the following information (otherwise you can delete this text): -->

Output of `helm version`:
Not applicable.

Output of `kubectl version`:
Not applicable.

Cloud Provider/Platform (AKS, GKE, Minikube etc.): 
Not applicable.

Currently `helm lint` does not fail when there is an error in dependent chart. `helm lint --strict` fails which is surprising for as the helm of the --strict flag is `fail on lint warnings` - which means that helm lint should detect warnings and --strict just to transform the warnings to errors.

It will be useful if `helm lint` is able to lint also dependent charts (in `charts/`).



Pull request description:
feat(cmd/lint): added flag to lint dependent charts
feat(cmd/lint): added flag to lint dependent charts. Supplying the flag `--with-subcharts` will also lint the dependent charts in `/charts`

Closes #5767.

Signed-off-by: Nick Lee nmkyu.lee@gmail.com

Patch:
diff --git a/cmd/helm/lint.go b/cmd/helm/lint.go
index 9a2e8d31c..bc0d1852b 100644
--- a/cmd/helm/lint.go
+++ b/cmd/helm/lint.go
@@ -19,6 +19,8 @@ package main
 import (
 	"fmt"
 	"io"
+	"os"
+	"path/filepath"
 	"strings"
 
 	"github.com/pkg/errors"
@@ -51,6 +53,21 @@ func newLintCmd(out io.Writer) *cobra.Command {
 			if len(args) > 0 {
 				paths = args
 			}
+			if client.WithSubcharts {
+				for _, p := range paths {
+					filepath.Walk(filepath.Join(p, "charts"), func(path string, info os.FileInfo, err error) error {
+						if info != nil {
+							if info.Name() == "Chart.yaml" {
+								paths = append(paths, filepath.Dir(path))
+							} else if strings.HasSuffix(path, ".tgz") || strings.HasSuffix(path, ".tar.gz") {
+								paths = append(paths, path)
+							}
+						}
+						return nil
+					})
+				}
+			}
+
 			client.Namespace = settings.Namespace()
 			vals, err := valueOpts.MergeValues(getter.All(settings))
 			if err != nil {
@@ -102,6 +119,7 @@ func newLintCmd(out io.Writer) *cobra.Command {
 
 	f := cmd.Flags()
 	f.BoolVar(&client.Strict, "strict", false, "fail on lint warnings")
+	f.BoolVar(&client.WithSubcharts, "with-subcharts", false, "lint dependent charts")
 	addValueOptionsFlags(f, valueOpts)
 
 	return cmd
diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/values.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/values.yaml
new file mode 100644
index 000000000..e69de29bb
diff --git a/pkg/action/lint.go b/pkg/action/lint.go
index c216c5832..ddb0101c7 100644
--- a/pkg/action/lint.go
+++ b/pkg/action/lint.go
@@ -33,8 +33,9 @@ import (
 //
 // It provides the implementation of 'helm lint'.
 type Lint struct {
-	Strict    bool
-	Namespace string
+	Strict        bool
+	Namespace     string
+	WithSubcharts bool
 }
 
 type LintResult struct {


Test patch:
diff --git a/cmd/helm/lint_test.go b/cmd/helm/lint_test.go
new file mode 100644
index 000000000..7638acb84
--- /dev/null
+++ b/cmd/helm/lint_test.go
@@ -0,0 +1,38 @@
+/*
+Copyright The Helm Authors.
+
+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.
+*/
+
+package main
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestLintCmdWithSubchartsFlag(t *testing.T) {
+	testChart := "testdata/testcharts/chart-with-bad-subcharts"
+	tests := []cmdTestCase{{
+		name:      "lint good chart with bad subcharts",
+		cmd:       fmt.Sprintf("lint %s", testChart),
+		golden:    "output/lint-chart-with-bad-subcharts.txt",
+		wantError: false,
+	}, {
+		name:      "lint good chart with bad subcharts using --with-subcharts flag",
+		cmd:       fmt.Sprintf("lint --with-subcharts %s", testChart),
+		golden:    "output/lint-chart-with-bad-subcharts-with-subcharts.txt",
+		wantError: true,
+	}}
+	runTestCmd(t, tests)
+}
diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt
new file mode 100644
index 000000000..cda011b57
--- /dev/null
+++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts-with-subcharts.txt
@@ -0,0 +1,16 @@
+==> Linting testdata/testcharts/chart-with-bad-subcharts
+[INFO] Chart.yaml: icon is recommended
+[WARNING] templates/: directory not found
+
+==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart
+[ERROR] Chart.yaml: name is required
+[ERROR] Chart.yaml: apiVersion is required. The value must be either "v1" or "v2"
+[ERROR] Chart.yaml: version is required
+[INFO] Chart.yaml: icon is recommended
+[WARNING] templates/: directory not found
+
+==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart
+[INFO] Chart.yaml: icon is recommended
+[WARNING] templates/: directory not found
+
+Error: 3 chart(s) linted, 1 chart(s) failed
diff --git a/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt
new file mode 100644
index 000000000..51f3f3718
--- /dev/null
+++ b/cmd/helm/testdata/output/lint-chart-with-bad-subcharts.txt
@@ -0,0 +1,5 @@
+==> Linting testdata/testcharts/chart-with-bad-subcharts
+[INFO] Chart.yaml: icon is recommended
+[WARNING] templates/: directory not found
+
+1 chart(s) linted, 0 chart(s) failed
diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/Chart.yaml
new file mode 100644
index 000000000..a575aa9f8
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/Chart.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+description: Chart with bad subcharts
+name: chart-with-bad-subcharts
+version: 0.0.1
diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml
new file mode 100644
index 000000000..0daa5c188
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml
@@ -0,0 +1,1 @@
+description: Bad subchart
\ No newline at end of file
diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/values.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/values.yaml
new file mode 100644
index 000000000..e69de29bb
diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/Chart.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/Chart.yaml
new file mode 100644
index 000000000..895433e31
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/Chart.yaml
@@ -0,0 +1,4 @@
+apiVersion: v1
+description: Good subchart
+name: good-subchart
+version: 0.0.1
\ No newline at end of file
diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/values.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/values.yaml
new file mode 100644
index 000000000..e69de29bb
diff --git a/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/requirements.yaml b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/requirements.yaml
new file mode 100644
index 000000000..de2fbb4dd
--- /dev/null
+++ b/cmd/helm/testdata/testcharts/chart-with-bad-subcharts/requirements.yaml
@@ -0,0 +1,5 @@
+dependencies:
+  - name: good-subchart
+    version: 0.0.1
+  - name: bad-subchart
+    version: 0.0.1
\ No newline at end of file