@@ -56,6 +56,46 @@ func isHiddenPath(path string) bool {
5656 return false
5757}
5858
59+ // patternTargetsHiddenPath checks if a user pattern explicitly targets a hidden path.
60+ // Returns true if the pattern starts with or contains a hidden directory component.
61+ // Examples:
62+ // - "./.git/**" -> true (explicitly targets .git)
63+ // - "/tmp/test/.git/**" -> true (explicitly targets .git)
64+ // - "./.github/workflows/**" -> true (explicitly targets .github)
65+ // - "./**" -> false (broad pattern, not targeting hidden)
66+ // - "./charts/**" -> false (normal path)
67+ func patternTargetsHiddenPath (pattern string ) bool {
68+ // Clean and normalize the pattern
69+ cleanPattern := filepath .Clean (pattern )
70+ cleanPattern = filepath .ToSlash (cleanPattern )
71+
72+ // Remove leading "./" for easier parsing (handles relative paths)
73+ cleanPattern = strings .TrimPrefix (cleanPattern , "./" )
74+
75+ // Split into parts
76+ parts := strings .Split (cleanPattern , "/" )
77+
78+ // Check if any non-wildcard part is a hidden directory
79+ for _ , part := range parts {
80+ // Skip wildcards
81+ if part == "*" || part == "**" {
82+ continue
83+ }
84+
85+ // Skip empty parts (from double slashes or leading slash)
86+ if part == "" {
87+ continue
88+ }
89+
90+ // Check if this part is a hidden directory
91+ if strings .HasPrefix (part , "." ) && part != "." && part != ".." {
92+ return true
93+ }
94+ }
95+
96+ return false
97+ }
98+
5999// isChartDirectory checks if a directory contains a Chart.yaml or Chart.yml file.
60100// Returns true if the directory is a valid Helm chart directory.
61101func isChartDirectory (dirPath string ) (bool , error ) {
@@ -225,19 +265,29 @@ func validateExplicitYAMLFile(path, kind, resourceName string) ([]string, error)
225265
226266// filterYAMLFilesByKind expands glob patterns and filters to files with matching kind.
227267// Silently skips files that can't be read or don't have the target kind.
228- func filterYAMLFilesByKind (patterns []string , originalPattern , kind string ) ([]string , error ) {
268+ // Optionally filters by gitignore if checker is provided.
269+ // Optionally skips hidden paths unless skipHidden is false (explicit bypass).
270+ func filterYAMLFilesByKind (patterns []string , originalPattern , kind string , gitignoreChecker * GitignoreChecker , skipHidden bool ) ([]string , error ) {
229271 var resultPaths []string
230272 seenPaths := make (map [string ]bool )
231273
232274 for _ , p := range patterns {
233- matches , err := GlobFiles (p )
275+ // Use gitignore filtering if checker provided
276+ var matches []string
277+ var err error
278+ if gitignoreChecker != nil {
279+ matches , err = GlobFiles (p , WithGitignoreChecker (gitignoreChecker ))
280+ } else {
281+ matches , err = GlobFiles (p )
282+ }
234283 if err != nil {
235284 return nil , fmt .Errorf ("expanding pattern %s: %w (from user pattern: %s)" , p , err , originalPattern )
236285 }
237286
238287 for _ , path := range matches {
239- // Skip hidden paths
240- if isHiddenPath (path ) {
288+ // Skip hidden paths (.git, .github, .vscode, etc.) by default
289+ // But allow bypass if user explicitly specified a hidden path pattern
290+ if skipHidden && isHiddenPath (path ) {
241291 continue
242292 }
243293
@@ -265,6 +315,7 @@ func filterYAMLFilesByKind(patterns []string, originalPattern, kind string) ([]s
265315
266316// discoverYAMLsByKind discovers YAML files containing a specific kind from a pattern.
267317// Handles both explicit file paths (strict validation) and glob patterns (lenient filtering).
318+ // Respects gitignore unless the pattern explicitly references a gitignored path.
268319//
269320// For explicit paths:
270321// - Validates file exists, is a file, has .yaml/.yml extension
@@ -275,6 +326,7 @@ func filterYAMLFilesByKind(patterns []string, originalPattern, kind string) ([]s
275326// - Expands pattern to find all YAML files
276327// - Filters to only files containing the specified kind
277328// - Silently skips files that don't match (allows mixed directories)
329+ // - Respects gitignore unless pattern explicitly includes gitignored path
278330func discoverYAMLsByKind (pattern , kind , resourceName string ) ([]string , error ) {
279331 // Validate empty pattern
280332 if pattern == "" {
@@ -295,14 +347,31 @@ func discoverYAMLsByKind(pattern, kind, resourceName string) ([]string, error) {
295347 return validateExplicitYAMLFile (pattern , kind , resourceName )
296348 }
297349
350+ // Create gitignore checker (returns nil if not in git repo or no gitignore)
351+ gitignoreChecker , _ := NewGitignoreChecker ("." )
352+
353+ // Check if pattern explicitly bypasses gitignore
354+ var checkerToUse * GitignoreChecker
355+ if gitignoreChecker != nil && gitignoreChecker .PathMatchesIgnoredPattern (pattern ) {
356+ // Pattern explicitly references gitignored path - bypass gitignore
357+ checkerToUse = nil
358+ } else {
359+ // Use gitignore filtering
360+ checkerToUse = gitignoreChecker
361+ }
362+
363+ // Check if pattern explicitly targets hidden paths
364+ // If yes, allow bypass of hidden path filtering (like gitignore bypass)
365+ skipHidden := ! patternTargetsHiddenPath (pattern )
366+
298367 // Glob pattern - build search patterns
299368 patterns , err := buildYAMLPatterns (pattern )
300369 if err != nil {
301370 return nil , err
302371 }
303372
304373 // Lenient filtering
305- return filterYAMLFilesByKind (patterns , originalPattern , kind )
374+ return filterYAMLFilesByKind (patterns , originalPattern , kind , checkerToUse , skipHidden )
306375}
307376
308377// validateExplicitChartDir validates an explicit directory path for chart discovery.
@@ -335,23 +404,34 @@ func validateExplicitChartDir(path string) ([]string, error) {
335404
336405// filterDirsByMarkerFile expands glob patterns to find marker files and returns their parent directories.
337406// Silently skips hidden paths and deduplicates results.
338- func filterDirsByMarkerFile (patterns []string , originalPattern string ) ([]string , error ) {
407+ // Optionally filters by gitignore if checker is provided.
408+ // Optionally skips hidden paths unless skipHidden is false (explicit bypass).
409+ func filterDirsByMarkerFile (patterns []string , originalPattern string , gitignoreChecker * GitignoreChecker , skipHidden bool ) ([]string , error ) {
339410 var chartDirs []string
340411 seenDirs := make (map [string ]bool )
341412
342413 for _ , p := range patterns {
343- matches , err := GlobFiles (p )
414+ // Use gitignore filtering if checker provided
415+ var matches []string
416+ var err error
417+ if gitignoreChecker != nil {
418+ matches , err = GlobFiles (p , WithGitignoreChecker (gitignoreChecker ))
419+ } else {
420+ matches , err = GlobFiles (p )
421+ }
344422 if err != nil {
345423 return nil , fmt .Errorf ("expanding pattern %s: %w (from user pattern: %s)" , p , err , originalPattern )
346424 }
347425
348426 for _ , markerPath := range matches {
349- chartDir := filepath . Dir ( markerPath )
350-
351- if isHiddenPath (chartDir ) {
427+ // Skip hidden paths (.git, .github, .vscode, etc.) by default
428+ // But allow bypass if user explicitly specified a hidden path pattern
429+ if skipHidden && isHiddenPath (markerPath ) {
352430 continue
353431 }
354432
433+ chartDir := filepath .Dir (markerPath )
434+
355435 if seenDirs [chartDir ] {
356436 continue
357437 }
@@ -366,6 +446,7 @@ func filterDirsByMarkerFile(patterns []string, originalPattern string) ([]string
366446
367447// discoverDirsByMarkerFile discovers directories containing specific marker files.
368448// Handles both explicit directory paths (strict validation) and glob patterns (lenient filtering).
449+ // Respects gitignore unless the pattern explicitly references a gitignored path.
369450//
370451// For explicit paths:
371452// - Validates path exists and is a directory
@@ -376,6 +457,7 @@ func filterDirsByMarkerFile(patterns []string, originalPattern string) ([]string
376457// - Expands pattern to find marker files
377458// - Returns parent directories of found markers
378459// - Silently skips paths that don't match
460+ // - Respects gitignore unless pattern explicitly includes gitignored path
379461func discoverDirsByMarkerFile (pattern string , markerFiles []string , resourceName string ) ([]string , error ) {
380462 if pattern == "" {
381463 return nil , fmt .Errorf ("pattern cannot be empty" )
@@ -392,6 +474,23 @@ func discoverDirsByMarkerFile(pattern string, markerFiles []string, resourceName
392474 return validateExplicitChartDir (pattern )
393475 }
394476
477+ // Create gitignore checker (returns nil if not in git repo or no gitignore)
478+ gitignoreChecker , _ := NewGitignoreChecker ("." )
479+
480+ // Check if pattern explicitly bypasses gitignore
481+ var checkerToUse * GitignoreChecker
482+ if gitignoreChecker != nil && gitignoreChecker .PathMatchesIgnoredPattern (pattern ) {
483+ // Pattern explicitly references gitignored path - bypass gitignore
484+ checkerToUse = nil
485+ } else {
486+ // Use gitignore filtering
487+ checkerToUse = gitignoreChecker
488+ }
489+
490+ // Check if pattern explicitly targets hidden paths
491+ // If yes, allow bypass of hidden path filtering (like gitignore bypass)
492+ skipHidden := ! patternTargetsHiddenPath (pattern )
493+
395494 // Build patterns for marker files
396495 var patterns []string
397496 if strings .HasSuffix (pattern , markerFiles [0 ]) || (len (markerFiles ) > 1 && strings .HasSuffix (pattern , markerFiles [1 ])) {
@@ -406,7 +505,7 @@ func discoverDirsByMarkerFile(pattern string, markerFiles []string, resourceName
406505 }
407506
408507 // Filter to directories containing marker files
409- return filterDirsByMarkerFile (patterns , originalPattern )
508+ return filterDirsByMarkerFile (patterns , originalPattern , checkerToUse , skipHidden )
410509}
411510
412511// discoverSupportBundlePaths discovers Support Bundle spec files from a glob pattern.
0 commit comments