From 794d014fae9a78bd8664e6628a20902bd6dc767a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Mur=C3=A9?= Date: Fri, 28 Sep 2018 23:51:47 +0200 Subject: [PATCH] bug: define a hash-based identifier for an operation --- bug/bug_test.go | 3 +++ bug/op_add_comment.go | 4 ++++ bug/op_create.go | 4 ++++ bug/op_label_change.go | 5 +++++ bug/op_set_status.go | 5 +++++ bug/op_set_title.go | 5 +++++ bug/operation.go | 40 ++++++++++++++++++++++++++++++++++------ bug/operation_pack.go | 3 +++ tests/graphql_test.go | 2 +- 9 files changed, 64 insertions(+), 7 deletions(-) diff --git a/bug/bug_test.go b/bug/bug_test.go index d85db6d2c705c4341fa99921890494b634ef931d..6504da1a0a7f3d0a298eefaea92c2f83f181c701 100644 --- a/bug/bug_test.go +++ b/bug/bug_test.go @@ -74,6 +74,9 @@ func TestBugSerialisation(t *testing.T) { // ignore some fields bug2.packs[0].commitHash = bug1.packs[0].commitHash + for i := range bug1.packs[0].Operations { + bug2.packs[0].Operations[i].base().hash = bug1.packs[0].Operations[i].base().hash + } deep.CompareUnexportedFields = true if diff := deep.Equal(bug1, bug2); diff != nil { diff --git a/bug/op_add_comment.go b/bug/op_add_comment.go index 0a3a5a37961b99ea7df7e42c9d71897a1425d084..300609fba7ad8df1e49dd33a703c21020f4030bb 100644 --- a/bug/op_add_comment.go +++ b/bug/op_add_comment.go @@ -22,6 +22,10 @@ func (op AddCommentOperation) base() *OpBase { return op.OpBase } +func (op AddCommentOperation) Hash() (git.Hash, error) { + return hashOperation(op) +} + func (op AddCommentOperation) Apply(snapshot Snapshot) Snapshot { comment := Comment{ Message: op.Message, diff --git a/bug/op_create.go b/bug/op_create.go index 2852a519e517123285c38624b764cb10ffc90bcb..c65b3bd8a235f3b630108c29474e401f1d4cb655 100644 --- a/bug/op_create.go +++ b/bug/op_create.go @@ -23,6 +23,10 @@ func (op CreateOperation) base() *OpBase { return op.OpBase } +func (op CreateOperation) Hash() (git.Hash, error) { + return hashOperation(op) +} + func (op CreateOperation) Apply(snapshot Snapshot) Snapshot { snapshot.Title = op.Title snapshot.Comments = []Comment{ diff --git a/bug/op_label_change.go b/bug/op_label_change.go index 120671fb38352b070dbea6915b3f339268840ac1..c245d1a544658a99a64431b3c99d5fc15fb4d73c 100644 --- a/bug/op_label_change.go +++ b/bug/op_label_change.go @@ -4,6 +4,7 @@ import ( "fmt" "sort" + "github.com/MichaelMure/git-bug/util/git" "github.com/pkg/errors" ) @@ -20,6 +21,10 @@ func (op LabelChangeOperation) base() *OpBase { return op.OpBase } +func (op LabelChangeOperation) Hash() (git.Hash, error) { + return hashOperation(op) +} + // Apply apply the operation func (op LabelChangeOperation) Apply(snapshot Snapshot) Snapshot { // Add in the set diff --git a/bug/op_set_status.go b/bug/op_set_status.go index d6df3da4dd60f34bddeb82907afd90aac2f0c1f7..19af46c26d84cfaa1fa8e5ca334351a8f08e6fb2 100644 --- a/bug/op_set_status.go +++ b/bug/op_set_status.go @@ -1,6 +1,7 @@ package bug import ( + "github.com/MichaelMure/git-bug/util/git" "github.com/pkg/errors" ) @@ -17,6 +18,10 @@ func (op SetStatusOperation) base() *OpBase { return op.OpBase } +func (op SetStatusOperation) Hash() (git.Hash, error) { + return hashOperation(op) +} + func (op SetStatusOperation) Apply(snapshot Snapshot) Snapshot { snapshot.Status = op.Status diff --git a/bug/op_set_title.go b/bug/op_set_title.go index e8c5caf889d85e012a52ecb247aad0f1f05a7831..a4912143062c61d39b5e53dcc72cef3eb838c0bb 100644 --- a/bug/op_set_title.go +++ b/bug/op_set_title.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" ) @@ -21,6 +22,10 @@ func (op SetTitleOperation) base() *OpBase { return op.OpBase } +func (op SetTitleOperation) Hash() (git.Hash, error) { + return hashOperation(op) +} + func (op SetTitleOperation) Apply(snapshot Snapshot) Snapshot { snapshot.Title = op.Title diff --git a/bug/operation.go b/bug/operation.go index cd4094dc4d772fb6b04cdbaffab78bf3e386d764..4c6f2e5a3d2c822b686d21598db0c7e2fbc40556 100644 --- a/bug/operation.go +++ b/bug/operation.go @@ -1,11 +1,13 @@ package bug import ( - "github.com/MichaelMure/git-bug/util/git" - "github.com/pkg/errors" - + "crypto/sha256" + "encoding/json" "fmt" "time" + + "github.com/MichaelMure/git-bug/util/git" + "github.com/pkg/errors" ) // OperationType is an operation type identifier @@ -24,6 +26,8 @@ const ( type Operation interface { // base return the OpBase of the Operation, for package internal use base() *OpBase + // Hash return the hash of the operation + Hash() (git.Hash, error) // Time return the time when the operation was added Time() time.Time // GetUnixTime return the unix timestamp when the operation was added @@ -40,11 +44,35 @@ type Operation interface { GetMetadata(key string) (string, bool) } +func hashRaw(data []byte) git.Hash { + hasher := sha256.New() + return git.Hash(fmt.Sprintf("%x", hasher.Sum(data))) +} + +// hash compute the hash of the serialized operation +func hashOperation(op Operation) (git.Hash, error) { + base := op.base() + + if base.hash != "" { + return base.hash, nil + } + + data, err := json.Marshal(op) + if err != nil { + return "", err + } + + base.hash = hashRaw(data) + + return base.hash, nil +} + // OpBase implement the common code for all operations type OpBase struct { - OperationType OperationType `json:"type"` - Author Person `json:"author"` - UnixTime int64 `json:"timestamp"` + OperationType OperationType `json:"type"` + Author Person `json:"author"` + UnixTime int64 `json:"timestamp"` + hash git.Hash Metadata map[string]string `json:"metadata,omitempty"` } diff --git a/bug/operation_pack.go b/bug/operation_pack.go index 2da8bee06e37904173da177d674ccaedac7df140..5238ea6081bf0a955aa80f18a091a33b3be63276 100644 --- a/bug/operation_pack.go +++ b/bug/operation_pack.go @@ -62,6 +62,9 @@ func (opp *OperationPack) UnmarshalJSON(data []byte) error { return err } + // Compute the hash of the operation + op.base().hash = hashRaw(raw) + opp.Operations = append(opp.Operations, op) } diff --git a/tests/graphql_test.go b/tests/graphql_test.go index c6dcd9e069d6e615a01f749a9006a236bdca8e4d..77008628937716a3679f17dd0c8d3d28ad36f7bd 100644 --- a/tests/graphql_test.go +++ b/tests/graphql_test.go @@ -111,7 +111,7 @@ func TestQueries(t *testing.T) { Nodes []struct { Author Person CreatedAt string `json:"createdAt"` - HumandId string `json:"humanId"` + HumanId string `json:"humanId"` Id string LastEdit string `json:"lastEdit"` Status string