Hip 0019 initial pr add env variable (#28)

* add variable to environment.go

Signed-off-by: Danilo Patrucco <danilo.patrucco@gmail.com>

* added variable and tested, need to add tests

Signed-off-by: Danilo Patrucco <danilo.patrucco@gmail.com>

* refactor all the lintignore into lintconfig

Signed-off-by: Danilo Patrucco <danilo.patrucco@gmail.com>

* cahnges from review

Signed-off-by: Danilo Patrucco <danilo.patrucco@gmail.com>

* Copy edit to HELM_LINT_CONFIG_FILE docstring in cmd/helm/root.go

Signed-off-by: Daniel Pritchett  <dpritchett@gmail.com>

---------

Signed-off-by: Danilo Patrucco <danilo.patrucco@gmail.com>
Signed-off-by: Daniel Pritchett  <dpritchett@gmail.com>
Co-authored-by: Daniel Pritchett  <dpritchett@radiusmethod.com>
pull/13257/head
danilo patrucco 1 year ago committed by GitHub
parent 67a410fcee
commit 0039252382
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -46,7 +46,7 @@ func newLintCmd(out io.Writer) *cobra.Command {
client := action.NewLint() client := action.NewLint()
valueOpts := &values.Options{} valueOpts := &values.Options{}
var kubeVersion string var kubeVersion string
var lintIgnoreFile string var lintConfigFile string
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "lint PATH", Use: "lint PATH",
@ -80,7 +80,6 @@ func newLintCmd(out io.Writer) *cobra.Command {
}) })
} }
} }
client.Namespace = settings.Namespace() client.Namespace = settings.Namespace()
vals, err := valueOpts.MergeValues(getter.All(settings)) vals, err := valueOpts.MergeValues(getter.All(settings))
if err != nil { if err != nil {
@ -92,7 +91,7 @@ func newLintCmd(out io.Writer) *cobra.Command {
errorsOrWarnings := 0 errorsOrWarnings := 0
for _, path := range paths { for _, path := range paths {
result := client.Run([]string{path}, vals, lintIgnoreFile, debug) result := client.Run([]string{path}, vals, lintConfigFile, debug)
// If there is no errors/warnings and quiet flag is set // If there is no errors/warnings and quiet flag is set
// go to the next chart // go to the next chart
@ -151,7 +150,7 @@ func newLintCmd(out io.Writer) *cobra.Command {
f.BoolVar(&client.Quiet, "quiet", false, "print only warnings and errors") f.BoolVar(&client.Quiet, "quiet", false, "print only warnings and errors")
f.BoolVar(&client.SkipSchemaValidation, "skip-schema-validation", false, "if set, disables JSON schema validation") f.BoolVar(&client.SkipSchemaValidation, "skip-schema-validation", false, "if set, disables JSON schema validation")
f.StringVar(&kubeVersion, "kube-version", "", "Kubernetes version used for capabilities and deprecation checks") f.StringVar(&kubeVersion, "kube-version", "", "Kubernetes version used for capabilities and deprecation checks")
f.StringVar(&lintIgnoreFile, "lint-ignore-file", "", "path to .helmlintignore file to specify ignore patterns") f.StringVar(&lintConfigFile, "lint-config-file", os.Getenv("HELM_LINT_CONFIG_FILE"), "path to .helmlintconfig.yaml file to specify ignore patterns")
addValueOptionsFlags(f, valueOpts) addValueOptionsFlags(f, valueOpts)
return cmd return cmd

@ -71,6 +71,7 @@ Environment variables:
| $HELM_KUBETLS_SERVER_NAME | set the server name used to validate the Kubernetes API server certificate | | $HELM_KUBETLS_SERVER_NAME | set the server name used to validate the Kubernetes API server certificate |
| $HELM_BURST_LIMIT | set the default burst limit in the case the server contains many CRDs (default 100, -1 to disable) | | $HELM_BURST_LIMIT | set the default burst limit in the case the server contains many CRDs (default 100, -1 to disable) |
| $HELM_QPS | set the Queries Per Second in cases where a high number of calls exceed the option for higher burst values | | $HELM_QPS | set the Queries Per Second in cases where a high number of calls exceed the option for higher burst values |
| $HELM_LINT_CONFIG_FILE | set the location for the config file for linting |
Helm stores cache, configuration, and data based on the following configuration order: Helm stores cache, configuration, and data based on the following configuration order:

@ -55,7 +55,7 @@ func NewLint() *Lint {
} }
// Run executes 'helm Lint' against the given chart. // Run executes 'helm Lint' against the given chart.
func (l *Lint) Run(paths []string, vals map[string]interface{}, lintIgnoreFilePath string, debugLogFn func(string, ...interface{})) *LintResult { func (l *Lint) Run(paths []string, vals map[string]interface{}, lintConfigFilePath string, debugLogFn func(string, ...interface{})) *LintResult {
lowestTolerance := support.ErrorSev lowestTolerance := support.ErrorSev
if l.Strict { if l.Strict {
lowestTolerance = support.WarningSev lowestTolerance = support.WarningSev
@ -63,7 +63,7 @@ func (l *Lint) Run(paths []string, vals map[string]interface{}, lintIgnoreFilePa
result := &LintResult{} result := &LintResult{}
for chartIndex, path := range paths { for chartIndex, path := range paths {
// attempt to build an action-level lint result ignorer // attempt to build an action-level lint result ignorer
ignorer, err := ignore.NewIgnorer(path, lintIgnoreFilePath, debugLogFn) ignorer, err := ignore.NewIgnorer(path, lintConfigFilePath, debugLogFn)
linter, err := lintChart(path, vals, l.Namespace, l.KubeVersion, l.SkipSchemaValidation) linter, err := lintChart(path, vals, l.Namespace, l.KubeVersion, l.SkipSchemaValidation)
if err != nil { if err != nil {
// ❗ Discard ignorable errors as early as possible // ❗ Discard ignorable errors as early as possible

@ -30,10 +30,10 @@ var (
chart2MultipleChartLint = "testdata/charts/multiplecharts-lint-chart-2" chart2MultipleChartLint = "testdata/charts/multiplecharts-lint-chart-2"
corruptedTgzChart = "testdata/charts/corrupted-compressed-chart.tgz" corruptedTgzChart = "testdata/charts/corrupted-compressed-chart.tgz"
chartWithNoTemplatesDir = "testdata/charts/chart-with-no-templates-dir" chartWithNoTemplatesDir = "testdata/charts/chart-with-no-templates-dir"
messyChartWithLintIgnore = "testdata/charts/messy-chart-with-lintignore" messyChartWithLintIgnore = "testdata/charts/messy-chart-with-lintconfig"
) )
const emptyLintIgnoreFilePath = "" const emptyLintConfigFilePath = ""
var settings = cli.New() var settings = cli.New()
@ -115,7 +115,7 @@ func TestNonExistentChart(t *testing.T) {
expectedError := "unable to open tarball: open non-existent-chart.tgz: no such file or directory" expectedError := "unable to open tarball: open non-existent-chart.tgz: no such file or directory"
testLint := NewLint() testLint := NewLint()
result := testLint.Run(testCharts, values, emptyLintIgnoreFilePath, debugLogFn) result := testLint.Run(testCharts, values, emptyLintConfigFilePath, debugLogFn)
if len(result.Errors) != 1 { if len(result.Errors) != 1 {
t.Error("expected one error, but got", len(result.Errors)) t.Error("expected one error, but got", len(result.Errors))
} }
@ -131,7 +131,7 @@ func TestNonExistentChart(t *testing.T) {
expectedEOFError := "unable to extract tarball: EOF" expectedEOFError := "unable to extract tarball: EOF"
testLint := NewLint() testLint := NewLint()
result := testLint.Run(testCharts, values, emptyLintIgnoreFilePath, debugLogFn) result := testLint.Run(testCharts, values, emptyLintConfigFilePath, debugLogFn)
if len(result.Errors) != 1 { if len(result.Errors) != 1 {
t.Error("expected one error, but got", len(result.Errors)) t.Error("expected one error, but got", len(result.Errors))
} }
@ -146,7 +146,7 @@ func TestNonExistentChart(t *testing.T) {
func TestLint_MultipleCharts(t *testing.T) { func TestLint_MultipleCharts(t *testing.T) {
testCharts := []string{chart2MultipleChartLint, chart1MultipleChartLint} testCharts := []string{chart2MultipleChartLint, chart1MultipleChartLint}
testLint := NewLint() testLint := NewLint()
if result := testLint.Run(testCharts, values, emptyLintIgnoreFilePath, debugLogFn); len(result.Errors) > 0 { if result := testLint.Run(testCharts, values, emptyLintConfigFilePath, debugLogFn); len(result.Errors) > 0 {
t.Error(result.Errors) t.Error(result.Errors)
} }
} }
@ -154,7 +154,7 @@ func TestLint_MultipleCharts(t *testing.T) {
func TestLint_EmptyResultErrors(t *testing.T) { func TestLint_EmptyResultErrors(t *testing.T) {
testCharts := []string{chart2MultipleChartLint} testCharts := []string{chart2MultipleChartLint}
testLint := NewLint() testLint := NewLint()
if result := testLint.Run(testCharts, values, emptyLintIgnoreFilePath, debugLogFn); len(result.Errors) > 0 { if result := testLint.Run(testCharts, values, emptyLintConfigFilePath, debugLogFn); len(result.Errors) > 0 {
t.Error("Expected no error, got more") t.Error("Expected no error, got more")
} }
} }
@ -164,7 +164,7 @@ func TestLint_ChartWithWarnings(t *testing.T) {
testCharts := []string{chartWithNoTemplatesDir} testCharts := []string{chartWithNoTemplatesDir}
testLint := NewLint() testLint := NewLint()
testLint.Strict = false testLint.Strict = false
if result := testLint.Run(testCharts, values, emptyLintIgnoreFilePath, debugLogFn); len(result.Errors) > 0 { if result := testLint.Run(testCharts, values, emptyLintConfigFilePath, debugLogFn); len(result.Errors) > 0 {
t.Error("Expected no error, got more") t.Error("Expected no error, got more")
} }
}) })
@ -173,18 +173,18 @@ func TestLint_ChartWithWarnings(t *testing.T) {
testCharts := []string{chartWithNoTemplatesDir} testCharts := []string{chartWithNoTemplatesDir}
testLint := NewLint() testLint := NewLint()
testLint.Strict = true testLint.Strict = true
if result := testLint.Run(testCharts, values, emptyLintIgnoreFilePath, debugLogFn); len(result.Errors) != 0 { if result := testLint.Run(testCharts, values, emptyLintConfigFilePath, debugLogFn); len(result.Errors) != 0 {
t.Error("expected no errors, but got", len(result.Errors)) t.Error("expected no errors, but got", len(result.Errors))
} }
}) })
} }
func TestLint_MessyChartWithLintIgnoreFile(t *testing.T) { func TestLint_MessyChartWithLintConfigFile(t *testing.T) {
t.Run("should find no errors or messages using its own .helmlintignore file", func(t *testing.T) { t.Run("should find no errors or messages using its own .helmlintconfig file", func(t *testing.T) {
testCharts := []string{messyChartWithLintIgnore} testCharts := []string{messyChartWithLintIgnore}
testLint := NewLint() testLint := NewLint()
testLint.Strict = false testLint.Strict = false
result := testLint.Run(testCharts, values, emptyLintIgnoreFilePath, debugLogFn) result := testLint.Run(testCharts, values, emptyLintConfigFilePath, debugLogFn)
if len(result.Errors) != 0 { if len(result.Errors) != 0 {
t.Error("expected no errors, but got", len(result.Errors)) t.Error("expected no errors, but got", len(result.Errors))
} }
@ -194,11 +194,11 @@ func TestLint_MessyChartWithLintIgnoreFile(t *testing.T) {
}) })
t.Run("should find all four errors when we feed it a fake lint ignore file path", func(t *testing.T) { t.Run("should find all four errors when we feed it a fake lint ignore file path", func(t *testing.T) {
fakeLintIgnoreFilePath := "some/file/might/exist/here" fakeLintConfigFilePath := "some/file/might/exist/here"
testCharts := []string{messyChartWithLintIgnore} testCharts := []string{messyChartWithLintIgnore}
testLint := NewLint() testLint := NewLint()
testLint.Strict = true testLint.Strict = true
result := testLint.Run(testCharts, values, fakeLintIgnoreFilePath, debugLogFn) result := testLint.Run(testCharts, values, fakeLintConfigFilePath, debugLogFn)
if len(result.Errors) != 2 { if len(result.Errors) != 2 {
t.Error("expected two errors, but got", len(result.Errors)) t.Error("expected two errors, but got", len(result.Errors))
} }

@ -47,6 +47,8 @@ const defaultBurstLimit = 100
// defaultQPS sets the default QPS value to 0 to use library defaults unless specified // defaultQPS sets the default QPS value to 0 to use library defaults unless specified
const defaultQPS = float32(0) const defaultQPS = float32(0)
const defaultLintConfigFile = string(".helmlintconfig.yaml")
// EnvSettings describes all of the environment settings. // EnvSettings describes all of the environment settings.
type EnvSettings struct { type EnvSettings struct {
namespace string namespace string
@ -88,6 +90,8 @@ type EnvSettings struct {
BurstLimit int BurstLimit int
// QPS is queries per second which may be used to avoid throttling. // QPS is queries per second which may be used to avoid throttling.
QPS float32 QPS float32
// Lint config file location
LintConfigFile string
} }
func New() *EnvSettings { func New() *EnvSettings {
@ -108,6 +112,7 @@ func New() *EnvSettings {
RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")), RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")),
BurstLimit: envIntOr("HELM_BURST_LIMIT", defaultBurstLimit), BurstLimit: envIntOr("HELM_BURST_LIMIT", defaultBurstLimit),
QPS: envFloat32Or("HELM_QPS", defaultQPS), QPS: envFloat32Or("HELM_QPS", defaultQPS),
LintConfigFile: envOr("HELM_LINT_CONFIG_FILE", defaultLintConfigFile),
} }
env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG")) env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG"))
@ -159,6 +164,7 @@ func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&s.RepositoryCache, "repository-cache", s.RepositoryCache, "path to the directory containing cached repository indexes") fs.StringVar(&s.RepositoryCache, "repository-cache", s.RepositoryCache, "path to the directory containing cached repository indexes")
fs.IntVar(&s.BurstLimit, "burst-limit", s.BurstLimit, "client-side default throttling limit") fs.IntVar(&s.BurstLimit, "burst-limit", s.BurstLimit, "client-side default throttling limit")
fs.Float32Var(&s.QPS, "qps", s.QPS, "queries per second used when communicating with the Kubernetes API, not including bursting") fs.Float32Var(&s.QPS, "qps", s.QPS, "queries per second used when communicating with the Kubernetes API, not including bursting")
fs.StringVar(&s.LintConfigFile, "lint-config-file", s.LintConfigFile, "path to .helmlintconfig.yaml file to specify ignore patterns")
} }
func envOr(name, def string) string { func envOr(name, def string) string {
@ -227,6 +233,7 @@ func (s *EnvSettings) EnvVars() map[string]string {
"HELM_MAX_HISTORY": strconv.Itoa(s.MaxHistory), "HELM_MAX_HISTORY": strconv.Itoa(s.MaxHistory),
"HELM_BURST_LIMIT": strconv.Itoa(s.BurstLimit), "HELM_BURST_LIMIT": strconv.Itoa(s.BurstLimit),
"HELM_QPS": strconv.FormatFloat(float64(s.QPS), 'f', 2, 32), "HELM_QPS": strconv.FormatFloat(float64(s.QPS), 'f', 2, 32),
"HELM_LINT_CONFIG_FILE": s.LintConfigFile,
// broken, these are populated from helm flags and not kubeconfig. // broken, these are populated from helm flags and not kubeconfig.
"HELM_KUBECONTEXT": s.KubeContext, "HELM_KUBECONTEXT": s.KubeContext,

@ -60,6 +60,7 @@ func TestEnvSettings(t *testing.T) {
kubeTLSServer string kubeTLSServer string
burstLimit int burstLimit int
qps float32 qps float32
lintConfigFile string
}{ }{
{ {
name: "defaults", name: "defaults",
@ -70,7 +71,7 @@ func TestEnvSettings(t *testing.T) {
}, },
{ {
name: "with flags set", name: "with flags set",
args: "--debug --namespace=myns --kube-as-user=poro --kube-as-group=admins --kube-as-group=teatime --kube-as-group=snackeaters --kube-ca-file=/tmp/ca.crt --burst-limit 100 --qps 50.12 --kube-insecure-skip-tls-verify=true --kube-tls-server-name=example.org", args: "--debug --namespace=myns --kube-as-user=poro --kube-as-group=admins --kube-as-group=teatime --kube-as-group=snackeaters --kube-ca-file=/tmp/ca.crt --burst-limit 100 --qps 50.12 --kube-insecure-skip-tls-verify=true --kube-tls-server-name=example.org --lint-config-file /tmp/.helmlintconfig.yaml",
ns: "myns", ns: "myns",
debug: true, debug: true,
maxhistory: defaultMaxHistory, maxhistory: defaultMaxHistory,
@ -81,10 +82,11 @@ func TestEnvSettings(t *testing.T) {
kubeCaFile: "/tmp/ca.crt", kubeCaFile: "/tmp/ca.crt",
kubeTLSServer: "example.org", kubeTLSServer: "example.org",
kubeInsecure: true, kubeInsecure: true,
lintConfigFile: "/tmp/.helmlintconfig.yaml",
}, },
{ {
name: "with envvars set", name: "with envvars set",
envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns", "HELM_KUBEASUSER": "pikachu", "HELM_KUBEASGROUPS": ",,,operators,snackeaters,partyanimals", "HELM_MAX_HISTORY": "5", "HELM_KUBECAFILE": "/tmp/ca.crt", "HELM_BURST_LIMIT": "150", "HELM_KUBEINSECURE_SKIP_TLS_VERIFY": "true", "HELM_KUBETLS_SERVER_NAME": "example.org", "HELM_QPS": "60.34"}, envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns", "HELM_KUBEASUSER": "pikachu", "HELM_KUBEASGROUPS": ",,,operators,snackeaters,partyanimals", "HELM_MAX_HISTORY": "5", "HELM_KUBECAFILE": "/tmp/ca.crt", "HELM_BURST_LIMIT": "150", "HELM_KUBEINSECURE_SKIP_TLS_VERIFY": "true", "HELM_KUBETLS_SERVER_NAME": "example.org", "HELM_QPS": "60.34", "HELM_LINT_CONFIG_FILE": "/tmp/.helmlintconfig.yaml"},
ns: "yourns", ns: "yourns",
maxhistory: 5, maxhistory: 5,
burstLimit: 150, burstLimit: 150,
@ -95,11 +97,12 @@ func TestEnvSettings(t *testing.T) {
kubeCaFile: "/tmp/ca.crt", kubeCaFile: "/tmp/ca.crt",
kubeTLSServer: "example.org", kubeTLSServer: "example.org",
kubeInsecure: true, kubeInsecure: true,
lintConfigFile: "/tmp/.helmlintconfig.yaml",
}, },
{ {
name: "with flags and envvars set", name: "with flags and envvars set",
args: "--debug --namespace=myns --kube-as-user=poro --kube-as-group=admins --kube-as-group=teatime --kube-as-group=snackeaters --kube-ca-file=/my/ca.crt --burst-limit 175 --qps 70 --kube-insecure-skip-tls-verify=true --kube-tls-server-name=example.org", args: "--debug --namespace=myns --kube-as-user=poro --kube-as-group=admins --kube-as-group=teatime --kube-as-group=snackeaters --kube-ca-file=/my/ca.crt --burst-limit 175 --qps 70 --kube-insecure-skip-tls-verify=true --kube-tls-server-name=example.org --lint-config-file /tmp/.helmlintconfig.yaml",
envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns", "HELM_KUBEASUSER": "pikachu", "HELM_KUBEASGROUPS": ",,,operators,snackeaters,partyanimals", "HELM_MAX_HISTORY": "5", "HELM_KUBECAFILE": "/tmp/ca.crt", "HELM_BURST_LIMIT": "200", "HELM_KUBEINSECURE_SKIP_TLS_VERIFY": "true", "HELM_KUBETLS_SERVER_NAME": "example.org", "HELM_QPS": "40"}, envvars: map[string]string{"HELM_DEBUG": "1", "HELM_NAMESPACE": "yourns", "HELM_KUBEASUSER": "pikachu", "HELM_KUBEASGROUPS": ",,,operators,snackeaters,partyanimals", "HELM_MAX_HISTORY": "5", "HELM_KUBECAFILE": "/tmp/ca.crt", "HELM_BURST_LIMIT": "200", "HELM_KUBEINSECURE_SKIP_TLS_VERIFY": "true", "HELM_KUBETLS_SERVER_NAME": "example.org", "HELM_QPS": "40", "HELM_LINT_CONFIG_FILE": "/tmp/.helmlintconfig.yaml"},
ns: "myns", ns: "myns",
debug: true, debug: true,
maxhistory: 5, maxhistory: 5,
@ -110,6 +113,7 @@ func TestEnvSettings(t *testing.T) {
kubeCaFile: "/my/ca.crt", kubeCaFile: "/my/ca.crt",
kubeTLSServer: "example.org", kubeTLSServer: "example.org",
kubeInsecure: true, kubeInsecure: true,
lintConfigFile: "/tmp/.helmlintconfig.yaml",
}, },
{ {
name: "invalid kubeconfig", name: "invalid kubeconfig",

@ -7,7 +7,7 @@ import (
) )
// DefaultIgnoreFileName is the name of the lint ignore file // DefaultIgnoreFileName is the name of the lint ignore file
const DefaultIgnoreFileName = ".helmlintignore" const DefaultIgnoreFileName = ".helmlintconfig.yaml"
var debugFn func(format string, v ...interface{}) var debugFn func(format string, v ...interface{})
@ -16,9 +16,9 @@ type Ignorer struct {
Matchers []MatchesErrors Matchers []MatchesErrors
} }
func NewIgnorer(chartPath string, lintIgnorePath string, debugLogFn func(string, ...interface{})) (*Ignorer, error) { func NewIgnorer(chartPath string, lintConfigPath string, debugLogFn func(string, ...interface{})) (*Ignorer, error) {
debugFn = debugLogFn debugFn = debugLogFn
matchers, err := LoadFromFilePath(chartPath, lintIgnorePath) matchers, err := LoadFromFilePath(chartPath, lintConfigPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }

Loading…
Cancel
Save