summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-29 10:22:50 +0300
committerPaul Buetow <paul@buetow.org>2026-05-29 10:24:09 +0300
commitde3a697796d2e6820e8f19890252ace08bc0ef63 (patch)
tree904eddaaf4997b278138150cc797b9558284a844
parent2b60fb406a178edb1822fb62b28b4e07e77dc0ed (diff)
refactor(localrepos): extract shared ListLocalRepos helper (nq)
-rw-r--r--internal/cli/release.go14
-rw-r--r--internal/localrepos/localrepos.go41
-rw-r--r--internal/localrepos/localrepos_test.go79
-rw-r--r--internal/showcase/showcase.go23
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) {