diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-29 17:07:22 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-29 17:07:22 +0300 |
| commit | b076c5e2ac5403de28c5d0ba44fddf216f3034ce (patch) | |
| tree | a979b40edc269005879d6be2c4a2fced4210156c | |
| parent | a956a672859e92190149506197ad0fa682e964e2 (diff) | |
fix(vq): handle ignored stash/pop and parse errors explicitly
| -rw-r--r-- | internal/release/release.go | 15 | ||||
| -rw-r--r-- | internal/release/release_tags_test.go | 20 | ||||
| -rw-r--r-- | internal/sync/git_operations.go | 9 | ||||
| -rw-r--r-- | internal/sync/git_operations_test.go | 43 | ||||
| -rw-r--r-- | internal/sync/sync.go | 6 |
5 files changed, 88 insertions, 5 deletions
diff --git a/internal/release/release.go b/internal/release/release.go index 9af3392..0c8b33f 100644 --- a/internal/release/release.go +++ b/internal/release/release.go @@ -9,6 +9,7 @@ import ( "os" "os/exec" "sort" + "strconv" "strings" "codeberg.org/snonux/gitsyncer/internal/aitool" @@ -164,10 +165,10 @@ func compareVersions(v1, v2 string) int { var n1, n2 int if i < len(parts1) { - fmt.Sscanf(parts1[i], "%d", &n1) + n1 = parseVersionPart(parts1[i]) } if i < len(parts2) { - fmt.Sscanf(parts2[i], "%d", &n2) + n2 = parseVersionPart(parts2[i]) } if n1 < n2 { @@ -180,6 +181,16 @@ func compareVersions(v1, v2 string) int { return 0 } +func parseVersionPart(part string) int { + n, err := strconv.Atoi(part) + if err != nil { + // Keep current behavior for non-numeric segments. + return 0 + } + + return n +} + // GetCommitsSinceTag gets all commits since a specific tag func (m *Manager) GetCommitsSinceTag(repoPath, fromTag, toTag string) ([]string, error) { // Use git log to get commits between tags diff --git a/internal/release/release_tags_test.go b/internal/release/release_tags_test.go index 334c165..eb6d581 100644 --- a/internal/release/release_tags_test.go +++ b/internal/release/release_tags_test.go @@ -41,6 +41,26 @@ func TestGetLocalTags_FiltersToStrictVersionTags(t *testing.T) { } } +func TestParseVersionPart_NonNumericReturnsZero(t *testing.T) { + t.Parallel() + + if got := parseVersionPart("abc"); got != 0 { + t.Fatalf("parseVersionPart(non-numeric) = %d, want 0", got) + } +} + +func TestCompareVersions_NonNumericSegmentsFollowZeroFallback(t *testing.T) { + t.Parallel() + + if got := compareVersions("v1.alpha.1", "v1.0.2"); got != -1 { + t.Fatalf("compareVersions(v1.alpha.1, v1.0.2) = %d, want -1", got) + } + + if got := compareVersions("v2.beta", "v2.0"); got != 0 { + t.Fatalf("compareVersions(v2.beta, v2.0) = %d, want 0", got) + } +} + func runGit(t *testing.T, repoPath string, args ...string) string { t.Helper() diff --git a/internal/sync/git_operations.go b/internal/sync/git_operations.go index 08eea34..1acfb95 100644 --- a/internal/sync/git_operations.go +++ b/internal/sync/git_operations.go @@ -43,8 +43,13 @@ func stashChanges(repoPath string) error { } // popStash attempts to pop the stash (used in defer) -func popStash(repoPath string) { - gitCommand(repoPath, "stash", "pop").Run() +func popStash(repoPath string) error { + output, err := gitCommand(repoPath, "stash", "pop").CombinedOutput() + if err != nil { + return fmt.Errorf("failed to restore stashed changes: %w\n%s", err, strings.TrimSpace(string(output))) + } + + return nil } // mergeBranch merges a branch from a remote diff --git a/internal/sync/git_operations_test.go b/internal/sync/git_operations_test.go index e696fb7..b80bf0e 100644 --- a/internal/sync/git_operations_test.go +++ b/internal/sync/git_operations_test.go @@ -1,7 +1,9 @@ package sync import ( + "os" "os/exec" + "path/filepath" "strings" "testing" ) @@ -77,6 +79,47 @@ func TestGetTagCommitHash_LocalTagMissingReturnsError(t *testing.T) { } } +func TestPopStash_NoStashReturnsError(t *testing.T) { + repoPath := t.TempDir() + runGit(t, repoPath, "init") + + if err := popStash(repoPath); err == nil { + t.Fatal("expected error when popping stash with no entries") + } +} + +func TestPopStash_RestoresStashedChanges(t *testing.T) { + repoPath := t.TempDir() + + runGit(t, repoPath, "init") + runGit(t, repoPath, "config", "user.name", "Test User") + runGit(t, repoPath, "config", "user.email", "test@example.com") + + trackedFile := filepath.Join(repoPath, "tracked.txt") + if err := os.WriteFile(trackedFile, []byte("first\n"), 0o644); err != nil { + t.Fatalf("write tracked file: %v", err) + } + runGit(t, repoPath, "add", "tracked.txt") + runGit(t, repoPath, "commit", "-m", "initial") + + if err := os.WriteFile(trackedFile, []byte("second\n"), 0o644); err != nil { + t.Fatalf("update tracked file: %v", err) + } + runGit(t, repoPath, "stash", "push", "-m", "test-stash") + + if err := popStash(repoPath); err != nil { + t.Fatalf("expected popStash to succeed, got error: %v", err) + } + + content, err := os.ReadFile(trackedFile) + if err != nil { + t.Fatalf("read tracked file: %v", err) + } + if string(content) != "second\n" { + t.Fatalf("expected stashed content to be restored, got %q", string(content)) + } +} + func runGit(t *testing.T, repoPath string, args ...string) string { t.Helper() diff --git a/internal/sync/sync.go b/internal/sync/sync.go index 2f05110..949cb43 100644 --- a/internal/sync/sync.go +++ b/internal/sync/sync.go @@ -324,7 +324,11 @@ func (s *Syncer) syncBranch(branch string, remotes map[string]*config.Organizati return err } if stashed { - defer popStash(repoPath) + defer func() { + if err := popStash(repoPath); err != nil { + fmt.Printf(" Warning: %v\n", err) + } + }() } // Create or checkout the branch |
