diff options
author | Michael Muré <batolettre@gmail.com> | 2019-01-17 02:05:50 +0100 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2019-03-01 22:35:37 +0100 |
commit | 3df4f46c71650c9d23b267c44afec16f1b759e92 (patch) | |
tree | 516540f3cd71acc0c000f1bdc2a9a9252501dacd | |
parent | 06d9c6872655b85f1a47599add92d49d570e7b2e (diff) | |
download | git-bug-3df4f46c71650c9d23b267c44afec16f1b759e92.tar.gz |
identity: add metadata support
-rw-r--r-- | identity/identity.go | 86 | ||||
-rw-r--r-- | identity/identity_test.go | 86 | ||||
-rw-r--r-- | identity/interface.go | 2 | ||||
-rw-r--r-- | identity/version.go | 26 |
4 files changed, 179 insertions, 21 deletions
diff --git a/identity/identity.go b/identity/identity.go index 0fe13d21..3d523d38 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -20,19 +20,33 @@ var ErrIdentityNotExist = errors.New("identity doesn't exist") type Identity struct { id string - Versions []Version + Versions []*Version } -func NewIdentity(name string, email string) (*Identity, error) { +func NewIdentity(name string, email string) *Identity { return &Identity{ - Versions: []Version{ + Versions: []*Version{ { Name: name, Email: email, Nonce: makeNonce(20), }, }, - }, nil + } +} + +func NewIdentityFull(name string, email string, login string, avatarUrl string) *Identity { + return &Identity{ + Versions: []*Version{ + { + Name: name, + Email: email, + Login: login, + AvatarUrl: avatarUrl, + Nonce: makeNonce(20), + }, + }, + } } type identityJson struct { @@ -84,7 +98,7 @@ func (i *Identity) Load(repo repository.Repo) error { hashes, err := repo.ListCommits(ref) - var versions []Version + var versions []*Version // TODO: this is not perfect, it might be a command invoke error if err != nil { @@ -122,7 +136,7 @@ func (i *Identity) Load(repo repository.Repo) error { // tag the version with the commit hash version.commitHash = hash - versions = append(versions, version) + versions = append(versions, &version) } i.Versions = versions @@ -149,7 +163,7 @@ func NewFromGitUser(repo repository.Repo) (*Identity, error) { return nil, errors.New("user name is not configured in git yet. Please use `git config --global user.email johndoe@example.com`") } - return NewIdentity(name, email) + return NewIdentity(name, email), nil } // BuildFromGit will query the repository for user detail and @@ -202,7 +216,7 @@ func GetIdentity(repo repository.Repo) (*Identity, error) { return Read(repo, id) } -func (i *Identity) AddVersion(version Version) { +func (i *Identity) AddVersion(version *Version) { i.Versions = append(i.Versions, version) } @@ -285,7 +299,15 @@ func (i *Identity) Validate() error { return nil } -func (i *Identity) LastVersion() Version { +func (i *Identity) firstVersion() *Version { + if len(i.Versions) <= 0 { + panic("no version at all") + } + + return i.Versions[0] +} + +func (i *Identity) lastVersion() *Version { if len(i.Versions) <= 0 { panic("no version at all") } @@ -305,27 +327,27 @@ func (i *Identity) Id() string { // Name return the last version of the name func (i *Identity) Name() string { - return i.LastVersion().Name + return i.lastVersion().Name } // Email return the last version of the email func (i *Identity) Email() string { - return i.LastVersion().Email + return i.lastVersion().Email } // Login return the last version of the login func (i *Identity) Login() string { - return i.LastVersion().Login + return i.lastVersion().Login } // Login return the last version of the Avatar URL func (i *Identity) AvatarUrl() string { - return i.LastVersion().AvatarUrl + return i.lastVersion().AvatarUrl } // Login return the last version of the valid keys func (i *Identity) Keys() []Key { - return i.LastVersion().Keys + return i.lastVersion().Keys } // IsProtected return true if the chain of git commits started to be signed. @@ -372,3 +394,39 @@ func (i *Identity) DisplayName() string { panic("invalid person data") } + +// SetMetadata store arbitrary metadata along the last defined Version. +// If the Version has been commit to git already, it won't be overwritten. +func (i *Identity) SetMetadata(key string, value string) { + i.lastVersion().SetMetadata(key, value) +} + +// ImmutableMetadata return all metadata for this Identity, accumulated from each Version. +// If multiple value are found, the first defined takes precedence. +func (i *Identity) ImmutableMetadata() map[string]string { + metadata := make(map[string]string) + + for _, version := range i.Versions { + for key, value := range version.Metadata { + if _, has := metadata[key]; !has { + metadata[key] = value + } + } + } + + return metadata +} + +// MutableMetadata return all metadata for this Identity, accumulated from each Version. +// If multiple value are found, the last defined takes precedence. +func (i *Identity) MutableMetadata() map[string]string { + metadata := make(map[string]string) + + for _, version := range i.Versions { + for key, value := range version.Metadata { + metadata[key] = value + } + } + + return metadata +} diff --git a/identity/identity_test.go b/identity/identity_test.go index 161fd56f..914126be 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -5,15 +5,16 @@ import ( "github.com/MichaelMure/git-bug/repository" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -func TestIdentityCommit(t *testing.T) { +func TestIdentityCommitLoad(t *testing.T) { mockRepo := repository.NewMockRepoForTest() // single version identity := Identity{ - Versions: []Version{ + Versions: []*Version{ { Name: "René Descartes", Email: "rene.descartes@example.com", @@ -26,10 +27,15 @@ func TestIdentityCommit(t *testing.T) { assert.Nil(t, err) assert.NotEmpty(t, identity.id) + loaded, err := Read(mockRepo, identity.id) + assert.Nil(t, err) + commitsAreSet(t, loaded) + equivalentIdentity(t, &identity, loaded) + // multiple version identity = Identity{ - Versions: []Version{ + Versions: []*Version{ { Time: 100, Name: "René Descartes", @@ -62,9 +68,14 @@ func TestIdentityCommit(t *testing.T) { assert.Nil(t, err) assert.NotEmpty(t, identity.id) + loaded, err = Read(mockRepo, identity.id) + assert.Nil(t, err) + commitsAreSet(t, loaded) + equivalentIdentity(t, &identity, loaded) + // add more version - identity.AddVersion(Version{ + identity.AddVersion(&Version{ Time: 201, Name: "René Descartes", Email: "rene.descartes@example.com", @@ -73,7 +84,7 @@ func TestIdentityCommit(t *testing.T) { }, }) - identity.AddVersion(Version{ + identity.AddVersion(&Version{ Time: 300, Name: "René Descartes", Email: "rene.descartes@example.com", @@ -86,11 +97,32 @@ func TestIdentityCommit(t *testing.T) { assert.Nil(t, err) assert.NotEmpty(t, identity.id) + + loaded, err = Read(mockRepo, identity.id) + assert.Nil(t, err) + commitsAreSet(t, loaded) + equivalentIdentity(t, &identity, loaded) +} + +func commitsAreSet(t *testing.T, identity *Identity) { + for _, version := range identity.Versions { + assert.NotEmpty(t, version.commitHash) + } +} + +func equivalentIdentity(t *testing.T, expected, actual *Identity) { + require.Equal(t, len(expected.Versions), len(actual.Versions)) + + for i, version := range expected.Versions { + actual.Versions[i].commitHash = version.commitHash + } + + assert.Equal(t, expected, actual) } func TestIdentity_ValidKeysAtTime(t *testing.T) { identity := Identity{ - Versions: []Version{ + Versions: []*Version{ { Time: 100, Name: "René Descartes", @@ -143,3 +175,45 @@ func TestIdentity_ValidKeysAtTime(t *testing.T) { assert.Equal(t, identity.ValidKeysAtTime(300), []Key{{PubKey: "pubkeyE"}}) assert.Equal(t, identity.ValidKeysAtTime(3000), []Key{{PubKey: "pubkeyE"}}) } + +func TestMetadata(t *testing.T) { + mockRepo := repository.NewMockRepoForTest() + + identity := NewIdentity("René Descartes", "rene.descartes@example.com") + + identity.SetMetadata("key1", "value1") + assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1") + assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1") + + err := identity.Commit(mockRepo) + assert.NoError(t, err) + + assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1") + assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value1") + + // try override + identity.AddVersion(&Version{ + Name: "René Descartes", + Email: "rene.descartes@example.com", + }) + + identity.SetMetadata("key1", "value2") + assertHasKeyValue(t, identity.ImmutableMetadata(), "key1", "value1") + assertHasKeyValue(t, identity.MutableMetadata(), "key1", "value2") + + err = identity.Commit(mockRepo) + assert.NoError(t, err) + + // reload + loaded, err := Read(mockRepo, identity.id) + assert.Nil(t, err) + + assertHasKeyValue(t, loaded.ImmutableMetadata(), "key1", "value1") + assertHasKeyValue(t, loaded.MutableMetadata(), "key1", "value2") +} + +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) +} diff --git a/identity/interface.go b/identity/interface.go index 058e6ec6..6489efbe 100644 --- a/identity/interface.go +++ b/identity/interface.go @@ -5,6 +5,8 @@ import ( ) type Interface interface { + Id() string + Name() string Email() string Login() string diff --git a/identity/version.go b/identity/version.go index 3e84ece3..bc4561d9 100644 --- a/identity/version.go +++ b/identity/version.go @@ -12,7 +12,7 @@ import ( "github.com/MichaelMure/git-bug/util/text" ) -// Version is a complete set of informations about an Identity at a point in time. +// Version is a complete set of information about an Identity at a point in time. type Version struct { // Private field so not serialized commitHash git.Hash @@ -35,6 +35,9 @@ type Version struct { // It has no functional purpose and should be ignored. // It is advised to fill this array if there is not enough entropy, e.g. if there is no keys. Nonce []byte `json:"nonce,omitempty"` + + // A set of arbitrary key/value to store metadata about a version or about an Identity in general. + Metadata map[string]string `json:"metadata,omitempty"` } func (v *Version) Validate() error { @@ -103,3 +106,24 @@ func makeNonce(len int) []byte { } return result } + +// SetMetadata store arbitrary metadata about a version or an Identity in general +// If the Version has been commit to git already, it won't be overwritten. +func (v *Version) SetMetadata(key string, value string) { + if v.Metadata == nil { + v.Metadata = make(map[string]string) + } + + v.Metadata[key] = value +} + +// GetMetadata retrieve arbitrary metadata about the Version +func (v *Version) GetMetadata(key string) (string, bool) { + val, ok := v.Metadata[key] + return val, ok +} + +// AllMetadata return all metadata for this Identity +func (v *Version) AllMetadata() map[string]string { + return v.Metadata +} |