Skip to content

Commit

Permalink
cmd: hide files excluded by .gitignore
Browse files Browse the repository at this point in the history
Fixes hmarr#14

This commit adds support for hiding files from output that have been excluded
by .gitignore and friends. I've implemented a few version of this and settled
on just `git ls-files` since it's likely going to be the most correct and
maintainable solution.

I've tried github.com/boyter/gocodewalker but it's a complex piece of machinery
and was much slower on a repo of 15k files (Cilium) than just git ls-files.
I also tried out github.com/ianlewis/go-gitignore directly, but it doesn't pick
up .gitignore files in subdirs automatically, nor the system-wide gitignore.

I figured since the overwhelming majority of users will be running this in CI
where Git will always be present, relying on the canonical .gitignore
implementation (git itself) is the safest option.

Signed-off-by: Timo Beckers <[email protected]>
  • Loading branch information
ti-mo committed Jul 24, 2024
1 parent 23678ff commit c59230f
Showing 1 changed file with 33 additions and 0 deletions.
33 changes: 33 additions & 0 deletions cmd/codeowners/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"

Expand Down Expand Up @@ -55,6 +56,8 @@ func main() {
defer out.Flush()

for _, startPath := range paths {
files := gitFiles(startPath)

err = filepath.WalkDir(startPath, func(path string, d os.DirEntry, err error) error {
if d.IsDir() {
if path == ".git" {
Expand All @@ -65,6 +68,14 @@ func main() {
return nil
}

if files != nil {
// Skip displaying code owners for files that are not managed by git,
// e.g. untracked files or files excluded by .gitignore.
if _, ok := files[path]; !ok {
return nil
}
}

return printFileOwners(out, ruleset, path, ownerFilters, showUnowned)
})

Expand Down Expand Up @@ -117,3 +128,25 @@ func loadCodeowners(path string) (codeowners.Ruleset, error) {
}
return codeowners.LoadFile(path)
}

// gitFiles returns a map of files in the git repository at the given path.
// Notably, this omits files that have been excluded by .gitignore,
// .git/info/exclude and system-wide gitignore. See
// https://git-scm.com/docs/gitignore for more details.
//
// Returns nil if anything goes wrong, such as the path not being a git repo or
// git not being installed.
func gitFiles(path string) map[string]struct{} {
cmd := exec.Command("git", "ls-files", "-z", "--", path)
out, err := cmd.Output()
if err != nil {
return nil
}

files := make(map[string]struct{})
for _, file := range strings.Split(string(out), "\x00") {
files[file] = struct{}{}
}

return files
}

0 comments on commit c59230f

Please sign in to comment.