summaryrefslogtreecommitdiff
path: root/internal/showcase
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-22 13:53:59 +0200
committerPaul Buetow <paul@buetow.org>2026-02-22 13:53:59 +0200
commit37665bec9014a69e82e2c19e59fc40ce06feea77 (patch)
tree9c7e7c6f1c0c6deed94ee9db1a36f1020cafe815 /internal/showcase
parentebc50a6600fcf4ebc53df4846f790bb05757b3df (diff)
fix(showcase): exclude backup-suffixed repositories
Diffstat (limited to 'internal/showcase')
-rw-r--r--internal/showcase/showcase.go46
-rw-r--r--internal/showcase/showcase_test.go100
2 files changed, 134 insertions, 12 deletions
diff --git a/internal/showcase/showcase.go b/internal/showcase/showcase.go
index a8770a2..19a9a89 100644
--- a/internal/showcase/showcase.go
+++ b/internal/showcase/showcase.go
@@ -815,23 +815,13 @@ func (g *Generator) verifyImages(summary *ProjectSummary) error {
// filterExcludedRepos filters out repositories that are in the exclusion list
func (g *Generator) filterExcludedRepos(repos []string) []string {
- if len(g.config.ExcludeFromShowcase) == 0 {
- return repos
- }
-
- // Create a map for quick lookup
- excludeMap := make(map[string]bool)
- for _, excluded := range g.config.ExcludeFromShowcase {
- excludeMap[excluded] = true
- }
-
// Filter repositories
var filtered []string
for _, repo := range repos {
- if !excludeMap[repo] {
+ if !g.isExcluded(repo) {
filtered = append(filtered, repo)
} else {
- fmt.Printf("Excluding repository from showcase: %s\n", repo)
+ fmt.Printf("Excluding repository from showcase (%s): %s\n", g.exclusionReason(repo), repo)
}
}
@@ -840,6 +830,10 @@ func (g *Generator) filterExcludedRepos(repos []string) []string {
// isExcluded checks if a repository is in the exclusion list
func (g *Generator) isExcluded(repo string) bool {
+ if isBackupRepo(repo) {
+ return true
+ }
+
for _, excluded := range g.config.ExcludeFromShowcase {
if excluded == repo {
return true
@@ -848,6 +842,34 @@ func (g *Generator) isExcluded(repo string) bool {
return false
}
+// exclusionReason returns why a repository is excluded from showcase generation.
+func (g *Generator) exclusionReason(repo string) string {
+ var reasons []string
+
+ if isBackupRepo(repo) {
+ reasons = append(reasons, "backup suffix")
+ }
+
+ for _, excluded := range g.config.ExcludeFromShowcase {
+ if excluded == repo {
+ reasons = append(reasons, "config")
+ break
+ }
+ }
+
+ if len(reasons) == 0 {
+ return "unknown reason"
+ }
+
+ return strings.Join(reasons, ", ")
+}
+
+// isBackupRepo checks whether a repository name has a backup suffix.
+// Excluded patterns: *.bak and *.bak.*
+func isBackupRepo(repo string) bool {
+ return strings.HasSuffix(repo, ".bak") || strings.Contains(repo, ".bak.")
+}
+
// formatNumber formats a number with thousands separators
func formatNumber(n int) string {
str := fmt.Sprintf("%d", n)
diff --git a/internal/showcase/showcase_test.go b/internal/showcase/showcase_test.go
new file mode 100644
index 0000000..284a6bc
--- /dev/null
+++ b/internal/showcase/showcase_test.go
@@ -0,0 +1,100 @@
+package showcase
+
+import (
+ "reflect"
+ "testing"
+
+ "codeberg.org/snonux/gitsyncer/internal/config"
+)
+
+func TestIsBackupRepo(t *testing.T) {
+ t.Parallel()
+
+ tests := []struct {
+ name string
+ repo string
+ want bool
+ }{
+ {name: "exact bak suffix", repo: "foo.bak", want: true},
+ {name: "bak dot suffix", repo: "foo.bak.20260222", want: true},
+ {name: "bak dot with multiple segments", repo: "foo.bak.tmp.snapshot", want: true},
+ {name: "backup word", repo: "foo.backup", want: false},
+ {name: "bak as prefix", repo: "bak.foo", want: false},
+ }
+
+ for _, tc := range tests {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+ got := isBackupRepo(tc.repo)
+ if got != tc.want {
+ t.Fatalf("isBackupRepo(%q) = %v, want %v", tc.repo, got, tc.want)
+ }
+ })
+ }
+}
+
+func TestIsExcluded_AdditiveRules(t *testing.T) {
+ t.Parallel()
+
+ g := &Generator{
+ config: &config.Config{
+ ExcludeFromShowcase: []string{"manual-exclude"},
+ },
+ }
+
+ tests := []struct {
+ name string
+ repo string
+ want bool
+ }{
+ {name: "excluded by config", repo: "manual-exclude", want: true},
+ {name: "excluded by backup suffix", repo: "repo.bak", want: true},
+ {name: "not excluded", repo: "normal-repo", want: false},
+ }
+
+ for _, tc := range tests {
+ tc := tc
+ t.Run(tc.name, func(t *testing.T) {
+ t.Parallel()
+ got := g.isExcluded(tc.repo)
+ if got != tc.want {
+ t.Fatalf("isExcluded(%q) = %v, want %v", tc.repo, got, tc.want)
+ }
+ })
+ }
+}
+
+func TestFilterExcludedRepos_RemovesBackupAndConfigRepos(t *testing.T) {
+ t.Parallel()
+
+ g := &Generator{
+ config: &config.Config{
+ ExcludeFromShowcase: []string{"manual-exclude"},
+ },
+ }
+
+ repos := []string{"normal", "manual-exclude", "mirror.bak", "mirror.bak.20260222", "keep"}
+ want := []string{"normal", "keep"}
+
+ got := g.filterExcludedRepos(repos)
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("filterExcludedRepos() = %#v, want %#v", got, want)
+ }
+}
+
+func TestFilterExcludedRepos_EmptyConfigStillRemovesBackupRepos(t *testing.T) {
+ t.Parallel()
+
+ g := &Generator{
+ config: &config.Config{},
+ }
+
+ repos := []string{"normal", "archive.bak", "archive.bak.old", "keep"}
+ want := []string{"normal", "keep"}
+
+ got := g.filterExcludedRepos(repos)
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("filterExcludedRepos() = %#v, want %#v", got, want)
+ }
+}