From 647b05eee4b612f33a2f22576821ea1c012d7c84 Mon Sep 17 00:00:00 2001 From: vince Date: Thu, 19 Nov 2020 20:57:57 +0800 Subject: add remove identity feature also adds: - listlocalidentities - refactors refstoids into entity package --- bug/bug.go | 21 ++------ entity/refs.go | 18 +++++++ go.sum | 3 ++ identity/identity.go | 64 ++++++++++++++++++++++++ identity/identity_test.go | 123 ++++++++++++++++++++++++++++++++-------------- 5 files changed, 173 insertions(+), 56 deletions(-) create mode 100644 entity/refs.go diff --git a/bug/bug.go b/bug/bug.go index 6f5d0a7a..f6c35a2d 100644 --- a/bug/bug.go +++ b/bug/bug.go @@ -234,7 +234,7 @@ func RemoveBug(repo repository.ClockedRepo, id entity.Id) error { return err } if len(refs) > 1 { - return NewErrMultipleMatchBug(refsToIds(refs)) + return NewErrMultipleMatchBug(entity.RefsToIds(refs)) } if len(refs) == 1 { // we have the bug locally @@ -253,7 +253,7 @@ func RemoveBug(repo repository.ClockedRepo, id entity.Id) error { return err } if len(remoteRefs) > 1 { - return NewErrMultipleMatchBug(refsToIds(refs)) + return NewErrMultipleMatchBug(entity.RefsToIds(refs)) } if len(remoteRefs) == 1 { // found the bug in a remote @@ -337,22 +337,7 @@ func ListLocalIds(repo repository.Repo) ([]entity.Id, error) { return nil, err } - return refsToIds(refs), nil -} - -func refsToIds(refs []string) []entity.Id { - ids := make([]entity.Id, len(refs)) - - for i, ref := range refs { - ids[i] = refToId(ref) - } - - return ids -} - -func refToId(ref string) entity.Id { - split := strings.Split(ref, "/") - return entity.Id(split[len(split)-1]) + return entity.RefsToIds(refs), nil } // Validate check if the Bug data is valid diff --git a/entity/refs.go b/entity/refs.go new file mode 100644 index 00000000..82b1741b --- /dev/null +++ b/entity/refs.go @@ -0,0 +1,18 @@ +package entity + +import "strings" + +func RefsToIds(refs []string) []Id { + ids := make([]Id, len(refs)) + + for i, ref := range refs { + ids[i] = refToId(ref) + } + + return ids +} + +func refToId(ref string) Id { + split := strings.Split(ref, "/") + return Id(split[len(split)-1]) +} diff --git a/go.sum b/go.sum index e2f6679f..f3f5f7c6 100644 --- a/go.sum +++ b/go.sum @@ -43,6 +43,7 @@ github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= github.com/MichaelMure/go-term-text v0.2.9 h1:jUxInT3rDhl4WoJgLnmMS3hR79zigyJS1TqKFDTI6xE= github.com/MichaelMure/go-term-text v0.2.9/go.mod h1:2QSU/Nn2u41Tqoar+90RlYuhjngJPYgod7evnsYwkWc= +github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= @@ -207,6 +208,7 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -379,6 +381,7 @@ github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= diff --git a/identity/identity.go b/identity/identity.go index b7bf9e64..8182e263 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -27,6 +27,10 @@ var ErrNoIdentitySet = errors.New("No identity is set.\n" + "\"git bug user create\"") var ErrMultipleIdentitiesSet = errors.New("multiple user identities set") +func NewErrMultipleMatchIdentity(matching []entity.Id) *entity.ErrMultipleMatch { + return entity.NewErrMultipleMatch("identity", matching) +} + var _ Interface = &Identity{} var _ entity.Interface = &Identity{} @@ -175,6 +179,66 @@ func read(repo repository.Repo, ref string) (*Identity, error) { return i, nil } +// ListLocalIds list all the available local identity ids +func ListLocalIds(repo repository.Repo) ([]entity.Id, error) { + refs, err := repo.ListRefs(identityRefPattern) + if err != nil { + return nil, err + } + + return entity.RefsToIds(refs), nil +} + +// RemoveIdentity will remove a local identity from its entity.Id +func RemoveIdentity(repo repository.ClockedRepo, id entity.Id) error { + var fullMatches []string + + refs, err := repo.ListRefs(identityRefPattern + id.String()) + if err != nil { + return err + } + if len(refs) > 1 { + return NewErrMultipleMatchIdentity(entity.RefsToIds(refs)) + } + if len(refs) == 1 { + // we have the identity locally + fullMatches = append(fullMatches, refs[0]) + } + + remotes, err := repo.GetRemotes() + if err != nil { + return err + } + + for remote := range remotes { + remotePrefix := fmt.Sprintf(identityRemoteRefPattern+id.String(), remote) + remoteRefs, err := repo.ListRefs(remotePrefix) + if err != nil { + return err + } + if len(remoteRefs) > 1 { + return NewErrMultipleMatchIdentity(entity.RefsToIds(refs)) + } + if len(remoteRefs) == 1 { + // found the identity in a remote + fullMatches = append(fullMatches, remoteRefs[0]) + } + } + + if len(fullMatches) == 0 { + return ErrIdentityNotExist + } + + for _, ref := range fullMatches { + err = repo.RemoveRef(ref) + if err != nil { + return err + } + } + + return nil +} + type StreamedIdentity struct { Identity *Identity Err error diff --git a/identity/identity_test.go b/identity/identity_test.go index f9091294..baf933c8 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -4,9 +4,10 @@ import ( "encoding/json" "testing" + "github.com/stretchr/testify/require" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/repository" - "github.com/stretchr/testify/assert" ) // Test the commit and load of an Identity with multiple versions @@ -27,13 +28,13 @@ func TestIdentityCommitLoad(t *testing.T) { err := identity.Commit(mockRepo) - assert.Nil(t, err) - assert.NotEmpty(t, identity.id) + require.NoError(t, err) + require.NotEmpty(t, identity.id) loaded, err := ReadLocal(mockRepo, identity.id) - assert.Nil(t, err) + require.NoError(t, err) commitsAreSet(t, loaded) - assert.Equal(t, identity, loaded) + require.Equal(t, identity, loaded) // multiple version @@ -69,13 +70,13 @@ func TestIdentityCommitLoad(t *testing.T) { err = identity.Commit(mockRepo) - assert.Nil(t, err) - assert.NotEmpty(t, identity.id) + require.NoError(t, err) + require.NotEmpty(t, identity.id) loaded, err = ReadLocal(mockRepo, identity.id) - assert.Nil(t, err) + require.NoError(t, err) commitsAreSet(t, loaded) - assert.Equal(t, identity, loaded) + require.Equal(t, identity, loaded) // add more version @@ -99,19 +100,19 @@ func TestIdentityCommitLoad(t *testing.T) { err = identity.Commit(mockRepo) - assert.Nil(t, err) - assert.NotEmpty(t, identity.id) + require.NoError(t, err) + require.NotEmpty(t, identity.id) loaded, err = ReadLocal(mockRepo, identity.id) - assert.Nil(t, err) + require.NoError(t, err) commitsAreSet(t, loaded) - assert.Equal(t, identity, loaded) + require.Equal(t, identity, loaded) } func TestIdentityMutate(t *testing.T) { identity := NewIdentity("René Descartes", "rene.descartes@example.com") - assert.Len(t, identity.versions, 1) + require.Len(t, identity.versions, 1) identity.Mutate(func(orig Mutator) Mutator { orig.Email = "rene@descartes.fr" @@ -120,15 +121,15 @@ func TestIdentityMutate(t *testing.T) { return orig }) - assert.Len(t, identity.versions, 2) - assert.Equal(t, identity.Email(), "rene@descartes.fr") - assert.Equal(t, identity.Name(), "René") - assert.Equal(t, identity.Login(), "rene") + require.Len(t, identity.versions, 2) + require.Equal(t, identity.Email(), "rene@descartes.fr") + require.Equal(t, identity.Name(), "René") + require.Equal(t, identity.Login(), "rene") } func commitsAreSet(t *testing.T, identity *Identity) { for _, version := range identity.versions { - assert.NotEmpty(t, version.commitHash) + require.NotEmpty(t, version.commitHash) } } @@ -180,14 +181,14 @@ func TestIdentity_ValidKeysAtTime(t *testing.T) { }, } - assert.Nil(t, identity.ValidKeysAtTime(10)) - assert.Equal(t, identity.ValidKeysAtTime(100), []*Key{{PubKey: "pubkeyA"}}) - assert.Equal(t, identity.ValidKeysAtTime(140), []*Key{{PubKey: "pubkeyA"}}) - assert.Equal(t, identity.ValidKeysAtTime(200), []*Key{{PubKey: "pubkeyB"}}) - assert.Equal(t, identity.ValidKeysAtTime(201), []*Key{{PubKey: "pubkeyD"}}) - assert.Equal(t, identity.ValidKeysAtTime(202), []*Key{{PubKey: "pubkeyD"}}) - assert.Equal(t, identity.ValidKeysAtTime(300), []*Key{{PubKey: "pubkeyE"}}) - assert.Equal(t, identity.ValidKeysAtTime(3000), []*Key{{PubKey: "pubkeyE"}}) + require.Nil(t, identity.ValidKeysAtTime(10)) + require.Equal(t, identity.ValidKeysAtTime(100), []*Key{{PubKey: "pubkeyA"}}) + require.Equal(t, identity.ValidKeysAtTime(140), []*Key{{PubKey: "pubkeyA"}}) + require.Equal(t, identity.ValidKeysAtTime(200), []*Key{{PubKey: "pubkeyB"}}) + require.Equal(t, identity.ValidKeysAtTime(201), []*Key{{PubKey: "pubkeyD"}}) + require.Equal(t, identity.ValidKeysAtTime(202), []*Key{{PubKey: "pubkeyD"}}) + require.Equal(t, identity.ValidKeysAtTime(300), []*Key{{PubKey: "pubkeyE"}}) + require.Equal(t, identity.ValidKeysAtTime(3000), []*Key{{PubKey: "pubkeyE"}}) } // Test the immutable or mutable metadata search @@ -201,7 +202,7 @@ func TestMetadata(t *testing.T) { assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1") err := identity.Commit(mockRepo) - assert.NoError(t, err) + require.NoError(t, err) assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1") assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1") @@ -217,11 +218,11 @@ func TestMetadata(t *testing.T) { assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value2") err = identity.Commit(mockRepo) - assert.NoError(t, err) + require.NoError(t, err) // reload loaded, err := ReadLocal(mockRepo, identity.id) - assert.Nil(t, err) + require.NoError(t, err) assertHasKeyValue(t, loaded.ImmutableMetadata(), "key1", "value1") assertHasKeyValue(t, loaded.MutableMetadata(), "key1", "value2") @@ -229,8 +230,8 @@ func TestMetadata(t *testing.T) { func assertHasKeyValue(t *testing.T, metadata map[string]string, key, value string) { val, ok := metadata[key] - assert.True(t, ok) - assert.Equal(t, val, value) + require.True(t, ok) + require.Equal(t, val, value) } func TestJSON(t *testing.T) { @@ -248,20 +249,66 @@ func TestJSON(t *testing.T) { // commit to make sure we have an Id err := identity.Commit(mockRepo) - assert.Nil(t, err) - assert.NotEmpty(t, identity.id) + require.NoError(t, err) + require.NotEmpty(t, identity.id) // serialize data, err := json.Marshal(identity) - assert.NoError(t, err) + require.NoError(t, err) // deserialize, got a IdentityStub with the same id var i Interface i, err = UnmarshalJSON(data) - assert.NoError(t, err) - assert.Equal(t, identity.id, i.Id()) + require.NoError(t, err) + require.Equal(t, identity.id, i.Id()) // make sure we can load the identity properly i, err = ReadLocal(mockRepo, i.Id()) - assert.NoError(t, err) + require.NoError(t, err) +} + +func TestIdentityRemove(t *testing.T) { + repo := repository.CreateGoGitTestRepo(false) + remoteA := repository.CreateGoGitTestRepo(true) + remoteB := repository.CreateGoGitTestRepo(true) + defer repository.CleanupTestRepos(repo, remoteA, remoteB) + + err := repo.AddRemote("remoteA", "file://"+remoteA.GetPath()) + require.NoError(t, err) + + err = repo.AddRemote("remoteB", "file://"+remoteB.GetPath()) + require.NoError(t, err) + + // generate an identity for testing + rene := NewIdentity("René Descartes", "rene@descartes.fr") + err = rene.Commit(repo) + require.NoError(t, err) + + _, err = Push(repo, "remoteA") + require.NoError(t, err) + + _, err = Push(repo, "remoteB") + require.NoError(t, err) + + _, err = Fetch(repo, "remoteA") + require.NoError(t, err) + + _, err = Fetch(repo, "remoteB") + require.NoError(t, err) + + err = RemoveIdentity(repo, rene.Id()) + require.NoError(t, err) + + _, err = ReadLocal(repo, rene.Id()) + require.Error(t, ErrIdentityNotExist, err) + + _, err = ReadRemote(repo, "remoteA", string(rene.Id())) + require.Error(t, ErrIdentityNotExist, err) + + _, err = ReadRemote(repo, "remoteB", string(rene.Id())) + require.Error(t, ErrIdentityNotExist, err) + + ids, err := ListLocalIds(repo) + require.NoError(t, err) + require.Len(t, ids, 0) } -- cgit