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  }