github.com/sgoings/helm@v2.0.0-alpha.2.0.20170406211108-734e92851ac3+incompatible/cmd/helm/lint.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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  	"errors"
    21  	"fmt"
    22  	"io"
    23  	"io/ioutil"
    24  	"os"
    25  	"path/filepath"
    26  	"strings"
    27  
    28  	"github.com/spf13/cobra"
    29  
    30  	"k8s.io/helm/pkg/chartutil"
    31  	"k8s.io/helm/pkg/lint"
    32  	"k8s.io/helm/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  type lintCmd struct {
    45  	strict bool
    46  	paths  []string
    47  	out    io.Writer
    48  }
    49  
    50  func newLintCmd(out io.Writer) *cobra.Command {
    51  	l := &lintCmd{
    52  		paths: []string{"."},
    53  		out:   out,
    54  	}
    55  	cmd := &cobra.Command{
    56  		Use:   "lint [flags] PATH",
    57  		Short: "examines a chart for possible issues",
    58  		Long:  longLintHelp,
    59  		RunE: func(cmd *cobra.Command, args []string) error {
    60  			if len(args) > 0 {
    61  				l.paths = args
    62  			}
    63  			return l.run()
    64  		},
    65  	}
    66  
    67  	cmd.Flags().BoolVar(&l.strict, "strict", false, "fail on lint warnings")
    68  
    69  	return cmd
    70  }
    71  
    72  var errLintNoChart = errors.New("No chart found for linting (missing Chart.yaml)")
    73  
    74  func (l *lintCmd) run() error {
    75  	var lowestTolerance int
    76  	if l.strict {
    77  		lowestTolerance = support.WarningSev
    78  	} else {
    79  		lowestTolerance = support.ErrorSev
    80  	}
    81  
    82  	var total int
    83  	var failures int
    84  	for _, path := range l.paths {
    85  		if linter, err := lintChart(path); err != nil {
    86  			fmt.Println("==> Skipping", path)
    87  			fmt.Println(err)
    88  		} else {
    89  			fmt.Println("==> Linting", path)
    90  
    91  			if len(linter.Messages) == 0 {
    92  				fmt.Println("Lint OK")
    93  			}
    94  
    95  			for _, msg := range linter.Messages {
    96  				fmt.Println(msg)
    97  			}
    98  
    99  			total = total + 1
   100  			if linter.HighestSeverity >= lowestTolerance {
   101  				failures = failures + 1
   102  			}
   103  		}
   104  		fmt.Println("")
   105  	}
   106  
   107  	msg := fmt.Sprintf("%d chart(s) linted", total)
   108  	if failures > 0 {
   109  		return fmt.Errorf("%s, %d chart(s) failed", msg, failures)
   110  	}
   111  
   112  	fmt.Fprintf(l.out, "%s, no failures\n", msg)
   113  
   114  	return nil
   115  }
   116  
   117  func lintChart(path string) (support.Linter, error) {
   118  	var chartPath string
   119  	linter := support.Linter{}
   120  
   121  	if strings.HasSuffix(path, ".tgz") {
   122  		tempDir, err := ioutil.TempDir("", "helm-lint")
   123  		if err != nil {
   124  			return linter, err
   125  		}
   126  		defer os.RemoveAll(tempDir)
   127  
   128  		file, err := os.Open(path)
   129  		if err != nil {
   130  			return linter, err
   131  		}
   132  		defer file.Close()
   133  
   134  		if err = chartutil.Expand(tempDir, file); err != nil {
   135  			return linter, err
   136  		}
   137  
   138  		base := strings.Split(filepath.Base(path), "-")[0]
   139  		chartPath = filepath.Join(tempDir, base)
   140  	} else {
   141  		chartPath = path
   142  	}
   143  
   144  	// Guard: Error out of this is not a chart.
   145  	if _, err := os.Stat(filepath.Join(chartPath, "Chart.yaml")); err != nil {
   146  		return linter, errLintNoChart
   147  	}
   148  
   149  	return lint.All(chartPath), nil
   150  }