diff options
| -rw-r--r-- | internal/cli/release.go | 14 | ||||
| -rw-r--r-- | internal/localrepos/localrepos.go | 41 | ||||
| -rw-r--r-- | internal/localrepos/localrepos_test.go | 79 | ||||
| -rw-r--r-- | internal/showcase/showcase.go | 23 |
4 files changed, 124 insertions, 33 deletions
diff --git a/internal/cli/release.go b/internal/cli/release.go index b5300c6..d57148d 100644 --- a/internal/cli/release.go +++ b/internal/cli/release.go @@ -8,6 +8,7 @@ import ( "strings" "codeberg.org/snonux/gitsyncer/internal/config" + "codeberg.org/snonux/gitsyncer/internal/localrepos" "codeberg.org/snonux/gitsyncer/internal/release" "codeberg.org/snonux/gitsyncer/internal/version" ) @@ -15,23 +16,12 @@ import ( // HandleCheckReleases checks for version tags without releases and creates them with confirmation func HandleCheckReleases(cfg *config.Config, flags *Flags) int { // Get all repositories from work directory - entries, err := os.ReadDir(flags.WorkDir) + repositories, err := localrepos.ListLocalRepos(flags.WorkDir) if err != nil { fmt.Printf("Error reading work directory %s: %v\n", flags.WorkDir, err) return 1 } - var repositories []string - for _, entry := range entries { - if entry.IsDir() { - // Check if it's a git repository - gitPath := filepath.Join(flags.WorkDir, entry.Name(), ".git") - if _, err := os.Stat(gitPath); err == nil { - repositories = append(repositories, entry.Name()) - } - } - } - if len(repositories) == 0 { fmt.Println("No repositories found in work directory") return 1 diff --git a/internal/localrepos/localrepos.go b/internal/localrepos/localrepos.go new file mode 100644 index 0000000..6200539 --- /dev/null +++ b/internal/localrepos/localrepos.go @@ -0,0 +1,41 @@ +package localrepos + +import ( + "os" + "path/filepath" +) + +// ListLocalRepos returns directory names in workDir that contain a .git path. +// The .git path may be either a directory or a file (for worktree layouts). +func ListLocalRepos(workDir string) ([]string, error) { + return listLocalRepos(workDir, false) +} + +// ListLocalReposWithGitDir returns directory names in workDir that contain +// a .git directory. +func ListLocalReposWithGitDir(workDir string) ([]string, error) { + return listLocalRepos(workDir, true) +} + +func listLocalRepos(workDir string, requireGitDir bool) ([]string, error) { + entries, err := os.ReadDir(workDir) + if err != nil { + return nil, err + } + + repositories := make([]string, 0, len(entries)) + for _, entry := range entries { + if !entry.IsDir() { + continue + } + + gitDir := filepath.Join(workDir, entry.Name(), ".git") + if info, err := os.Stat(gitDir); err == nil { + if !requireGitDir || info.IsDir() { + repositories = append(repositories, entry.Name()) + } + } + } + + return repositories, nil +} diff --git a/internal/localrepos/localrepos_test.go b/internal/localrepos/localrepos_test.go new file mode 100644 index 0000000..f1b49e5 --- /dev/null +++ b/internal/localrepos/localrepos_test.go @@ -0,0 +1,79 @@ +package localrepos + +import ( + "os" + "path/filepath" + "reflect" + "testing" +) + +func TestListLocalRepos_ReturnsGitPathsSorted(t *testing.T) { + t.Parallel() + + workDir := t.TempDir() + + if err := os.MkdirAll(filepath.Join(workDir, "z-repo", ".git"), 0755); err != nil { + t.Fatalf("failed to create z-repo: %v", err) + } + if err := os.MkdirAll(filepath.Join(workDir, "a-repo", ".git"), 0755); err != nil { + t.Fatalf("failed to create a-repo: %v", err) + } + if err := os.MkdirAll(filepath.Join(workDir, "not-a-repo"), 0755); err != nil { + t.Fatalf("failed to create non-repo dir: %v", err) + } + if err := os.WriteFile(filepath.Join(workDir, "README.txt"), []byte("ignore"), 0644); err != nil { + t.Fatalf("failed to create file entry: %v", err) + } + + if err := os.MkdirAll(filepath.Join(workDir, "git-file-repo"), 0755); err != nil { + t.Fatalf("failed to create git-file-repo dir: %v", err) + } + if err := os.WriteFile(filepath.Join(workDir, "git-file-repo", ".git"), []byte("gitdir: /tmp/worktree"), 0644); err != nil { + t.Fatalf("failed to create .git file: %v", err) + } + + got, err := ListLocalRepos(workDir) + if err != nil { + t.Fatalf("ListLocalRepos returned error: %v", err) + } + + want := []string{"a-repo", "git-file-repo", "z-repo"} + if !reflect.DeepEqual(got, want) { + t.Fatalf("ListLocalRepos() = %#v, want %#v", got, want) + } +} + +func TestListLocalReposWithGitDir_ExcludesGitFileRepos(t *testing.T) { + t.Parallel() + + workDir := t.TempDir() + + if err := os.MkdirAll(filepath.Join(workDir, "repo-dir", ".git"), 0755); err != nil { + t.Fatalf("failed to create repo-dir: %v", err) + } + if err := os.MkdirAll(filepath.Join(workDir, "repo-file"), 0755); err != nil { + t.Fatalf("failed to create repo-file: %v", err) + } + if err := os.WriteFile(filepath.Join(workDir, "repo-file", ".git"), []byte("gitdir: /tmp/worktree"), 0644); err != nil { + t.Fatalf("failed to create repo-file .git file: %v", err) + } + + got, err := ListLocalReposWithGitDir(workDir) + if err != nil { + t.Fatalf("ListLocalReposWithGitDir returned error: %v", err) + } + + want := []string{"repo-dir"} + if !reflect.DeepEqual(got, want) { + t.Fatalf("ListLocalReposWithGitDir() = %#v, want %#v", got, want) + } +} + +func TestListLocalRepos_ReturnsReadDirError(t *testing.T) { + t.Parallel() + + _, err := ListLocalRepos(filepath.Join(t.TempDir(), "missing")) + if err == nil { + t.Fatal("expected error for missing work dir") + } +} diff --git a/internal/showcase/showcase.go b/internal/showcase/showcase.go index 90a4dc7..ea9b82e 100644 --- a/internal/showcase/showcase.go +++ b/internal/showcase/showcase.go @@ -13,6 +13,7 @@ import ( "codeberg.org/snonux/gitsyncer/internal/aitool" "codeberg.org/snonux/gitsyncer/internal/config" + "codeberg.org/snonux/gitsyncer/internal/localrepos" ) // Generator handles showcase generation for repositories @@ -624,27 +625,7 @@ func isSetextUnderline(line string) bool { // getRepositories returns a list of repository directories in the work directory func (g *Generator) getRepositories() ([]string, error) { - entries, err := os.ReadDir(g.workDir) - if err != nil { - return nil, err - } - - var repos []string - for _, entry := range entries { - if !entry.IsDir() { - continue - } - - // Check if it's a git repository - gitDir := filepath.Join(g.workDir, entry.Name(), ".git") - if info, err := os.Stat(gitDir); err == nil && info.IsDir() { - repos = append(repos, entry.Name()) - } - } - - // Sort repositories alphabetically - sort.Strings(repos) - return repos, nil + return localrepos.ListLocalReposWithGitDir(g.workDir) } func (g *Generator) buildProjectLinks(repoName string) (string, string, string) { |
