Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions pkg/fsx/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,12 @@ var heavyDirs = map[string]bool{
".vscode": true,
}

// allowedDirs are hidden directories that should be traversed despite starting with a dot.
var allowedDirs = map[string]bool{
".github": true,
".gitlab": true,
}

// WalkFiles walks the directory tree starting at root and returns a list of file paths.
// It is bounded by MaxFiles (defaults to DefaultMaxFiles) and skips hidden directories
// and known heavy directories like node_modules, vendor, etc.
Expand Down Expand Up @@ -176,12 +182,15 @@ func WalkFiles(ctx context.Context, root string, opts WalkFilesOptions) ([]strin

name := d.Name()

// Skip hidden files/directories (starting with .)
// Skip hidden files/directories (starting with .) except allowed dirs
if strings.HasPrefix(name, ".") && name != "." {
if d.IsDir() {
return fs.SkipDir
if !allowedDirs[name] {
return fs.SkipDir
}
} else {
return nil
}
return nil
}

// Skip known heavy directories
Expand Down
83 changes: 75 additions & 8 deletions pkg/fsx/walk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,41 +168,56 @@ func TestWalkFiles_HiddenDirectories(t *testing.T) {
// config
// .cache/
// data
// .github/
// workflows/
// ci.yaml
// src/
// main.go

dirs := []string{
filepath.Join(tmpDir, ".git"),
filepath.Join(tmpDir, ".cache"),
filepath.Join(tmpDir, ".github", "workflows"),
filepath.Join(tmpDir, "src"),
}
for _, d := range dirs {
require.NoError(t, os.MkdirAll(d, 0o755))
}

files := map[string]string{
filepath.Join(tmpDir, ".git", "config"): "[core]",
filepath.Join(tmpDir, ".cache", "data"): "cached",
filepath.Join(tmpDir, "src", "main.go"): "package main",
filepath.Join(tmpDir, ".git", "config"): "[core]",
filepath.Join(tmpDir, ".cache", "data"): "cached",
filepath.Join(tmpDir, ".github", "workflows", "ci.yaml"): "name: CI",
filepath.Join(tmpDir, "src", "main.go"): "package main",
}
for path, content := range files {
require.NoError(t, os.WriteFile(path, []byte(content), 0o644))
}

t.Run("skips hidden directories", func(t *testing.T) {
t.Run("skips most hidden directories but allows .github", func(t *testing.T) {
t.Parallel()

got, err := WalkFiles(t.Context(), tmpDir, WalkFilesOptions{})
require.NoError(t, err)

assert.Len(t, got, 1, "should only find src/main.go")
assert.Contains(t, got[0], "main.go")
// Should find src/main.go and .github/workflows/ci.yaml
assert.Len(t, got, 2, "should find src/main.go and .github/workflows/ci.yaml")

// Verify .github files are included
var foundGithub, foundMain bool
for _, f := range got {
assert.False(t, strings.HasPrefix(filepath.Base(f), "."))
assert.NotContains(t, f, ".git")
if strings.Contains(f, ".github") {
foundGithub = true
}
if strings.Contains(f, "main.go") {
foundMain = true
}
// These should still be excluded
assert.NotContains(t, f, ".git"+string(filepath.Separator))
assert.NotContains(t, f, ".cache")
}
assert.True(t, foundGithub, "should include .github files")
assert.True(t, foundMain, "should include src/main.go")
})
}

Expand Down Expand Up @@ -355,6 +370,58 @@ func TestWalkFiles_ContextCancellation(t *testing.T) {
})
}

func TestWalkFiles_AllowedHiddenDirectories(t *testing.T) {
t.Parallel()

tmpDir := t.TempDir()

// Create .github and .gitlab (allowed) with files
allowedDirs := []string{".github", ".gitlab"}
for _, dir := range allowedDirs {
dirPath := filepath.Join(tmpDir, dir)
require.NoError(t, os.MkdirAll(dirPath, 0o755))
filePath := filepath.Join(dirPath, "config.yaml")
require.NoError(t, os.WriteFile(filePath, []byte("content"), 0o644))
}

// Create other hidden directories that should be skipped
skippedDirs := []string{".hidden", ".circleci", ".husky", ".devcontainer"}
for _, dir := range skippedDirs {
dirPath := filepath.Join(tmpDir, dir)
require.NoError(t, os.MkdirAll(dirPath, 0o755))
require.NoError(t, os.WriteFile(filepath.Join(dirPath, "config.yaml"), []byte("content"), 0o644))
}

t.Run("includes only .github and .gitlab hidden directories", func(t *testing.T) {
t.Parallel()

got, err := WalkFiles(t.Context(), tmpDir, WalkFilesOptions{})
require.NoError(t, err)

// Should find files only in .github and .gitlab (2 files)
assert.Len(t, got, 2, "should find files only in .github and .gitlab")

// Verify .github and .gitlab are included
for _, dir := range allowedDirs {
found := false
for _, f := range got {
if strings.HasPrefix(f, dir+string(filepath.Separator)) {
found = true
break
}
}
assert.True(t, found, "should include files from %s", dir)
}

// Verify other hidden dirs are NOT included
for _, f := range got {
for _, dir := range skippedDirs {
assert.NotContains(t, f, dir, "should not include %s directory", dir)
}
}
})
}

func TestWalkFiles_EmptyDirectory(t *testing.T) {
t.Parallel()

Expand Down