From 9ceb621b82cc301b44eedc06b13fb2575d5699e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 12:56:57 +0000 Subject: [PATCH 1/4] Initial plan From 3d8b2befed88de9642e0723dbc767f9a94789bac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 13:02:25 +0000 Subject: [PATCH 2/4] Add branch and tag counts to repository header Co-authored-by: steffen <6301+steffen@users.noreply.github.com> --- main.go | 10 ++++ pkg/git/git.go | 36 ++++++++++++ pkg/git/git_test.go | 139 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) diff --git a/main.go b/main.go index 283e997..0240cef 100644 --- a/main.go +++ b/main.go @@ -129,6 +129,16 @@ func main() { fmt.Printf("Most recent commit %s\n", lastCommit) } + // Branches and tags count + branchCount, branchErr := git.GetBranchCount() + tagCount, tagErr := git.GetTagCount() + if branchErr == nil { + fmt.Printf("Branches %d\n", branchCount) + } + if tagErr == nil { + fmt.Printf("Tags %d\n", tagCount) + } + // First commit and age if progress.ShowProgress { fmt.Printf("First commit ... fetching\n") diff --git a/pkg/git/git.go b/pkg/git/git.go index cb7fd0c..4822d43 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -646,3 +646,39 @@ func calculatePercentile(sortedData []int, percentile int) int { func isLeapYear(year int) bool { return year%4 == 0 && (year%100 != 0 || year%400 == 0) } + +// GetBranchCount returns the total number of branches in the repository +func GetBranchCount() (int, error) { + output, err := RunGitCommand(false, "branch", "-a") + if err != nil { + return 0, err + } + + lines := strings.Split(strings.TrimSpace(string(output)), "\n") + count := 0 + for _, line := range lines { + if strings.TrimSpace(line) != "" { + count++ + } + } + + return count, nil +} + +// GetTagCount returns the total number of tags in the repository +func GetTagCount() (int, error) { + output, err := RunGitCommand(false, "tag") + if err != nil { + return 0, err + } + + lines := strings.Split(strings.TrimSpace(string(output)), "\n") + count := 0 + for _, line := range lines { + if strings.TrimSpace(line) != "" { + count++ + } + } + + return count, nil +} diff --git a/pkg/git/git_test.go b/pkg/git/git_test.go index 618b02a..3a79fbe 100644 --- a/pkg/git/git_test.go +++ b/pkg/git/git_test.go @@ -110,3 +110,142 @@ func TestGetGitDirectory(t *testing.T) { func mockRunGitCommand(_ bool, _ ...string) ([]byte, error) { return []byte("git version 2.35.1"), nil } + +func TestGetBranchCount(t *testing.T) { + tests := []struct { + name string + setupFunc func() string + cleanup func(string) + wantMin int + wantErr bool + }{ + { + name: "Repository with at least one branch", + setupFunc: func() string { + // Create a temporary directory and initialize a git repo + tempDir, _ := os.MkdirTemp("", "git-branch-test") + cmd := exec.Command("git", "init", tempDir) + cmd.Run() + // Set a user name and email for the test repo + exec.Command("git", "-C", tempDir, "config", "user.name", "Test User").Run() + exec.Command("git", "-C", tempDir, "config", "user.email", "test@example.com").Run() + // Create an initial commit to ensure there's a branch + exec.Command("git", "-C", tempDir, "commit", "--allow-empty", "-m", "Initial commit").Run() + return tempDir + }, + cleanup: func(path string) { + os.RemoveAll(path) + }, + wantMin: 1, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var originalDir string + if tt.setupFunc != nil { + originalDir, _ = os.Getwd() + path := tt.setupFunc() + os.Chdir(path) + if tt.cleanup != nil { + defer func() { + os.Chdir(originalDir) + tt.cleanup(path) + }() + } + } + + count, err := GetBranchCount() + if (err != nil) != tt.wantErr { + t.Errorf("GetBranchCount() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if !tt.wantErr && count < tt.wantMin { + t.Errorf("GetBranchCount() = %v, want at least %v", count, tt.wantMin) + } + }) + } +} + +func TestGetTagCount(t *testing.T) { + tests := []struct { + name string + setupFunc func() string + cleanup func(string) + wantCount int + wantErr bool + }{ + { + name: "Repository with no tags", + setupFunc: func() string { + // Create a temporary directory and initialize a git repo + tempDir, _ := os.MkdirTemp("", "git-tag-test") + cmd := exec.Command("git", "init", tempDir) + cmd.Run() + // Set a user name and email for the test repo + exec.Command("git", "-C", tempDir, "config", "user.name", "Test User").Run() + exec.Command("git", "-C", tempDir, "config", "user.email", "test@example.com").Run() + // Create an initial commit + exec.Command("git", "-C", tempDir, "commit", "--allow-empty", "-m", "Initial commit").Run() + return tempDir + }, + cleanup: func(path string) { + os.RemoveAll(path) + }, + wantCount: 0, + wantErr: false, + }, + { + name: "Repository with tags", + setupFunc: func() string { + // Create a temporary directory and initialize a git repo + tempDir, _ := os.MkdirTemp("", "git-tag-test-2") + cmd := exec.Command("git", "init", tempDir) + cmd.Run() + // Set a user name and email for the test repo + exec.Command("git", "-C", tempDir, "config", "user.name", "Test User").Run() + exec.Command("git", "-C", tempDir, "config", "user.email", "test@example.com").Run() + // Create an initial commit + exec.Command("git", "-C", tempDir, "commit", "--allow-empty", "-m", "Initial commit").Run() + // Create a tag + exec.Command("git", "-C", tempDir, "tag", "v1.0.0").Run() + exec.Command("git", "-C", tempDir, "tag", "v2.0.0").Run() + return tempDir + }, + cleanup: func(path string) { + os.RemoveAll(path) + }, + wantCount: 2, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var originalDir string + if tt.setupFunc != nil { + originalDir, _ = os.Getwd() + path := tt.setupFunc() + os.Chdir(path) + if tt.cleanup != nil { + defer func() { + os.Chdir(originalDir) + tt.cleanup(path) + }() + } + } + + count, err := GetTagCount() + if (err != nil) != tt.wantErr { + t.Errorf("GetTagCount() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if !tt.wantErr && count != tt.wantCount { + t.Errorf("GetTagCount() = %v, want %v", count, tt.wantCount) + } + }) + } +} From e82709b0f53914fac82d436f7f3db8c9370b4625 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 13:05:56 +0000 Subject: [PATCH 3/4] Fix edge case handling and improve error handling in tests Co-authored-by: steffen <6301+steffen@users.noreply.github.com> --- pkg/git/git.go | 14 ++++++++++++-- pkg/git/git_test.go | 27 ++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/pkg/git/git.go b/pkg/git/git.go index 4822d43..1e30f96 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -654,7 +654,12 @@ func GetBranchCount() (int, error) { return 0, err } - lines := strings.Split(strings.TrimSpace(string(output)), "\n") + trimmed := strings.TrimSpace(string(output)) + if trimmed == "" { + return 0, nil + } + + lines := strings.Split(trimmed, "\n") count := 0 for _, line := range lines { if strings.TrimSpace(line) != "" { @@ -672,7 +677,12 @@ func GetTagCount() (int, error) { return 0, err } - lines := strings.Split(strings.TrimSpace(string(output)), "\n") + trimmed := strings.TrimSpace(string(output)) + if trimmed == "" { + return 0, nil + } + + lines := strings.Split(trimmed, "\n") count := 0 for _, line := range lines { if strings.TrimSpace(line) != "" { diff --git a/pkg/git/git_test.go b/pkg/git/git_test.go index 3a79fbe..65956ed 100644 --- a/pkg/git/git_test.go +++ b/pkg/git/git_test.go @@ -123,7 +123,10 @@ func TestGetBranchCount(t *testing.T) { name: "Repository with at least one branch", setupFunc: func() string { // Create a temporary directory and initialize a git repo - tempDir, _ := os.MkdirTemp("", "git-branch-test") + tempDir, err := os.MkdirTemp("", "git-branch-test") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } cmd := exec.Command("git", "init", tempDir) cmd.Run() // Set a user name and email for the test repo @@ -145,7 +148,11 @@ func TestGetBranchCount(t *testing.T) { t.Run(tt.name, func(t *testing.T) { var originalDir string if tt.setupFunc != nil { - originalDir, _ = os.Getwd() + var err error + originalDir, err = os.Getwd() + if err != nil { + t.Fatalf("Failed to get current directory: %v", err) + } path := tt.setupFunc() os.Chdir(path) if tt.cleanup != nil { @@ -181,7 +188,10 @@ func TestGetTagCount(t *testing.T) { name: "Repository with no tags", setupFunc: func() string { // Create a temporary directory and initialize a git repo - tempDir, _ := os.MkdirTemp("", "git-tag-test") + tempDir, err := os.MkdirTemp("", "git-tag-test") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } cmd := exec.Command("git", "init", tempDir) cmd.Run() // Set a user name and email for the test repo @@ -201,7 +211,10 @@ func TestGetTagCount(t *testing.T) { name: "Repository with tags", setupFunc: func() string { // Create a temporary directory and initialize a git repo - tempDir, _ := os.MkdirTemp("", "git-tag-test-2") + tempDir, err := os.MkdirTemp("", "git-tag-test-2") + if err != nil { + t.Fatalf("Failed to create temp directory: %v", err) + } cmd := exec.Command("git", "init", tempDir) cmd.Run() // Set a user name and email for the test repo @@ -226,7 +239,11 @@ func TestGetTagCount(t *testing.T) { t.Run(tt.name, func(t *testing.T) { var originalDir string if tt.setupFunc != nil { - originalDir, _ = os.Getwd() + var err error + originalDir, err = os.Getwd() + if err != nil { + t.Fatalf("Failed to get current directory: %v", err) + } path := tt.setupFunc() os.Chdir(path) if tt.cleanup != nil { From 003d6c76e2c478cdf49f47b4aaff1d0d89485ff9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 16 Oct 2025 13:09:02 +0000 Subject: [PATCH 4/4] Refactor to reduce code duplication and improve test robustness Co-authored-by: steffen <6301+steffen@users.noreply.github.com> --- pkg/git/git.go | 38 +++++++++++----------------- pkg/git/git_test.go | 61 ++++++++++++++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 41 deletions(-) diff --git a/pkg/git/git.go b/pkg/git/git.go index 1e30f96..20e051d 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -647,16 +647,11 @@ func isLeapYear(year int) bool { return year%4 == 0 && (year%100 != 0 || year%400 == 0) } -// GetBranchCount returns the total number of branches in the repository -func GetBranchCount() (int, error) { - output, err := RunGitCommand(false, "branch", "-a") - if err != nil { - return 0, err - } - +// countNonEmptyLines counts the number of non-empty lines in the output +func countNonEmptyLines(output []byte) int { trimmed := strings.TrimSpace(string(output)) if trimmed == "" { - return 0, nil + return 0 } lines := strings.Split(trimmed, "\n") @@ -667,7 +662,17 @@ func GetBranchCount() (int, error) { } } - return count, nil + return count +} + +// GetBranchCount returns the total number of branches in the repository +func GetBranchCount() (int, error) { + output, err := RunGitCommand(false, "branch", "-a") + if err != nil { + return 0, err + } + + return countNonEmptyLines(output), nil } // GetTagCount returns the total number of tags in the repository @@ -677,18 +682,5 @@ func GetTagCount() (int, error) { return 0, err } - trimmed := strings.TrimSpace(string(output)) - if trimmed == "" { - return 0, nil - } - - lines := strings.Split(trimmed, "\n") - count := 0 - for _, line := range lines { - if strings.TrimSpace(line) != "" { - count++ - } - } - - return count, nil + return countNonEmptyLines(output), nil } diff --git a/pkg/git/git_test.go b/pkg/git/git_test.go index 65956ed..1d433cc 100644 --- a/pkg/git/git_test.go +++ b/pkg/git/git_test.go @@ -127,13 +127,20 @@ func TestGetBranchCount(t *testing.T) { if err != nil { t.Fatalf("Failed to create temp directory: %v", err) } - cmd := exec.Command("git", "init", tempDir) - cmd.Run() + if err := exec.Command("git", "init", tempDir).Run(); err != nil { + t.Fatalf("Failed to initialize git repo: %v", err) + } // Set a user name and email for the test repo - exec.Command("git", "-C", tempDir, "config", "user.name", "Test User").Run() - exec.Command("git", "-C", tempDir, "config", "user.email", "test@example.com").Run() + if err := exec.Command("git", "-C", tempDir, "config", "user.name", "Test User").Run(); err != nil { + t.Fatalf("Failed to set git user.name: %v", err) + } + if err := exec.Command("git", "-C", tempDir, "config", "user.email", "test@example.com").Run(); err != nil { + t.Fatalf("Failed to set git user.email: %v", err) + } // Create an initial commit to ensure there's a branch - exec.Command("git", "-C", tempDir, "commit", "--allow-empty", "-m", "Initial commit").Run() + if err := exec.Command("git", "-C", tempDir, "commit", "--allow-empty", "-m", "Initial commit").Run(); err != nil { + t.Fatalf("Failed to create initial commit: %v", err) + } return tempDir }, cleanup: func(path string) { @@ -192,13 +199,20 @@ func TestGetTagCount(t *testing.T) { if err != nil { t.Fatalf("Failed to create temp directory: %v", err) } - cmd := exec.Command("git", "init", tempDir) - cmd.Run() + if err := exec.Command("git", "init", tempDir).Run(); err != nil { + t.Fatalf("Failed to initialize git repo: %v", err) + } // Set a user name and email for the test repo - exec.Command("git", "-C", tempDir, "config", "user.name", "Test User").Run() - exec.Command("git", "-C", tempDir, "config", "user.email", "test@example.com").Run() + if err := exec.Command("git", "-C", tempDir, "config", "user.name", "Test User").Run(); err != nil { + t.Fatalf("Failed to set git user.name: %v", err) + } + if err := exec.Command("git", "-C", tempDir, "config", "user.email", "test@example.com").Run(); err != nil { + t.Fatalf("Failed to set git user.email: %v", err) + } // Create an initial commit - exec.Command("git", "-C", tempDir, "commit", "--allow-empty", "-m", "Initial commit").Run() + if err := exec.Command("git", "-C", tempDir, "commit", "--allow-empty", "-m", "Initial commit").Run(); err != nil { + t.Fatalf("Failed to create initial commit: %v", err) + } return tempDir }, cleanup: func(path string) { @@ -215,16 +229,27 @@ func TestGetTagCount(t *testing.T) { if err != nil { t.Fatalf("Failed to create temp directory: %v", err) } - cmd := exec.Command("git", "init", tempDir) - cmd.Run() + if err := exec.Command("git", "init", tempDir).Run(); err != nil { + t.Fatalf("Failed to initialize git repo: %v", err) + } // Set a user name and email for the test repo - exec.Command("git", "-C", tempDir, "config", "user.name", "Test User").Run() - exec.Command("git", "-C", tempDir, "config", "user.email", "test@example.com").Run() + if err := exec.Command("git", "-C", tempDir, "config", "user.name", "Test User").Run(); err != nil { + t.Fatalf("Failed to set git user.name: %v", err) + } + if err := exec.Command("git", "-C", tempDir, "config", "user.email", "test@example.com").Run(); err != nil { + t.Fatalf("Failed to set git user.email: %v", err) + } // Create an initial commit - exec.Command("git", "-C", tempDir, "commit", "--allow-empty", "-m", "Initial commit").Run() - // Create a tag - exec.Command("git", "-C", tempDir, "tag", "v1.0.0").Run() - exec.Command("git", "-C", tempDir, "tag", "v2.0.0").Run() + if err := exec.Command("git", "-C", tempDir, "commit", "--allow-empty", "-m", "Initial commit").Run(); err != nil { + t.Fatalf("Failed to create initial commit: %v", err) + } + // Create tags + if err := exec.Command("git", "-C", tempDir, "tag", "v1.0.0").Run(); err != nil { + t.Fatalf("Failed to create tag v1.0.0: %v", err) + } + if err := exec.Command("git", "-C", tempDir, "tag", "v2.0.0").Run(); err != nil { + t.Fatalf("Failed to create tag v2.0.0: %v", err) + } return tempDir }, cleanup: func(path string) {