Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions cache/repo_cache_common.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package cache

import (
"fmt"
"io"
"sync"

"github.com/pkg/errors"

"github.com/git-bug/git-bug/entities/identity"
"github.com/git-bug/git-bug/entity"
"github.com/git-bug/git-bug/repository"
Expand Down Expand Up @@ -155,16 +154,21 @@ func (c *RepoCache) Pull(remote string) error {
return err
}

var failure error
for merge := range c.MergeAll(remote) {
if merge.Err != nil {
return merge.Err
if failure != nil {
// keep reading, so that the other entities are merged and
// MergeAll's goroutine doesn't block forever
continue
}
if merge.Status == entity.MergeStatusInvalid {
return errors.Errorf("merge failure: %s", merge.Reason)
if merge.Err != nil {
failure = merge.Err
} else if merge.Status == entity.MergeStatusInvalid {
failure = fmt.Errorf("merge failure: %s", merge.Reason)
}
}

return nil
return failure
}

func (c *RepoCache) SetUserIdentity(i *IdentityCache) error {
Expand Down
46 changes: 46 additions & 0 deletions cache/repo_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,52 @@ func TestCacheMerge(t *testing.T) {
require.Equal(t, uint64(len(cacheB.Identities().AllIds())), indexCount(t, identity.Namespace))
}

// A merge failure is reported by Pull, but doesn't stop the other entities from
// being merged.
func TestCachePullAfterFailure(t *testing.T) {
repoA, repoB, _ := repository.SetupGoGitReposAndRemote(t)

cacheA := createTestRepoCacheNoEvents(t, repoA)
cacheB := createTestRepoCacheNoEvents(t, repoB)

reneA, err := cacheA.Identities().New("René Descartes", "[email protected]")
require.NoError(t, err)
err = cacheA.SetUserIdentity(reneA)
require.NoError(t, err)

_, err = cacheA.Push("origin")
require.NoError(t, err)
err = cacheB.Pull("origin")
require.NoError(t, err)

// the identity diverges, which can't be merged. Identities are merged before
// bugs, so this failure is the first merge result.
reneB, err := cacheB.Identities().Resolve(reneA.Id())
require.NoError(t, err)
err = reneB.Mutate(repoB, func(m *identity.Mutator) { m.Name = "René B" })
require.NoError(t, err)
err = reneB.Commit()
require.NoError(t, err)

err = reneA.Mutate(repoA, func(m *identity.Mutator) { m.Name = "René A" })
require.NoError(t, err)
err = reneA.Commit()
require.NoError(t, err)

// more than one bug, as the merge used to stop right after the first one
bug1A, _, err := cacheA.Bugs().New("bug1", "message")
require.NoError(t, err)
bug2A, _, err := cacheA.Bugs().New("bug2", "message")
require.NoError(t, err)

_, err = cacheA.Push("origin")
require.NoError(t, err)

err = cacheB.Pull("origin")
require.ErrorContains(t, err, "merge failure")
require.ElementsMatch(t, []entity.Id{bug1A.Id(), bug2A.Id()}, cacheB.Bugs().AllIds())
}

// Pulling into a fresh repo must not require a user identity, otherwise it's
// impossible to adopt an identity that only exists on the remote.
// See https://github.com/git-bug/git-bug/issues/1003
Expand Down
15 changes: 10 additions & 5 deletions entities/identity/identity_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,21 @@ func Pull(repo repository.ClockedRepo, remote string) error {
return err
}

var failure error
for merge := range MergeAll(repo, remote) {
if merge.Err != nil {
return merge.Err
if failure != nil {
// keep reading, so that the other identities are merged and
// MergeAll's goroutine doesn't block forever
continue
Comment on lines +34 to +37
}
if merge.Status == entity.MergeStatusInvalid {
return errors.Errorf("merge failure: %s", merge.Reason)
if merge.Err != nil {
failure = merge.Err
} else if merge.Status == entity.MergeStatusInvalid {
failure = fmt.Errorf("merge failure: %s", merge.Reason)
}
}

return nil
return failure
}

// MergeAll will merge all the available remote identity
Expand Down
15 changes: 10 additions & 5 deletions entity/dag/entity_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,21 @@ func Pull[EntityT entity.Interface](def Definition, wrapper func(e *Entity) Enti
return err
}

var failure error
for merge := range MergeAll(def, wrapper, repo, resolvers, remote, author) {
if merge.Err != nil {
return merge.Err
if failure != nil {
// keep reading, so that the other entities are merged and
// MergeAll's goroutine doesn't block forever
continue
}
if merge.Status == entity.MergeStatusInvalid {
return errors.Errorf("merge failure: %s", merge.Reason)
if merge.Err != nil {
failure = merge.Err
} else if merge.Status == entity.MergeStatusInvalid {
failure = fmt.Errorf("merge failure: %s", merge.Reason)
}
}

return nil
return failure
}

// MergeAll will merge all the available remote Entity:
Expand Down
Loading