diff options
author | Michael Muré <batolettre@gmail.com> | 2019-01-19 19:23:31 +0100 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2019-03-01 22:40:21 +0100 |
commit | d10c76469d40f13e27739fd363145e89bf74c3e0 (patch) | |
tree | ff613ef1ce9400f8c208d3381bd703b186958aa3 /bug | |
parent | 844616baf8dc628360942d57fd69f24e298e08da (diff) | |
download | git-bug-d10c76469d40f13e27739fd363145e89bf74c3e0.tar.gz |
identity: somewhat getting closer !
Diffstat (limited to 'bug')
-rw-r--r-- | bug/bug_actions_test.go | 149 | ||||
-rw-r--r-- | bug/bug_test.go | 6 | ||||
-rw-r--r-- | bug/op_add_comment.go | 54 | ||||
-rw-r--r-- | bug/op_add_comment_test.go | 25 | ||||
-rw-r--r-- | bug/op_create.go | 59 | ||||
-rw-r--r-- | bug/op_create_test.go | 17 | ||||
-rw-r--r-- | bug/op_edit_comment.go | 58 | ||||
-rw-r--r-- | bug/op_edit_comment_test.go | 18 | ||||
-rw-r--r-- | bug/op_label_change.go | 53 | ||||
-rw-r--r-- | bug/op_label_change_test.go | 25 | ||||
-rw-r--r-- | bug/op_noop.go | 42 | ||||
-rw-r--r-- | bug/op_noop_test.go | 25 | ||||
-rw-r--r-- | bug/op_set_metadata.go | 54 | ||||
-rw-r--r-- | bug/op_set_metadata_test.go | 19 | ||||
-rw-r--r-- | bug/op_set_status.go | 49 | ||||
-rw-r--r-- | bug/op_set_status_test.go | 25 | ||||
-rw-r--r-- | bug/op_set_title.go | 53 | ||||
-rw-r--r-- | bug/op_set_title_test.go | 25 | ||||
-rw-r--r-- | bug/operation.go | 36 | ||||
-rw-r--r-- | bug/operation_iterator_test.go | 8 | ||||
-rw-r--r-- | bug/operation_pack.go | 8 |
21 files changed, 695 insertions, 113 deletions
diff --git a/bug/bug_actions_test.go b/bug/bug_actions_test.go index 4327ae58..95ca01c9 100644 --- a/bug/bug_actions_test.go +++ b/bug/bug_actions_test.go @@ -77,17 +77,20 @@ func TestPushPull(t *testing.T) { repoA, repoB, remote := setupRepos(t) defer cleanupRepos(repoA, repoB, remote) + err := rene.Commit(repoA) + assert.NoError(t, err) + bug1, _, err := Create(rene, unix, "bug1", "message") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) // A --> remote --> B _, err = Push(repoA, "origin") - assert.Nil(t, err) + assert.NoError(t, err) err = Pull(repoB, "origin") - assert.Nil(t, err) + assert.NoError(t, err) bugs := allBugs(t, ReadAllLocalBugs(repoB)) @@ -97,15 +100,15 @@ func TestPushPull(t *testing.T) { // B --> remote --> A bug2, _, err := Create(rene, unix, "bug2", "message") - assert.Nil(t, err) + assert.NoError(t, err) err = bug2.Commit(repoB) - assert.Nil(t, err) + assert.NoError(t, err) _, err = Push(repoB, "origin") - assert.Nil(t, err) + assert.NoError(t, err) err = Pull(repoA, "origin") - assert.Nil(t, err) + assert.NoError(t, err) bugs = allBugs(t, ReadAllLocalBugs(repoA)) @@ -140,37 +143,37 @@ func _RebaseTheirs(t testing.TB) { defer cleanupRepos(repoA, repoB, remote) bug1, _, err := Create(rene, unix, "bug1", "message") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) // A --> remote _, err = Push(repoA, "origin") - assert.Nil(t, err) + assert.NoError(t, err) // remote --> B err = Pull(repoB, "origin") - assert.Nil(t, err) + assert.NoError(t, err) bug2, err := ReadLocalBug(repoB, bug1.Id()) - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message2") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message3") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message4") - assert.Nil(t, err) + assert.NoError(t, err) err = bug2.Commit(repoB) - assert.Nil(t, err) + assert.NoError(t, err) // B --> remote _, err = Push(repoB, "origin") - assert.Nil(t, err) + assert.NoError(t, err) // remote --> A err = Pull(repoA, "origin") - assert.Nil(t, err) + assert.NoError(t, err) bugs := allBugs(t, ReadAllLocalBugs(repoB)) @@ -179,7 +182,7 @@ func _RebaseTheirs(t testing.TB) { } bug3, err := ReadLocalBug(repoA, bug1.Id()) - assert.Nil(t, err) + assert.NoError(t, err) if nbOps(bug3) != 4 { t.Fatal("Unexpected number of operations") @@ -201,48 +204,48 @@ func _RebaseOurs(t testing.TB) { defer cleanupRepos(repoA, repoB, remote) bug1, _, err := Create(rene, unix, "bug1", "message") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) // A --> remote _, err = Push(repoA, "origin") - assert.Nil(t, err) + assert.NoError(t, err) // remote --> B err = Pull(repoB, "origin") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message2") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message3") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message4") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message5") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message6") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message7") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message8") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message9") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message10") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) // remote --> A err = Pull(repoA, "origin") - assert.Nil(t, err) + assert.NoError(t, err) bugs := allBugs(t, ReadAllLocalBugs(repoA)) @@ -251,7 +254,7 @@ func _RebaseOurs(t testing.TB) { } bug2, err := ReadLocalBug(repoA, bug1.Id()) - assert.Nil(t, err) + assert.NoError(t, err) if nbOps(bug2) != 10 { t.Fatal("Unexpected number of operations") @@ -282,82 +285,82 @@ func _RebaseConflict(t testing.TB) { defer cleanupRepos(repoA, repoB, remote) bug1, _, err := Create(rene, unix, "bug1", "message") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) // A --> remote _, err = Push(repoA, "origin") - assert.Nil(t, err) + assert.NoError(t, err) // remote --> B err = Pull(repoB, "origin") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message2") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message3") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message4") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message5") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message6") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message7") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message8") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message9") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug1, rene, unix, "message10") - assert.Nil(t, err) + assert.NoError(t, err) err = bug1.Commit(repoA) - assert.Nil(t, err) + assert.NoError(t, err) bug2, err := ReadLocalBug(repoB, bug1.Id()) - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message11") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message12") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message13") - assert.Nil(t, err) + assert.NoError(t, err) err = bug2.Commit(repoB) - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message14") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message15") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message16") - assert.Nil(t, err) + assert.NoError(t, err) err = bug2.Commit(repoB) - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message17") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message18") - assert.Nil(t, err) + assert.NoError(t, err) _, err = AddComment(bug2, rene, unix, "message19") - assert.Nil(t, err) + assert.NoError(t, err) err = bug2.Commit(repoB) - assert.Nil(t, err) + assert.NoError(t, err) // A --> remote _, err = Push(repoA, "origin") - assert.Nil(t, err) + assert.NoError(t, err) // remote --> B err = Pull(repoB, "origin") - assert.Nil(t, err) + assert.NoError(t, err) bugs := allBugs(t, ReadAllLocalBugs(repoB)) @@ -366,7 +369,7 @@ func _RebaseConflict(t testing.TB) { } bug3, err := ReadLocalBug(repoB, bug1.Id()) - assert.Nil(t, err) + assert.NoError(t, err) if nbOps(bug3) != 19 { t.Fatal("Unexpected number of operations") @@ -374,11 +377,11 @@ func _RebaseConflict(t testing.TB) { // B --> remote _, err = Push(repoB, "origin") - assert.Nil(t, err) + assert.NoError(t, err) // remote --> A err = Pull(repoA, "origin") - assert.Nil(t, err) + assert.NoError(t, err) bugs = allBugs(t, ReadAllLocalBugs(repoA)) @@ -387,7 +390,7 @@ func _RebaseConflict(t testing.TB) { } bug4, err := ReadLocalBug(repoA, bug1.Id()) - assert.Nil(t, err) + assert.NoError(t, err) if nbOps(bug4) != 19 { t.Fatal("Unexpected number of operations") diff --git a/bug/bug_test.go b/bug/bug_test.go index 0fd373d5..41a5b03d 100644 --- a/bug/bug_test.go +++ b/bug/bug_test.go @@ -2,7 +2,6 @@ package bug import ( "github.com/MichaelMure/git-bug/repository" - "github.com/go-test/deep" "github.com/stretchr/testify/assert" "testing" @@ -87,8 +86,5 @@ func TestBugSerialisation(t *testing.T) { } } - deep.CompareUnexportedFields = true - if diff := deep.Equal(bug1, bug2); diff != nil { - t.Fatal(diff) - } + assert.Equal(t, bug1, bug2) } diff --git a/bug/op_add_comment.go b/bug/op_add_comment.go index 23a10419..ba5d611e 100644 --- a/bug/op_add_comment.go +++ b/bug/op_add_comment.go @@ -1,10 +1,10 @@ package bug import ( + "encoding/json" "fmt" "github.com/MichaelMure/git-bug/identity" - "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" ) @@ -14,9 +14,9 @@ var _ Operation = &AddCommentOperation{} // AddCommentOperation will add a new comment in the bug type AddCommentOperation struct { OpBase - Message string `json:"message"` + Message string // TODO: change for a map[string]util.hash to store the filename ? - Files []git.Hash `json:"files"` + Files []git.Hash } func (op *AddCommentOperation) base() *OpBase { @@ -67,6 +67,54 @@ func (op *AddCommentOperation) Validate() error { return nil } +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *AddCommentOperation) MarshalJSON() ([]byte, error) { + base, err := json.Marshal(op.OpBase) + if err != nil { + return nil, err + } + + // revert back to a flat map to be able to add our own fields + var data map[string]interface{} + if err := json.Unmarshal(base, &data); err != nil { + return nil, err + } + + data["message"] = op.Message + data["files"] = op.Files + + return json.Marshal(data) +} + +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *AddCommentOperation) UnmarshalJSON(data []byte) error { + // Unmarshal OpBase and the op separately + + base := OpBase{} + err := json.Unmarshal(data, &base) + if err != nil { + return err + } + + aux := struct { + Message string `json:"message"` + Files []git.Hash `json:"files"` + }{} + + err = json.Unmarshal(data, &aux) + if err != nil { + return err + } + + op.OpBase = base + op.Message = aux.Message + op.Files = aux.Files + + return nil +} + // Sign post method for gqlgen func (op *AddCommentOperation) IsAuthored() {} diff --git a/bug/op_add_comment_test.go b/bug/op_add_comment_test.go new file mode 100644 index 00000000..a38d0228 --- /dev/null +++ b/bug/op_add_comment_test.go @@ -0,0 +1,25 @@ +package bug + +import ( + "encoding/json" + "testing" + "time" + + "github.com/MichaelMure/git-bug/identity" + "github.com/stretchr/testify/assert" +) + +func TestAddCommentSerialize(t *testing.T) { + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + before := NewAddCommentOp(rene, unix, "message", nil) + + data, err := json.Marshal(before) + assert.NoError(t, err) + + var after AddCommentOperation + err = json.Unmarshal(data, &after) + assert.NoError(t, err) + + assert.Equal(t, before, &after) +} diff --git a/bug/op_create.go b/bug/op_create.go index 01b2bf03..1d157e67 100644 --- a/bug/op_create.go +++ b/bug/op_create.go @@ -1,11 +1,11 @@ package bug import ( + "encoding/json" "fmt" "strings" "github.com/MichaelMure/git-bug/identity" - "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" ) @@ -15,9 +15,9 @@ var _ Operation = &CreateOperation{} // CreateOperation define the initial creation of a bug type CreateOperation struct { OpBase - Title string `json:"title"` - Message string `json:"message"` - Files []git.Hash `json:"files"` + Title string + Message string + Files []git.Hash } func (op *CreateOperation) base() *OpBase { @@ -83,6 +83,57 @@ func (op *CreateOperation) Validate() error { return nil } +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *CreateOperation) MarshalJSON() ([]byte, error) { + base, err := json.Marshal(op.OpBase) + if err != nil { + return nil, err + } + + // revert back to a flat map to be able to add our own fields + var data map[string]interface{} + if err := json.Unmarshal(base, &data); err != nil { + return nil, err + } + + data["title"] = op.Title + data["message"] = op.Message + data["files"] = op.Files + + return json.Marshal(data) +} + +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *CreateOperation) UnmarshalJSON(data []byte) error { + // Unmarshal OpBase and the op separately + + base := OpBase{} + err := json.Unmarshal(data, &base) + if err != nil { + return err + } + + aux := struct { + Title string `json:"title"` + Message string `json:"message"` + Files []git.Hash `json:"files"` + }{} + + err = json.Unmarshal(data, &aux) + if err != nil { + return err + } + + op.OpBase = base + op.Title = aux.Title + op.Message = aux.Message + op.Files = aux.Files + + return nil +} + // Sign post method for gqlgen func (op *CreateOperation) IsAuthored() {} diff --git a/bug/op_create_test.go b/bug/op_create_test.go index aff58acc..31693a4a 100644 --- a/bug/op_create_test.go +++ b/bug/op_create_test.go @@ -1,11 +1,13 @@ package bug import ( + "encoding/json" "testing" "time" "github.com/MichaelMure/git-bug/identity" "github.com/go-test/deep" + "github.com/stretchr/testify/assert" ) func TestCreate(t *testing.T) { @@ -45,3 +47,18 @@ func TestCreate(t *testing.T) { t.Fatal(diff) } } + +func TestCreateSerialize(t *testing.T) { + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + before := NewCreateOp(rene, unix, "title", "message", nil) + + data, err := json.Marshal(before) + assert.NoError(t, err) + + var after CreateOperation + err = json.Unmarshal(data, &after) + assert.NoError(t, err) + + assert.Equal(t, before, &after) +} diff --git a/bug/op_edit_comment.go b/bug/op_edit_comment.go index 9e0afc02..3ff16653 100644 --- a/bug/op_edit_comment.go +++ b/bug/op_edit_comment.go @@ -1,6 +1,7 @@ package bug import ( + "encoding/json" "fmt" "github.com/MichaelMure/git-bug/identity" @@ -14,9 +15,9 @@ var _ Operation = &EditCommentOperation{} // EditCommentOperation will change a comment in the bug type EditCommentOperation struct { OpBase - Target git.Hash `json:"target"` - Message string `json:"message"` - Files []git.Hash `json:"files"` + Target git.Hash + Message string + Files []git.Hash } func (op *EditCommentOperation) base() *OpBase { @@ -94,6 +95,57 @@ func (op *EditCommentOperation) Validate() error { return nil } +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *EditCommentOperation) MarshalJSON() ([]byte, error) { + base, err := json.Marshal(op.OpBase) + if err != nil { + return nil, err + } + + // revert back to a flat map to be able to add our own fields + var data map[string]interface{} + if err := json.Unmarshal(base, &data); err != nil { + return nil, err + } + + data["target"] = op.Target + data["message"] = op.Message + data["files"] = op.Files + + return json.Marshal(data) +} + +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *EditCommentOperation) UnmarshalJSON(data []byte) error { + // Unmarshal OpBase and the op separately + + base := OpBase{} + err := json.Unmarshal(data, &base) + if err != nil { + return err + } + + aux := struct { + Target git.Hash `json:"target"` + Message string `json:"message"` + Files []git.Hash `json:"files"` + }{} + + err = json.Unmarshal(data, &aux) + if err != nil { + return err + } + + op.OpBase = base + op.Target = aux.Target + op.Message = aux.Message + op.Files = aux.Files + + return nil +} + // Sign post method for gqlgen func (op *EditCommentOperation) IsAuthored() {} diff --git a/bug/op_edit_comment_test.go b/bug/op_edit_comment_test.go index 7eee2fc1..dbdf341d 100644 --- a/bug/op_edit_comment_test.go +++ b/bug/op_edit_comment_test.go @@ -1,11 +1,12 @@ package bug import ( + "encoding/json" "testing" "time" "github.com/MichaelMure/git-bug/identity" - "gotest.tools/assert" + "github.com/stretchr/testify/assert" ) func TestEdit(t *testing.T) { @@ -49,3 +50,18 @@ func TestEdit(t *testing.T) { assert.Equal(t, snapshot.Comments[0].Message, "create edited") assert.Equal(t, snapshot.Comments[1].Message, "comment edited") } + +func TestEditCommentSerialize(t *testing.T) { + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + before := NewEditCommentOp(rene, unix, "target", "message", nil) + + data, err := json.Marshal(before) + assert.NoError(t, err) + + var after EditCommentOperation + err = json.Unmarshal(data, &after) + assert.NoError(t, err) + + assert.Equal(t, before, &after) +} diff --git a/bug/op_label_change.go b/bug/op_label_change.go index 5d0b6a78..b0dd2c33 100644 --- a/bug/op_label_change.go +++ b/bug/op_label_change.go @@ -1,6 +1,7 @@ package bug import ( + "encoding/json" "fmt" "sort" @@ -15,8 +16,8 @@ var _ Operation = &LabelChangeOperation{} // LabelChangeOperation define a Bug operation to add or remove labels type LabelChangeOperation struct { OpBase - Added []Label `json:"added"` - Removed []Label `json:"removed"` + Added []Label + Removed []Label } func (op *LabelChangeOperation) base() *OpBase { @@ -99,6 +100,54 @@ func (op *LabelChangeOperation) Validate() error { return nil } +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *LabelChangeOperation) MarshalJSON() ([]byte, error) { + base, err := json.Marshal(op.OpBase) + if err != nil { + return nil, err + } + + // revert back to a flat map to be able to add our own fields + var data map[string]interface{} + if err := json.Unmarshal(base, &data); err != nil { + return nil, err + } + + data["added"] = op.Added + data["removed"] = op.Removed + + return json.Marshal(data) +} + +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *LabelChangeOperation) UnmarshalJSON(data []byte) error { + // Unmarshal OpBase and the op separately + + base := OpBase{} + err := json.Unmarshal(data, &base) + if err != nil { + return err + } + + aux := struct { + Added []Label `json:"added"` + Removed []Label `json:"removed"` + }{} + + err = json.Unmarshal(data, &aux) + if err != nil { + return err + } + + op.OpBase = base + op.Added = aux.Added + op.Removed = aux.Removed + + return nil +} + // Sign post method for gqlgen func (op *LabelChangeOperation) IsAuthored() {} diff --git a/bug/op_label_change_test.go b/bug/op_label_change_test.go new file mode 100644 index 00000000..f5550b72 --- /dev/null +++ b/bug/op_label_change_test.go @@ -0,0 +1,25 @@ +package bug + +import ( + "encoding/json" + "testing" + "time" + + "github.com/MichaelMure/git-bug/identity" + "github.com/stretchr/testify/assert" +) + +func TestLabelChangeSerialize(t *testing.T) { + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + before := NewLabelChangeOperation(rene, unix, []Label{"added"}, []Label{"removed"}) + + data, err := json.Marshal(before) + assert.NoError(t, err) + + var after LabelChangeOperation + err = json.Unmarshal(data, &after) + assert.NoError(t, err) + + assert.Equal(t, before, &after) +} diff --git a/bug/op_noop.go b/bug/op_noop.go index 410799b3..fbc112a8 100644 --- a/bug/op_noop.go +++ b/bug/op_noop.go @@ -1,6 +1,8 @@ package bug import ( + "encoding/json" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" ) @@ -30,6 +32,46 @@ func (op *NoOpOperation) Validate() error { return opBaseValidate(op, NoOpOp) } +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *NoOpOperation) MarshalJSON() ([]byte, error) { + base, err := json.Marshal(op.OpBase) + if err != nil { + return nil, err + } + + // revert back to a flat map to be able to add our own fields + var data map[string]interface{} + if err := json.Unmarshal(base, &data); err != nil { + return nil, err + } + + return json.Marshal(data) +} + +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *NoOpOperation) UnmarshalJSON(data []byte) error { + // Unmarshal OpBase and the op separately + + base := OpBase{} + err := json.Unmarshal(data, &base) + if err != nil { + return err + } + + aux := struct{}{} + + err = json.Unmarshal(data, &aux) + if err != nil { + return err + } + + op.OpBase = base + + return nil +} + // Sign post method for gqlgen func (op *NoOpOperation) IsAuthored() {} diff --git a/bug/op_noop_test.go b/bug/op_noop_test.go new file mode 100644 index 00000000..385bc914 --- /dev/null +++ b/bug/op_noop_test.go @@ -0,0 +1,25 @@ +package bug + +import ( + "encoding/json" + "testing" + "time" + + "github.com/MichaelMure/git-bug/identity" + "github.com/stretchr/testify/assert" +) + +func TestNoopSerialize(t *testing.T) { + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + before := NewNoOpOp(rene, unix) + + data, err := json.Marshal(before) + assert.NoError(t, err) + + var after NoOpOperation + err = json.Unmarshal(data, &after) + assert.NoError(t, err) + + assert.Equal(t, before, &after) +} diff --git a/bug/op_set_metadata.go b/bug/op_set_metadata.go index e18f1cb6..57b78667 100644 --- a/bug/op_set_metadata.go +++ b/bug/op_set_metadata.go @@ -1,6 +1,8 @@ package bug import ( + "encoding/json" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" ) @@ -9,8 +11,8 @@ var _ Operation = &SetMetadataOperation{} type SetMetadataOperation struct { OpBase - Target git.Hash `json:"target"` - NewMetadata map[string]string `json:"new_metadata"` + Target git.Hash + NewMetadata map[string]string } func (op *SetMetadataOperation) base() *OpBase { @@ -56,6 +58,54 @@ func (op *SetMetadataOperation) Validate() error { return nil } +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *SetMetadataOperation) MarshalJSON() ([]byte, error) { + base, err := json.Marshal(op.OpBase) + if err != nil { + return nil, err + } + + // revert back to a flat map to be able to add our own fields + var data map[string]interface{} + if err := json.Unmarshal(base, &data); err != nil { + return nil, err + } + + data["target"] = op.Target + data["new_metadata"] = op.NewMetadata + + return json.Marshal(data) +} + +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *SetMetadataOperation) UnmarshalJSON(data []byte) error { + // Unmarshal OpBase and the op separately + + base := OpBase{} + err := json.Unmarshal(data, &base) + if err != nil { + return err + } + + aux := struct { + Target git.Hash `json:"target"` + NewMetadata map[string]string `json:"new_metadata"` + }{} + + err = json.Unmarshal(data, &aux) + if err != nil { + return err + } + + op.OpBase = base + op.Target = aux.Target + op.NewMetadata = aux.NewMetadata + + return nil +} + // Sign post method for gqlgen func (op *SetMetadataOperation) IsAuthored() {} diff --git a/bug/op_set_metadata_test.go b/bug/op_set_metadata_test.go index 6e62c9a3..847164f3 100644 --- a/bug/op_set_metadata_test.go +++ b/bug/op_set_metadata_test.go @@ -1,6 +1,7 @@ package bug import ( + "encoding/json" "testing" "time" @@ -94,3 +95,21 @@ func TestSetMetadata(t *testing.T) { assert.Equal(t, commentMetadata["key2"], "value2") assert.Equal(t, commentMetadata["key3"], "value3") } + +func TestSetMetadataSerialize(t *testing.T) { + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + before := NewSetMetadataOp(rene, unix, "message", map[string]string{ + "key1": "value1", + "key2": "value2", + }) + + data, err := json.Marshal(before) + assert.NoError(t, err) + + var after SetMetadataOperation + err = json.Unmarshal(data, &after) + assert.NoError(t, err) + + assert.Equal(t, before, &after) +} diff --git a/bug/op_set_status.go b/bug/op_set_status.go index 9fc64e52..6deb1675 100644 --- a/bug/op_set_status.go +++ b/bug/op_set_status.go @@ -1,6 +1,8 @@ package bug import ( + "encoding/json" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/pkg/errors" @@ -11,7 +13,7 @@ var _ Operation = &SetStatusOperation{} // SetStatusOperation will change the status of a bug type SetStatusOperation struct { OpBase - Status Status `json:"status"` + Status Status } func (op *SetStatusOperation) base() *OpBase { @@ -54,6 +56,51 @@ func (op *SetStatusOperation) Validate() error { return nil } +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *SetStatusOperation) MarshalJSON() ([]byte, error) { + base, err := json.Marshal(op.OpBase) + if err != nil { + return nil, err + } + + // revert back to a flat map to be able to add our own fields + var data map[string]interface{} + if err := json.Unmarshal(base, &data); err != nil { + return nil, err + } + + data["status"] = op.Status + + return json.Marshal(data) +} + +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *SetStatusOperation) UnmarshalJSON(data []byte) error { + // Unmarshal OpBase and the op separately + + base := OpBase{} + err := json.Unmarshal(data, &base) + if err != nil { + return err + } + + aux := struct { + Status Status `json:"status"` + }{} + + err = json.Unmarshal(data, &aux) + if err != nil { + return err + } + + op.OpBase = base + op.Status = aux.Status + + return nil +} + // Sign post method for gqlgen func (op *SetStatusOperation) IsAuthored() {} diff --git a/bug/op_set_status_test.go b/bug/op_set_status_test.go new file mode 100644 index 00000000..2506b947 --- /dev/null +++ b/bug/op_set_status_test.go @@ -0,0 +1,25 @@ +package bug + +import ( + "encoding/json" + "testing" + "time" + + "github.com/MichaelMure/git-bug/identity" + "github.com/stretchr/testify/assert" +) + +func TestSetStatusSerialize(t *testing.T) { + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + before := NewSetStatusOp(rene, unix, ClosedStatus) + + data, err := json.Marshal(before) + assert.NoError(t, err) + + var after SetStatusOperation + err = json.Unmarshal(data, &after) + assert.NoError(t, err) + + assert.Equal(t, before, &after) +} diff --git a/bug/op_set_title.go b/bug/op_set_title.go index 3b253c06..ae6484c6 100644 --- a/bug/op_set_title.go +++ b/bug/op_set_title.go @@ -1,6 +1,7 @@ package bug import ( + "encoding/json" "fmt" "strings" @@ -15,8 +16,8 @@ var _ Operation = &SetTitleOperation{} // SetTitleOperation will change the title of a bug type SetTitleOperation struct { OpBase - Title string `json:"title"` - Was string `json:"was"` + Title string + Was string } func (op *SetTitleOperation) base() *OpBase { @@ -76,6 +77,54 @@ func (op *SetTitleOperation) Validate() error { return nil } +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *SetTitleOperation) MarshalJSON() ([]byte, error) { + base, err := json.Marshal(op.OpBase) + if err != nil { + return nil, err + } + + // revert back to a flat map to be able to add our own fields + var data map[string]interface{} + if err := json.Unmarshal(base, &data); err != nil { + return nil, err + } + + data["title"] = op.Title + data["was"] = op.Was + + return json.Marshal(data) +} + +// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op +// MarshalJSON +func (op *SetTitleOperation) UnmarshalJSON(data []byte) error { + // Unmarshal OpBase and the op separately + + base := OpBase{} + err := json.Unmarshal(data, &base) + if err != nil { + return err + } + + aux := struct { + Title string `json:"title"` + Was string `json:"was"` + }{} + + err = json.Unmarshal(data, &aux) + if err != nil { + return err + } + + op.OpBase = base + op.Title = aux.Title + op.Was = aux.Was + + return nil +} + // Sign post method for gqlgen func (op *SetTitleOperation) IsAuthored() {} diff --git a/bug/op_set_title_test.go b/bug/op_set_title_test.go new file mode 100644 index 00000000..1f730596 --- /dev/null +++ b/bug/op_set_title_test.go @@ -0,0 +1,25 @@ +package bug + +import ( + "encoding/json" + "testing" + "time" + + "github.com/MichaelMure/git-bug/identity" + "github.com/stretchr/testify/assert" +) + +func TestSetTitleSerialize(t *testing.T) { + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + before := NewSetTitleOp(rene, unix, "title", "was") + + data, err := json.Marshal(before) + assert.NoError(t, err) + + var after SetTitleOperation + err = json.Unmarshal(data, &after) + assert.NoError(t, err) + + assert.Equal(t, before, &after) +} diff --git a/bug/operation.go b/bug/operation.go index 8dec5644..cc5b0007 100644 --- a/bug/operation.go +++ b/bug/operation.go @@ -76,8 +76,6 @@ func hashOperation(op Operation) (git.Hash, error) { return base.hash, nil } -// TODO: serialization with identity - // OpBase implement the common code for all operations type OpBase struct { OperationType OperationType @@ -100,28 +98,40 @@ func newOpBase(opType OperationType, author identity.Interface, unixTime int64) } } -type opBaseJson struct { - OperationType OperationType `json:"type"` - UnixTime int64 `json:"timestamp"` - Metadata map[string]string `json:"metadata,omitempty"` -} - -func (op *OpBase) MarshalJSON() ([]byte, error) { - return json.Marshal(opBaseJson{ +func (op OpBase) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + OperationType OperationType `json:"type"` + Author identity.Interface `json:"author"` + UnixTime int64 `json:"timestamp"` + Metadata map[string]string `json:"metadata,omitempty"` + }{ OperationType: op.OperationType, + Author: op.Author, UnixTime: op.UnixTime, Metadata: op.Metadata, }) } func (op *OpBase) UnmarshalJSON(data []byte) error { - aux := opBaseJson{} + aux := struct { + OperationType OperationType `json:"type"` + Author json.RawMessage `json:"author"` + UnixTime int64 `json:"timestamp"` + Metadata map[string]string `json:"metadata,omitempty"` + }{} if err := json.Unmarshal(data, &aux); err != nil { return err } + // delegate the decoding of the identity + author, err := identity.UnmarshalJSON(aux.Author) + if err != nil { + return err + } + op.OperationType = aux.OperationType + op.Author = author op.UnixTime = aux.UnixTime op.Metadata = aux.Metadata @@ -149,10 +159,6 @@ func opBaseValidate(op Operation, opType OperationType) error { return fmt.Errorf("incorrect operation type (expected: %v, actual: %v)", opType, op.base().OperationType) } - if _, err := op.Hash(); err != nil { - return errors.Wrap(err, "op is not serializable") - } - if op.GetUnixTime() == 0 { return fmt.Errorf("time not set") } diff --git a/bug/operation_iterator_test.go b/bug/operation_iterator_test.go index b8e1bf09..e1aa8911 100644 --- a/bug/operation_iterator_test.go +++ b/bug/operation_iterator_test.go @@ -3,6 +3,8 @@ package bug import ( "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" + "github.com/stretchr/testify/assert" + "testing" "time" ) @@ -29,13 +31,15 @@ func TestOpIterator(t *testing.T) { bug1.Append(addCommentOp) bug1.Append(setStatusOp) bug1.Append(labelChangeOp) - bug1.Commit(mockRepo) + err := bug1.Commit(mockRepo) + assert.NoError(t, err) // second pack bug1.Append(setTitleOp) bug1.Append(setTitleOp) bug1.Append(setTitleOp) - bug1.Commit(mockRepo) + err = bug1.Commit(mockRepo) + assert.NoError(t, err) // staging bug1.Append(setTitleOp) diff --git a/bug/operation_pack.go b/bug/operation_pack.go index fc395d90..18b2a478 100644 --- a/bug/operation_pack.go +++ b/bug/operation_pack.go @@ -139,6 +139,14 @@ func (opp *OperationPack) Validate() error { // Write will serialize and store the OperationPack as a git blob and return // its hash func (opp *OperationPack) Write(repo repository.Repo) (git.Hash, error) { + // First, make sure that all the identities are properly Commit as well + for _, op := range opp.Operations { + err := op.base().Author.Commit(repo) + if err != nil { + return "", err + } + } + data, err := json.Marshal(opp) if err != nil { |