From efcb5735e5cba163dd4acfb1a3489bff1b70f49a Mon Sep 17 00:00:00 2001 From: George Jenkins Date: Mon, 31 Mar 2025 09:09:51 -0700 Subject: [PATCH] cleanup: Remove extra lint/rules.Template functions Signed-off-by: George Jenkins --- pkg/chart/v2/lint/lint.go | 7 +- pkg/chart/v2/lint/rules/template.go | 91 ++++++++++++++++-------- pkg/chart/v2/lint/rules/template_test.go | 37 ++++++++-- 3 files changed, 97 insertions(+), 38 deletions(-) diff --git a/pkg/chart/v2/lint/lint.go b/pkg/chart/v2/lint/lint.go index b26d65a34..1c871d936 100644 --- a/pkg/chart/v2/lint/lint.go +++ b/pkg/chart/v2/lint/lint.go @@ -58,7 +58,12 @@ func RunAll(baseDir string, values map[string]interface{}, namespace string, opt rules.Chartfile(&result) rules.ValuesWithOverrides(&result, values, lo.SkipSchemaValidation) - rules.TemplatesWithSkipSchemaValidation(&result, values, namespace, lo.KubeVersion, lo.SkipSchemaValidation) + rules.Templates( + &result, + namespace, + values, + rules.TemplateLinterKubeVersion(lo.KubeVersion), + rules.TemplateLinterSkipSchemaValidation(lo.SkipSchemaValidation)) rules.Dependencies(&result) rules.Crds(&result) diff --git a/pkg/chart/v2/lint/rules/template.go b/pkg/chart/v2/lint/rules/template.go index 5c84d0f68..b21050a9e 100644 --- a/pkg/chart/v2/lint/rules/template.go +++ b/pkg/chart/v2/lint/rules/template.go @@ -42,35 +42,66 @@ import ( ) // Templates lints the templates in the Linter. -func Templates(linter *support.Linter, values map[string]interface{}, namespace string, _ bool) { - TemplatesWithKubeVersion(linter, values, namespace, nil) +func Templates(linter *support.Linter, namespace string, values map[string]any, options ...TemplateLinterOption) { + templateLinter := newTemplateLinter(linter, namespace, values, options...) + templateLinter.Lint() } -// TemplatesWithKubeVersion lints the templates in the Linter, allowing to specify the kubernetes version. -func TemplatesWithKubeVersion(linter *support.Linter, values map[string]interface{}, namespace string, kubeVersion *common.KubeVersion) { - TemplatesWithSkipSchemaValidation(linter, values, namespace, kubeVersion, false) +type TemplateLinterOption func(*templateLinter) + +func TemplateLinterKubeVersion(kubeVersion *common.KubeVersion) TemplateLinterOption { + return func(tl *templateLinter) { + tl.kubeVersion = kubeVersion + } +} + +func TemplateLinterSkipSchemaValidation(skipSchemaValidation bool) TemplateLinterOption { + return func(tl *templateLinter) { + tl.skipSchemaValidation = skipSchemaValidation + } } -// TemplatesWithSkipSchemaValidation lints the templates in the Linter, allowing to specify the kubernetes version and if schema validation is enabled or not. -func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string]interface{}, namespace string, kubeVersion *common.KubeVersion, skipSchemaValidation bool) { - fpath := "templates/" - templatesPath := filepath.Join(linter.ChartDir, fpath) +func newTemplateLinter(linter *support.Linter, namespace string, values map[string]any, options ...TemplateLinterOption) templateLinter { + + result := templateLinter{ + linter: linter, + values: values, + namespace: namespace, + } - // Templates directory is optional for now - templatesDirExists := linter.RunLinterRule(support.WarningSev, fpath, templatesDirExists(templatesPath)) + for _, o := range options { + o(&result) + } + + return result +} + +type templateLinter struct { + linter *support.Linter + values map[string]any + namespace string + kubeVersion *common.KubeVersion + skipSchemaValidation bool +} + +func (t *templateLinter) Lint() { + templatesDir := "templates/" + templatesPath := filepath.Join(t.linter.ChartDir, templatesDir) + + templatesDirExists := t.linter.RunLinterRule(support.WarningSev, templatesDir, templatesDirExists(templatesPath)) if !templatesDirExists { return } - validTemplatesDir := linter.RunLinterRule(support.ErrorSev, fpath, validateTemplatesDir(templatesPath)) + validTemplatesDir := t.linter.RunLinterRule(support.ErrorSev, templatesDir, validateTemplatesDir(templatesPath)) if !validTemplatesDir { return } // Load chart and parse templates - chart, err := loader.Load(linter.ChartDir) + chart, err := loader.Load(t.linter.ChartDir) - chartLoaded := linter.RunLinterRule(support.ErrorSev, fpath, err) + chartLoaded := t.linter.RunLinterRule(support.ErrorSev, templatesDir, err) if !chartLoaded { return @@ -78,35 +109,35 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string options := common.ReleaseOptions{ Name: "test-release", - Namespace: namespace, + Namespace: t.namespace, } caps := common.DefaultCapabilities.Copy() - if kubeVersion != nil { - caps.KubeVersion = *kubeVersion + if t.kubeVersion != nil { + caps.KubeVersion = *t.kubeVersion } // lint ignores import-values // See https://github.com/helm/helm/issues/9658 - if err := chartutil.ProcessDependencies(chart, values); err != nil { + if err := chartutil.ProcessDependencies(chart, t.values); err != nil { return } - cvals, err := util.CoalesceValues(chart, values) + cvals, err := util.CoalesceValues(chart, t.values) if err != nil { return } - valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, skipSchemaValidation) + valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, t.skipSchemaValidation) if err != nil { - linter.RunLinterRule(support.ErrorSev, fpath, err) + t.linter.RunLinterRule(support.ErrorSev, templatesDir, err) return } var e engine.Engine e.LintMode = true renderedContentMap, err := e.Render(chart, valuesToRender) - renderOk := linter.RunLinterRule(support.ErrorSev, fpath, err) + renderOk := t.linter.RunLinterRule(support.ErrorSev, templatesDir, err) if !renderOk { return @@ -121,9 +152,8 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string */ for _, template := range chart.Templates { fileName := template.Name - fpath = fileName - linter.RunLinterRule(support.ErrorSev, fpath, validateAllowedExtension(fileName)) + t.linter.RunLinterRule(support.ErrorSev, fileName, validateAllowedExtension(fileName)) // We only apply the following lint rules to yaml files if filepath.Ext(fileName) != ".yaml" || filepath.Ext(fileName) == ".yml" { @@ -139,7 +169,7 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string renderedContent := renderedContentMap[path.Join(chart.Name(), fileName)] if strings.TrimSpace(renderedContent) != "" { - linter.RunLinterRule(support.WarningSev, fpath, validateTopIndentLevel(renderedContent)) + t.linter.RunLinterRule(support.WarningSev, fileName, validateTopIndentLevel(renderedContent)) decoder := yaml.NewYAMLOrJSONDecoder(strings.NewReader(renderedContent), 4096) @@ -156,17 +186,17 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string // If YAML linting fails here, it will always fail in the next block as well, so we should return here. // fix https://github.com/helm/helm/issues/11391 - if !linter.RunLinterRule(support.ErrorSev, fpath, validateYamlContent(err)) { + if !t.linter.RunLinterRule(support.ErrorSev, fileName, validateYamlContent(err)) { return } if yamlStruct != nil { // NOTE: set to warnings to allow users to support out-of-date kubernetes // Refs https://github.com/helm/helm/issues/8596 - linter.RunLinterRule(support.WarningSev, fpath, validateMetadataName(yamlStruct)) - linter.RunLinterRule(support.WarningSev, fpath, validateNoDeprecations(yamlStruct, kubeVersion)) + t.linter.RunLinterRule(support.WarningSev, fileName, validateMetadataName(yamlStruct)) + t.linter.RunLinterRule(support.WarningSev, fileName, validateNoDeprecations(yamlStruct, t.kubeVersion)) - linter.RunLinterRule(support.ErrorSev, fpath, validateMatchSelector(yamlStruct, renderedContent)) - linter.RunLinterRule(support.ErrorSev, fpath, validateListAnnotations(yamlStruct, renderedContent)) + t.linter.RunLinterRule(support.ErrorSev, fileName, validateMatchSelector(yamlStruct, renderedContent)) + t.linter.RunLinterRule(support.ErrorSev, fileName, validateListAnnotations(yamlStruct, renderedContent)) } } } @@ -234,6 +264,7 @@ func validateYamlContent(err error) error { if err != nil { return fmt.Errorf("unable to parse YAML: %w", err) } + return nil } diff --git a/pkg/chart/v2/lint/rules/template_test.go b/pkg/chart/v2/lint/rules/template_test.go index 3e8e0b371..7629d3de5 100644 --- a/pkg/chart/v2/lint/rules/template_test.go +++ b/pkg/chart/v2/lint/rules/template_test.go @@ -51,11 +51,14 @@ func TestValidateAllowedExtension(t *testing.T) { var values = map[string]interface{}{"nameOverride": "", "httpPort": 80} const namespace = "testNamespace" -const strict = false func TestTemplateParsing(t *testing.T) { linter := support.Linter{ChartDir: templateTestBasedir} - Templates(&linter, values, namespace, strict) + Templates( + &linter, + namespace, + values, + TemplateLinterSkipSchemaValidation(false)) res := linter.Messages if len(res) != 1 { @@ -78,7 +81,11 @@ func TestTemplateIntegrationHappyPath(t *testing.T) { defer os.Rename(ignoredTemplatePath, wrongTemplatePath) linter := support.Linter{ChartDir: templateTestBasedir} - Templates(&linter, values, namespace, strict) + Templates( + &linter, + namespace, + values, + TemplateLinterSkipSchemaValidation(false)) res := linter.Messages if len(res) != 0 { @@ -88,7 +95,11 @@ func TestTemplateIntegrationHappyPath(t *testing.T) { func TestMultiTemplateFail(t *testing.T) { linter := support.Linter{ChartDir: "./testdata/multi-template-fail"} - Templates(&linter, values, namespace, strict) + Templates( + &linter, + namespace, + values, + TemplateLinterSkipSchemaValidation(false)) res := linter.Messages if len(res) != 1 { @@ -208,7 +219,11 @@ func TestDeprecatedAPIFails(t *testing.T) { } linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} - Templates(&linter, values, namespace, strict) + Templates( + &linter, + namespace, + values, + TemplateLinterSkipSchemaValidation(false)) if l := len(linter.Messages); l != 1 { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg) @@ -264,7 +279,11 @@ func TestStrictTemplateParsingMapError(t *testing.T) { linter := &support.Linter{ ChartDir: filepath.Join(dir, ch.Metadata.Name), } - Templates(linter, ch.Values, namespace, strict) + Templates( + linter, + namespace, + ch.Values, + TemplateLinterSkipSchemaValidation(false)) if len(linter.Messages) != 0 { t.Errorf("expected zero messages, got %d", len(linter.Messages)) for i, msg := range linter.Messages { @@ -393,7 +412,11 @@ func TestEmptyWithCommentsManifests(t *testing.T) { } linter := support.Linter{ChartDir: filepath.Join(tmpdir, mychart.Name())} - Templates(&linter, values, namespace, strict) + Templates( + &linter, + namespace, + values, + TemplateLinterSkipSchemaValidation(false)) if l := len(linter.Messages); l > 0 { for i, msg := range linter.Messages { t.Logf("Message %d: %s", i, msg)