Add "--set" and "--values" to helm lint

Keep lint syntax as close as possible to "helm install" resp. "helm
upgrade", so that one only needs to change the command.

Closes #2495,#2036
pull/2972/head
Julian Strobl 8 years ago
parent 3307e0998c
commit 76b0d0d8a9

@ -25,11 +25,13 @@ import (
"path/filepath"
"strings"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/lint"
"k8s.io/helm/pkg/lint/support"
"k8s.io/helm/pkg/strvals"
)
var longLintHelp = `
@ -42,6 +44,8 @@ or recommendation, it will emit [WARNING] messages.
`
type lintCmd struct {
valueFiles valueFiles
values []string
namespace string
strict bool
paths []string
@ -65,6 +69,8 @@ func newLintCmd(out io.Writer) *cobra.Command {
},
}
cmd.Flags().VarP(&l.valueFiles, "values", "f", "specify values in a YAML file (can specify multiple)")
cmd.Flags().StringArrayVar(&l.values, "set", []string{}, "set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
cmd.Flags().StringVar(&l.namespace, "namespace", "default", "namespace to install the release into (only used if --install is set)")
cmd.Flags().BoolVar(&l.strict, "strict", false, "fail on lint warnings")
@ -81,10 +87,16 @@ func (l *lintCmd) run() error {
lowestTolerance = support.ErrorSev
}
// Get the raw values
rvals, err := l.vals()
if err != nil {
return err
}
var total int
var failures int
for _, path := range l.paths {
if linter, err := lintChart(path, l.namespace); err != nil {
if linter, err := lintChart(path, rvals, l.namespace); err != nil {
fmt.Println("==> Skipping", path)
fmt.Println(err)
} else {
@ -116,7 +128,7 @@ func (l *lintCmd) run() error {
return nil
}
func lintChart(path string, namespace string) (support.Linter, error) {
func lintChart(path string, vals []byte, namespace string) (support.Linter, error) {
var chartPath string
linter := support.Linter{}
@ -148,5 +160,33 @@ func lintChart(path string, namespace string) (support.Linter, error) {
return linter, errLintNoChart
}
return lint.All(chartPath, namespace), nil
return lint.All(chartPath, vals, namespace), nil
}
func (l *lintCmd) vals() ([]byte, error) {
base := map[string]interface{}{}
// User specified a values files via -f/--values
for _, filePath := range l.valueFiles {
currentMap := map[string]interface{}{}
bytes, err := ioutil.ReadFile(filePath)
if err != nil {
return []byte{}, err
}
if err := yaml.Unmarshal(bytes, &currentMap); err != nil {
return []byte{}, fmt.Errorf("failed to parse %s: %s", filePath, err)
}
// Merge with the previous map
base = mergeValues(base, currentMap)
}
// User specified a value via --set
for _, value := range l.values {
if err := strvals.ParseInto(value, base); err != nil {
return []byte{}, fmt.Errorf("failed parsing --set data: %s", err)
}
}
return yaml.Marshal(base)
}

@ -21,17 +21,18 @@ import (
)
var (
values = []byte{}
namespace = "testNamespace"
archivedChartPath = "testdata/testcharts/compressedchart-0.1.0.tgz"
chartDirPath = "testdata/testcharts/decompressedchart/"
)
func TestLintChart(t *testing.T) {
if _, err := lintChart(chartDirPath, namespace); err != nil {
if _, err := lintChart(chartDirPath, values, namespace); err != nil {
t.Errorf("%s", err)
}
if _, err := lintChart(archivedChartPath, namespace); err != nil {
if _, err := lintChart(archivedChartPath, values, namespace); err != nil {
t.Errorf("%s", err)
}

@ -24,13 +24,13 @@ import (
)
// All runs all of the available linters on the given base directory.
func All(basedir string, namespace string) support.Linter {
func All(basedir string, values []byte, namespace string) support.Linter {
// Using abs path to get directory context
chartDir, _ := filepath.Abs(basedir)
linter := support.Linter{ChartDir: chartDir}
rules.Chartfile(&linter)
rules.Values(&linter)
rules.Templates(&linter, namespace)
rules.Templates(&linter, values, namespace)
return linter
}

@ -24,6 +24,8 @@ import (
"testing"
)
var values = []byte{}
const namespace = "testNamespace"
const badChartDir = "rules/testdata/badchartfile"
@ -32,7 +34,7 @@ const badYamlFileDir = "rules/testdata/albatross"
const goodChartDir = "rules/testdata/goodone"
func TestBadChart(t *testing.T) {
m := All(badChartDir, namespace).Messages
m := All(badChartDir, values, namespace).Messages
if len(m) != 5 {
t.Errorf("Number of errors %v", len(m))
t.Errorf("All didn't fail with expected errors, got %#v", m)
@ -68,7 +70,7 @@ func TestBadChart(t *testing.T) {
}
func TestInvalidYaml(t *testing.T) {
m := All(badYamlFileDir, namespace).Messages
m := All(badYamlFileDir, values, namespace).Messages
if len(m) != 1 {
t.Fatalf("All didn't fail with expected errors, got %#v", m)
}
@ -78,7 +80,7 @@ func TestInvalidYaml(t *testing.T) {
}
func TestBadValues(t *testing.T) {
m := All(badValuesFileDir, namespace).Messages
m := All(badValuesFileDir, values, namespace).Messages
if len(m) != 1 {
t.Fatalf("All didn't fail with expected errors, got %#v", m)
}
@ -88,7 +90,7 @@ func TestBadValues(t *testing.T) {
}
func TestGoodChart(t *testing.T) {
m := All(goodChartDir, namespace).Messages
m := All(goodChartDir, values, namespace).Messages
if len(m) != 0 {
t.Errorf("All failed but shouldn't have: %#v", m)
}

@ -26,12 +26,13 @@ import (
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/engine"
"k8s.io/helm/pkg/lint/support"
cpb "k8s.io/helm/pkg/proto/hapi/chart"
"k8s.io/helm/pkg/timeconv"
tversion "k8s.io/helm/pkg/version"
)
// Templates lints the templates in the Linter.
func Templates(linter *support.Linter, namespace string) {
func Templates(linter *support.Linter, values []byte, namespace string) {
path := "templates/"
templatesPath := filepath.Join(linter.ChartDir, path)
@ -57,7 +58,17 @@ func Templates(linter *support.Linter, namespace string) {
KubeVersion: chartutil.DefaultKubeVersion,
TillerVersion: tversion.GetVersionProto(),
}
valuesToRender, err := chartutil.ToRenderValuesCaps(chart, chart.Values, options, caps)
cvals, err := chartutil.CoalesceValues(chart, &cpb.Config{Raw: string(values)})
if err != nil {
return
}
// convert our values back into config
yvals, err := cvals.YAML()
if err != nil {
return
}
cc := &cpb.Config{Raw: yvals}
valuesToRender, err := chartutil.ToRenderValuesCaps(chart, cc, options, caps)
if err != nil {
// FIXME: This seems to generate a duplicate, but I can't find where the first
// error is coming from.

@ -44,11 +44,13 @@ func TestValidateAllowedExtension(t *testing.T) {
}
}
var values = []byte("nameOverride: ''\nhttpPort: 80")
const namespace = "testNamespace"
func TestTemplateParsing(t *testing.T) {
linter := support.Linter{ChartDir: templateTestBasedir}
Templates(&linter, namespace)
Templates(&linter, values, namespace)
res := linter.Messages
if len(res) != 1 {
@ -71,7 +73,7 @@ func TestTemplateIntegrationHappyPath(t *testing.T) {
defer os.Rename(ignoredTemplatePath, wrongTemplatePath)
linter := support.Linter{ChartDir: templateTestBasedir}
Templates(&linter, namespace)
Templates(&linter, values, namespace)
res := linter.Messages
if len(res) != 0 {

Loading…
Cancel
Save