github.com/amy/helm@v2.7.2+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 }