github.com/Racer159/helm-experiment@v0.0.0-20230822001441-1eb31183f614/src/lint.go (about) 1 /* 2 Copyright The Helm Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "fmt" 21 "io" 22 "os" 23 "path/filepath" 24 "strings" 25 26 "github.com/pkg/errors" 27 "github.com/spf13/cobra" 28 29 "helm.sh/helm/v3/pkg/action" 30 "helm.sh/helm/v3/pkg/cli/values" 31 "helm.sh/helm/v3/pkg/getter" 32 "helm.sh/helm/v3/pkg/lint/support" 33 ) 34 35 var longLintHelp = ` 36 This command takes a path to a chart and runs a series of tests to verify that 37 the chart is well-formed. 38 39 If the linter encounters things that will cause the chart to fail installation, 40 it will emit [ERROR] messages. If it encounters issues that break with convention 41 or recommendation, it will emit [WARNING] messages. 42 ` 43 44 func newLintCmd(out io.Writer) *cobra.Command { 45 client := action.NewLint() 46 valueOpts := &values.Options{} 47 48 cmd := &cobra.Command{ 49 Use: "lint PATH", 50 Short: "examine a chart for possible issues", 51 Long: longLintHelp, 52 RunE: func(cmd *cobra.Command, args []string) error { 53 paths := []string{"."} 54 if len(args) > 0 { 55 paths = args 56 } 57 if client.WithSubcharts { 58 for _, p := range paths { 59 filepath.Walk(filepath.Join(p, "charts"), func(path string, info os.FileInfo, err error) error { 60 if info != nil { 61 if info.Name() == "Chart.yaml" { 62 paths = append(paths, filepath.Dir(path)) 63 } else if strings.HasSuffix(path, ".tgz") || strings.HasSuffix(path, ".tar.gz") { 64 paths = append(paths, path) 65 } 66 } 67 return nil 68 }) 69 } 70 } 71 72 client.Namespace = settings.Namespace() 73 vals, err := valueOpts.MergeValues(getter.All(settings)) 74 if err != nil { 75 return err 76 } 77 78 var message strings.Builder 79 failed := 0 80 errorsOrWarnings := 0 81 82 for _, path := range paths { 83 result := client.Run([]string{path}, vals) 84 85 // If there is no errors/warnings and quiet flag is set 86 // go to the next chart 87 hasWarningsOrErrors := action.HasWarningsOrErrors(result) 88 if hasWarningsOrErrors { 89 errorsOrWarnings++ 90 } 91 if client.Quiet && !hasWarningsOrErrors { 92 continue 93 } 94 95 fmt.Fprintf(&message, "==> Linting %s\n", path) 96 97 // All the Errors that are generated by a chart 98 // that failed a lint will be included in the 99 // results.Messages so we only need to print 100 // the Errors if there are no Messages. 101 if len(result.Messages) == 0 { 102 for _, err := range result.Errors { 103 fmt.Fprintf(&message, "Error %s\n", err) 104 } 105 } 106 107 for _, msg := range result.Messages { 108 if !client.Quiet || msg.Severity > support.InfoSev { 109 fmt.Fprintf(&message, "%s\n", msg) 110 } 111 } 112 113 if len(result.Errors) != 0 { 114 failed++ 115 } 116 117 // Adding extra new line here to break up the 118 // results, stops this from being a big wall of 119 // text and makes it easier to follow. 120 fmt.Fprint(&message, "\n") 121 } 122 123 fmt.Fprint(out, message.String()) 124 125 summary := fmt.Sprintf("%d chart(s) linted, %d chart(s) failed", len(paths), failed) 126 if failed > 0 { 127 return errors.New(summary) 128 } 129 if !client.Quiet || errorsOrWarnings > 0 { 130 fmt.Fprintln(out, summary) 131 } 132 return nil 133 }, 134 } 135 136 f := cmd.Flags() 137 f.BoolVar(&client.Strict, "strict", false, "fail on lint warnings") 138 f.BoolVar(&client.WithSubcharts, "with-subcharts", false, "lint dependent charts") 139 f.BoolVar(&client.Quiet, "quiet", false, "print only warnings and errors") 140 addValueOptionsFlags(f, valueOpts) 141 142 return cmd 143 }