diff --git a/internal/chart/v3/lint/rules/template.go b/internal/chart/v3/lint/rules/template.go index 4b2bce927..21658c5a3 100644 --- a/internal/chart/v3/lint/rules/template.go +++ b/internal/chart/v3/lint/rules/template.go @@ -123,6 +123,11 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string fileName := template.Name fpath = fileName + // skip the linting rules if the file starts with _ and is not a yml/yaml file + if isHelperFile(fileName) { + continue + } + linter.RunLinterRule(support.ErrorSev, fpath, validateAllowedExtension(fileName)) // We only apply the following lint rules to yaml files @@ -219,14 +224,19 @@ func validateTemplatesDir(templatesPath string) error { return nil } -func validateAllowedExtension(fileName string) error { +// checks if the file starts with '_'. +func isHelperFile(fileName string) bool { baseName := filepath.Base(fileName) + ext := filepath.Ext(fileName) - if strings.HasPrefix(baseName, "_") { - fmt.Println("skipping _ files") - return nil + if strings.HasPrefix(baseName, "_") && ext != ".yaml" && ext != ".yml" { + return true } + return false +} + +func validateAllowedExtension(fileName string) error { ext := filepath.Ext(fileName) validExtensions := []string{".yaml", ".yml", ".tpl", ".txt"} diff --git a/internal/chart/v3/lint/rules/template_test.go b/internal/chart/v3/lint/rules/template_test.go index 598ccf1e6..0d42be968 100644 --- a/internal/chart/v3/lint/rules/template_test.go +++ b/internal/chart/v3/lint/rules/template_test.go @@ -32,14 +32,14 @@ import ( const templateTestBasedir = "./testdata/albatross" func TestValidateAllowedExtension(t *testing.T) { - var failTest = []string{"/foo", "/test.toml", "regular.json"} + var failTest = []string{"/foo", "/test.toml"} for _, test := range failTest { err := validateAllowedExtension(test) if err == nil || !strings.Contains(err.Error(), "Valid extensions are .yaml, .yml, .tpl, or .txt") { t.Errorf("validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) } } - var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt", "_envoy.json"} + var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} for _, test := range successTest { err := validateAllowedExtension(test) if err != nil { @@ -401,6 +401,7 @@ func TestEmptyWithCommentsManifests(t *testing.T) { t.Fatalf("Expected 0 lint errors, got %d", l) } } + func TestValidateListAnnotations(t *testing.T) { md := &k8sYamlStruct{ APIVersion: "v1", @@ -439,3 +440,35 @@ items: t.Fatalf("List objects keep annotations should pass. got: %s", err) } } + +func TestIsHelperFile(t *testing.T) { + tests := []struct { + fileName string + expected bool + }{ + // Should return true (helper files, non-yaml/yml) + {"_helpers.go", true}, + {"_helpers.json", true}, + {"subdir/_helpers.json", true}, + {"subdir/_partial.tpl", true}, + {"_config.txt", true}, + + // Should return false (yaml/yml files, even with _) + {"_helpers.yaml", false}, + {"_config.yml", false}, + {"subdir/_partial.yaml", false}, + + // Should return false (regular files without _) + {"helpers.go", false}, + {"config.json", false}, + {"deployment.yaml", false}, + } + for _, tt := range tests { + t.Run(tt.fileName, func(t *testing.T) { + result := isHelperFile(tt.fileName) + if result != tt.expected { + t.Errorf("isHelperFile(%q) = %v, expected %v", tt.fileName, result, tt.expected) + } + }) + } +} diff --git a/pkg/chart/v2/lint/rules/template.go b/pkg/chart/v2/lint/rules/template.go index 3006d8af8..3f567136e 100644 --- a/pkg/chart/v2/lint/rules/template.go +++ b/pkg/chart/v2/lint/rules/template.go @@ -123,6 +123,11 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string fileName := template.Name fpath = fileName + // skip the linting rules if the file starts with _ and is not a yaml/yml file + if isHelperFile(fileName) { + continue + } + linter.RunLinterRule(support.ErrorSev, fpath, validateAllowedExtension(fileName)) // We only apply the following lint rules to yaml files @@ -219,13 +224,19 @@ func validateTemplatesDir(templatesPath string) error { return nil } -func validateAllowedExtension(fileName string) error { +// checks if the file starts with '_'. +func isHelperFile(fileName string) bool { baseName := filepath.Base(fileName) + ext := filepath.Ext(fileName) - if strings.HasPrefix(baseName, "_") { - return nil + if strings.HasPrefix(baseName, "_") && ext != ".yaml" && ext != ".yml" { + return true } + return false +} + +func validateAllowedExtension(fileName string) error { ext := filepath.Ext(fileName) validExtensions := []string{".yaml", ".yml", ".tpl", ".txt"} diff --git a/pkg/chart/v2/lint/rules/template_test.go b/pkg/chart/v2/lint/rules/template_test.go index 9ad66800a..41b396838 100644 --- a/pkg/chart/v2/lint/rules/template_test.go +++ b/pkg/chart/v2/lint/rules/template_test.go @@ -32,14 +32,14 @@ import ( const templateTestBasedir = "./testdata/albatross" func TestValidateAllowedExtension(t *testing.T) { - var failTest = []string{"/foo", "/test.toml", "regular.json"} + var failTest = []string{"/foo", "/test.toml"} for _, test := range failTest { err := validateAllowedExtension(test) if err == nil || !strings.Contains(err.Error(), "Valid extensions are .yaml, .yml, .tpl, or .txt") { t.Errorf("validateAllowedExtension('%s') to return \"Valid extensions are .yaml, .yml, .tpl, or .txt\", got no error", test) } } - var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt", "_regular.json"} + var successTest = []string{"/foo.yaml", "foo.yaml", "foo.tpl", "/foo/bar/baz.yaml", "NOTES.txt"} for _, test := range successTest { err := validateAllowedExtension(test) if err != nil { @@ -439,3 +439,35 @@ items: t.Fatalf("List objects keep annotations should pass. got: %s", err) } } + +func TestIsHelperFile(t *testing.T) { + tests := []struct { + fileName string + expected bool + }{ + // Should return true (helper files, non-yaml/yml) + {"_helpers.go", true}, + {"_helpers.json", true}, + {"subdir/_helpers.json", true}, + {"subdir/_partial.tpl", true}, + {"_config.txt", true}, + + // Should return false (yaml/yml files, even with _) + {"_helpers.yaml", false}, + {"_config.yml", false}, + {"subdir/_partial.yaml", false}, + + // Should return false (regular files without _) + {"helpers.go", false}, + {"config.json", false}, + {"deployment.yaml", false}, + } + for _, tt := range tests { + t.Run(tt.fileName, func(t *testing.T) { + result := isHelperFile(tt.fileName) + if result != tt.expected { + t.Errorf("isHelperFile(%q) = %v, expected %v", tt.fileName, result, tt.expected) + } + }) + } +}