github.com/codefresh-io/kcfi@v0.0.0-20230301195427-c1578715cc46/cmd/kcfi/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 main
    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  )
    33  
    34  var longLintHelp = `
    35  This command takes a path to a chart and runs a series of tests to verify that
    36  the chart is well-formed.
    37  
    38  If the linter encounters things that will cause the chart to fail installation,
    39  it will emit [ERROR] messages. If it encounters issues that break with convention
    40  or recommendation, it will emit [WARNING] messages.
    41  `
    42  
    43  func newLintCmd(out io.Writer) *cobra.Command {
    44  	client := action.NewLint()
    45  	valueOpts := &values.Options{}
    46  
    47  	cmd := &cobra.Command{
    48  		Use:   "lint PATH",
    49  		Short: "examines a chart for possible issues",
    50  		Long:  longLintHelp,
    51  		RunE: func(cmd *cobra.Command, args []string) error {
    52  			paths := []string{"."}
    53  			if len(args) > 0 {
    54  				paths = args
    55  			}
    56  			if client.WithSubcharts {
    57  				for _, p := range paths {
    58  					filepath.Walk(filepath.Join(p, "charts"), func(path string, info os.FileInfo, err error) error {
    59  						if info != nil {
    60  							if info.Name() == "Chart.yaml" {
    61  								paths = append(paths, filepath.Dir(path))
    62  							} else if strings.HasSuffix(path, ".tgz") || strings.HasSuffix(path, ".tar.gz") {
    63  								paths = append(paths, path)
    64  							}
    65  						}
    66  						return nil
    67  					})
    68  				}
    69  			}
    70  
    71  			client.Namespace = settings.Namespace()
    72  			vals, err := valueOpts.MergeValues(getter.All(settings))
    73  			if err != nil {
    74  				return err
    75  			}
    76  
    77  			var message strings.Builder
    78  			failed := 0
    79  
    80  			for _, path := range paths {
    81  				fmt.Fprintf(&message, "==> Linting %s\n", path)
    82  
    83  				result := client.Run([]string{path}, vals)
    84  
    85  				// All the Errors that are generated by a chart
    86  				// that failed a lint will be included in the
    87  				// results.Messages so we only need to print
    88  				// the Errors if there are no Messages.
    89  				if len(result.Messages) == 0 {
    90  					for _, err := range result.Errors {
    91  						fmt.Fprintf(&message, "Error %s\n", err)
    92  					}
    93  				}
    94  
    95  				for _, msg := range result.Messages {
    96  					fmt.Fprintf(&message, "%s\n", msg)
    97  				}
    98  
    99  				if len(result.Errors) != 0 {
   100  					failed++
   101  				}
   102  
   103  				// Adding extra new line here to break up the
   104  				// results, stops this from being a big wall of
   105  				// text and makes it easier to follow.
   106  				fmt.Fprint(&message, "\n")
   107  			}
   108  
   109  			fmt.Fprint(out, message.String())
   110  
   111  			summary := fmt.Sprintf("%d chart(s) linted, %d chart(s) failed", len(paths), failed)
   112  			if failed > 0 {
   113  				return errors.New(summary)
   114  			}
   115  			fmt.Fprintln(out, summary)
   116  			return nil
   117  		},
   118  	}
   119  
   120  	f := cmd.Flags()
   121  	f.BoolVar(&client.Strict, "strict", false, "fail on lint warnings")
   122  	f.BoolVar(&client.WithSubcharts, "with-subcharts", false, "lint dependent charts")
   123  	addValueOptionsFlags(f, valueOpts)
   124  
   125  	return cmd
   126  }