fix(gitstore): adjust garbage collection to run after push operation

- Updated `maybeRunGC` to accept `repoDir` instead of `repo`.
- Moved garbage collection trigger to occur after the push step for improved reliability.
- Added a test to validate the sequence of push and GC operations.

Closes: #3373
This commit is contained in:
Luis Pater
2026-05-16 04:55:44 +08:00
parent 9d01c80d33
commit 30a8824b64
2 changed files with 41 additions and 2 deletions
+7 -2
View File
@@ -858,7 +858,6 @@ func (s *GitTokenStore) commitAndPushLocked(message string, relPaths ...string)
} else if errRewrite := s.rewriteHeadAsSingleCommit(repo, headRef.Name(), commitHash, message, signature); errRewrite != nil { } else if errRewrite := s.rewriteHeadAsSingleCommit(repo, headRef.Name(), commitHash, message, signature); errRewrite != nil {
return errRewrite return errRewrite
} }
s.maybeRunGC(repo)
pushOpts := &git.PushOptions{Auth: s.gitAuth(), Force: true} pushOpts := &git.PushOptions{Auth: s.gitAuth(), Force: true}
if s.branch != "" { if s.branch != "" {
pushOpts.RefSpecs = []config.RefSpec{config.RefSpec("refs/heads/" + s.branch + ":refs/heads/" + s.branch)} pushOpts.RefSpecs = []config.RefSpec{config.RefSpec("refs/heads/" + s.branch + ":refs/heads/" + s.branch)}
@@ -874,6 +873,7 @@ func (s *GitTokenStore) commitAndPushLocked(message string, relPaths ...string)
} }
return fmt.Errorf("git token store: push: %w", err) return fmt.Errorf("git token store: push: %w", err)
} }
s.maybeRunGC(repoDir)
return nil return nil
} }
@@ -907,13 +907,18 @@ func (s *GitTokenStore) rewriteHeadAsSingleCommit(repo *git.Repository, branch p
return nil return nil
} }
func (s *GitTokenStore) maybeRunGC(repo *git.Repository) { func (s *GitTokenStore) maybeRunGC(repoDir string) {
now := time.Now() now := time.Now()
if now.Sub(s.lastGC) < gcInterval { if now.Sub(s.lastGC) < gcInterval {
return return
} }
s.lastGC = now s.lastGC = now
repo, err := git.PlainOpen(repoDir)
if err != nil {
return
}
pruneOpts := git.PruneOptions{ pruneOpts := git.PruneOptions{
OnlyObjectsOlderThan: now, OnlyObjectsOlderThan: now,
Handler: repo.DeleteObject, Handler: repo.DeleteObject,
+34
View File
@@ -239,6 +239,40 @@ func TestEnsureRepositoryResetsToRemoteDefaultWhenBranchUnset(t *testing.T) {
assertRemoteBranchContents(t, remoteDir, "master", "local master update\n") assertRemoteBranchContents(t, remoteDir, "master", "local master update\n")
} }
func TestCommitAndPushLockedPushesBeforeRunningGC(t *testing.T) {
root := t.TempDir()
remoteDir := setupGitRemoteRepository(t, root, "master",
testBranchSpec{name: "master", contents: "remote master branch\n"},
)
store := NewGitTokenStore(remoteDir, "", "", "")
store.SetBaseDir(filepath.Join(root, "workspace", "auths"))
if err := store.EnsureRepository(); err != nil {
t.Fatalf("EnsureRepository: %v", err)
}
workspaceDir := filepath.Join(root, "workspace")
updates := []string{
"local master update one\n",
"local master update two\n",
}
for _, contents := range updates {
if err := os.WriteFile(filepath.Join(workspaceDir, "branch.txt"), []byte(contents), 0o600); err != nil {
t.Fatalf("write local master marker: %v", err)
}
store.lastGC = time.Now().Add(-gcInterval)
store.mu.Lock()
err := store.commitAndPushLocked("Update master marker", "branch.txt")
store.mu.Unlock()
if err != nil {
t.Fatalf("commitAndPushLocked with forced GC: %v", err)
}
assertRemoteBranchContents(t, remoteDir, "master", contents)
}
}
func TestEnsureRepositoryFollowsRenamedRemoteDefaultBranchWhenAvailable(t *testing.T) { func TestEnsureRepositoryFollowsRenamedRemoteDefaultBranchWhenAvailable(t *testing.T) {
root := t.TempDir() root := t.TempDir()
remoteDir := setupGitRemoteRepository(t, root, "master", remoteDir := setupGitRemoteRepository(t, root, "master",