aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Muré <batolettre@gmail.com>2019-01-17 02:05:50 +0100
committerMichael Muré <batolettre@gmail.com>2019-03-01 22:35:37 +0100
commit3df4f46c71650c9d23b267c44afec16f1b759e92 (patch)
tree516540f3cd71acc0c000f1bdc2a9a9252501dacd
parent06d9c6872655b85f1a47599add92d49d570e7b2e (diff)
downloadgit-bug-3df4f46c71650c9d23b267c44afec16f1b759e92.tar.gz
identity: add metadata support
-rw-r--r--identity/identity.go86
-rw-r--r--identity/identity_test.go86
-rw-r--r--identity/interface.go2
-rw-r--r--identity/version.go26
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
+}