From 576c2160b7acc71f2cfbb31472f3fb7a4acbe6d6 Mon Sep 17 00:00:00 2001 From: Louis Williams Date: Thu, 6 Feb 2025 18:55:11 -0500 Subject: [PATCH 1/3] Support for only including files tracked by git --- cmd/codeowners/main.go | 43 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/cmd/codeowners/main.go b/cmd/codeowners/main.go index 8a9e7e1..f866958 100644 --- a/cmd/codeowners/main.go +++ b/cmd/codeowners/main.go @@ -2,9 +2,11 @@ package main import ( "bufio" + "bytes" "fmt" "io" "os" + "os/exec" "path/filepath" "strings" @@ -17,11 +19,13 @@ func main() { ownerFilters []string showUnowned bool codeownersPath string + trackedFlag bool helpFlag bool ) flag.StringSliceVarP(&ownerFilters, "owner", "o", nil, "filter results by owner") flag.BoolVarP(&showUnowned, "unowned", "u", false, "only show unowned files (can be combined with -o)") flag.StringVarP(&codeownersPath, "file", "f", "", "CODEOWNERS file path") + flag.BoolVarP(&trackedFlag, "tracked", "t", false, "only show files tracked by git") flag.BoolVarP(&helpFlag, "help", "h", false, "show this help message") flag.Usage = func() { @@ -35,6 +39,33 @@ func main() { os.Exit(0) } + var trackedFiles map[string]bool + if trackedFlag { + // Ensure the script is run inside a Git repository + if _, err := os.Stat(".git"); os.IsNotExist(err) { + fmt.Println(os.Stderr, "error: this is not a Git repository.") + os.Exit(1) + } + + cmd := exec.Command("git", "ls-files") + var out bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + fmt.Println(os.Stderr, "Error running git ls-files:", err) + os.Exit(1) + } + + trackedFiles = make(map[string]bool) + files := strings.Split(out.String(), "\n") + for _, file := range files { + if file != "" { + trackedFiles[file] = true + } + } + } + ruleset, err := loadCodeowners(codeownersPath) if err != nil { fmt.Fprintln(os.Stderr, err) @@ -57,7 +88,7 @@ func main() { for _, startPath := range paths { // godirwalk only accepts directories, so we need to handle files separately if !isDir(startPath) { - if err := printFileOwners(out, ruleset, startPath, ownerFilters, showUnowned); err != nil { + if err := printFileOwners(out, ruleset, startPath, ownerFilters, showUnowned, trackedFiles, trackedFlag); err != nil { fmt.Fprintf(os.Stderr, "error: %v", err) os.Exit(1) } @@ -71,7 +102,7 @@ func main() { // Only show code owners for files, not directories if !d.IsDir() { - return printFileOwners(out, ruleset, path, ownerFilters, showUnowned) + return printFileOwners(out, ruleset, path, ownerFilters, showUnowned, trackedFiles, trackedFlag) } return nil }) @@ -83,7 +114,13 @@ func main() { } } -func printFileOwners(out io.Writer, ruleset codeowners.Ruleset, path string, ownerFilters []string, showUnowned bool) error { +func printFileOwners(out io.Writer, ruleset codeowners.Ruleset, path string, ownerFilters []string, showUnowned bool, trackedFiles map[string]bool, trackedOnly bool) error { + if trackedOnly { + if _, ok := trackedFiles[path]; !ok { + return nil + } + } + rule, err := ruleset.Match(path) if err != nil { return err From 5ef61505675bb19690d0eb766706b29891ac8d63 Mon Sep 17 00:00:00 2001 From: Louis Williams Date: Fri, 9 May 2025 10:30:21 -0500 Subject: [PATCH 2/3] Clean up, fix bugs --- cmd/codeowners/main.go | 76 ++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/cmd/codeowners/main.go b/cmd/codeowners/main.go index f866958..9a955b2 100644 --- a/cmd/codeowners/main.go +++ b/cmd/codeowners/main.go @@ -19,13 +19,13 @@ func main() { ownerFilters []string showUnowned bool codeownersPath string - trackedFlag bool + trackedOnly bool helpFlag bool ) flag.StringSliceVarP(&ownerFilters, "owner", "o", nil, "filter results by owner") flag.BoolVarP(&showUnowned, "unowned", "u", false, "only show unowned files (can be combined with -o)") flag.StringVarP(&codeownersPath, "file", "f", "", "CODEOWNERS file path") - flag.BoolVarP(&trackedFlag, "tracked", "t", false, "only show files tracked by git") + flag.BoolVarP(&trackedOnly, "tracked", "t", false, "only show files tracked by git") flag.BoolVarP(&helpFlag, "help", "h", false, "show this help message") flag.Usage = func() { @@ -40,30 +40,8 @@ func main() { } var trackedFiles map[string]bool - if trackedFlag { - // Ensure the script is run inside a Git repository - if _, err := os.Stat(".git"); os.IsNotExist(err) { - fmt.Println(os.Stderr, "error: this is not a Git repository.") - os.Exit(1) - } - - cmd := exec.Command("git", "ls-files") - var out bytes.Buffer - cmd.Stdout = &out - cmd.Stderr = os.Stderr - - if err := cmd.Run(); err != nil { - fmt.Println(os.Stderr, "Error running git ls-files:", err) - os.Exit(1) - } - - trackedFiles = make(map[string]bool) - files := strings.Split(out.String(), "\n") - for _, file := range files { - if file != "" { - trackedFiles[file] = true - } - } + if trackedOnly { + trackedFiles = getTrackedFiles() } ruleset, err := loadCodeowners(codeownersPath) @@ -88,7 +66,12 @@ func main() { for _, startPath := range paths { // godirwalk only accepts directories, so we need to handle files separately if !isDir(startPath) { - if err := printFileOwners(out, ruleset, startPath, ownerFilters, showUnowned, trackedFiles, trackedFlag); err != nil { + if err := printFileOwners( + out, + ruleset, + startPath, + ownerFilters, + showUnowned, trackedOnly, trackedFiles); err != nil { fmt.Fprintf(os.Stderr, "error: %v", err) os.Exit(1) } @@ -102,7 +85,7 @@ func main() { // Only show code owners for files, not directories if !d.IsDir() { - return printFileOwners(out, ruleset, path, ownerFilters, showUnowned, trackedFiles, trackedFlag) + return printFileOwners(out, ruleset, path, ownerFilters, showUnowned, trackedOnly, trackedFiles) } return nil }) @@ -114,7 +97,14 @@ func main() { } } -func printFileOwners(out io.Writer, ruleset codeowners.Ruleset, path string, ownerFilters []string, showUnowned bool, trackedFiles map[string]bool, trackedOnly bool) error { +func printFileOwners( + out io.Writer, + ruleset codeowners.Ruleset, + path string, ownerFilters []string, + showUnowned bool, + trackedOnly bool, + trackedFiles map[string]bool, +) error { if trackedOnly { if _, ok := trackedFiles[path]; !ok { return nil @@ -171,3 +161,31 @@ func isDir(path string) bool { } return info.IsDir() } + +func getTrackedFiles() map[string]bool { + // Ensure the script is run inside a Git repository + if _, err := os.Stat(".git"); os.IsNotExist(err) { + fmt.Fprintln(os.Stderr, "error: this is not a Git repository.") + os.Exit(1) + } + + cmd := exec.Command("git", "ls-files") + var out bytes.Buffer + cmd.Stdout = &out + cmd.Stderr = os.Stderr + + if err := cmd.Run(); err != nil { + fmt.Fprintln(os.Stderr, "Error running git ls-files:", err) + os.Exit(1) + } + + var trackedFiles = make(map[string]bool) + files := strings.Split(out.String(), "\n") + for _, file := range files { + if file != "" { + trackedFiles[file] = true + } + } + + return trackedFiles +} From 50a76c1a55b4df52e02695196d2400d436d2706f Mon Sep 17 00:00:00 2001 From: Louis Williams Date: Mon, 19 May 2025 16:42:25 -0400 Subject: [PATCH 3/3] update README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8950522..bf8eea6 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ usage: codeowners ... -f, --file string CODEOWNERS file path -h, --help show this help message -o, --owner strings filter results by owner + -t, --tracked only show files tracked by git -u, --unowned only show unowned files (can be combined with -o) $ ls