From feab9412dffe5772048aad29893c4cb01d566387 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Wed, 21 Nov 2018 18:56:12 +0100 Subject: WIP identity in git --- bug/bug_actions.go | 5 +++ bug/bug_actions_test.go | 2 +- bug/comment.go | 3 +- bug/op_add_comment.go | 8 ++-- bug/op_create.go | 8 ++-- bug/op_create_test.go | 6 +-- bug/op_edit_comment.go | 8 ++-- bug/op_edit_comment_test.go | 6 +-- bug/op_label_change.go | 8 ++-- bug/op_noop.go | 9 ++-- bug/op_set_metadata.go | 9 ++-- bug/op_set_metadata_test.go | 6 +-- bug/op_set_status.go | 9 ++-- bug/op_set_title.go | 8 ++-- bug/operation.go | 50 ++++++++++++++++++---- bug/operation_iterator_test.go | 7 +--- bug/operation_pack.go | 31 +++++++++----- bug/operation_test.go | 11 ++--- bug/person.go | 95 ------------------------------------------ bug/snapshot.go | 3 +- bug/timeline.go | 5 ++- 21 files changed, 132 insertions(+), 165 deletions(-) delete mode 100644 bug/person.go (limited to 'bug') diff --git a/bug/bug_actions.go b/bug/bug_actions.go index 487ba25e..a21db826 100644 --- a/bug/bug_actions.go +++ b/bug/bug_actions.go @@ -35,6 +35,11 @@ func Pull(repo repository.ClockedRepo, remote string) error { if merge.Err != nil { return merge.Err } + if merge.Status == MergeStatusInvalid { + // Not awesome: simply output the merge failure here as this function + // is only used in tests for now. + fmt.Println(merge) + } } return nil diff --git a/bug/bug_actions_test.go b/bug/bug_actions_test.go index a60e5c68..4327ae58 100644 --- a/bug/bug_actions_test.go +++ b/bug/bug_actions_test.go @@ -50,7 +50,7 @@ func cleanupRepo(repo repository.Repo) error { func setupRepos(t testing.TB) (repoA, repoB, remote *repository.GitRepo) { repoA = createRepo(false) repoB = createRepo(false) - remote = createRepo(true) + remote = createRepo(false) remoteAddr := "file://" + remote.GetPath() diff --git a/bug/comment.go b/bug/comment.go index 67936634..84d34299 100644 --- a/bug/comment.go +++ b/bug/comment.go @@ -1,13 +1,14 @@ package bug import ( + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/dustin/go-humanize" ) // Comment represent a comment in a Bug type Comment struct { - Author Person + Author identity.Interface Message string Files []git.Hash diff --git a/bug/op_add_comment.go b/bug/op_add_comment.go index 2d6fb21a..23a10419 100644 --- a/bug/op_add_comment.go +++ b/bug/op_add_comment.go @@ -3,6 +3,8 @@ package bug import ( "fmt" + "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" ) @@ -68,7 +70,7 @@ func (op *AddCommentOperation) Validate() error { // Sign post method for gqlgen func (op *AddCommentOperation) IsAuthored() {} -func NewAddCommentOp(author Person, unixTime int64, message string, files []git.Hash) *AddCommentOperation { +func NewAddCommentOp(author identity.Interface, unixTime int64, message string, files []git.Hash) *AddCommentOperation { return &AddCommentOperation{ OpBase: newOpBase(AddCommentOp, author, unixTime), Message: message, @@ -82,11 +84,11 @@ type AddCommentTimelineItem struct { } // Convenience function to apply the operation -func AddComment(b Interface, author Person, unixTime int64, message string) (*AddCommentOperation, error) { +func AddComment(b Interface, author identity.Interface, unixTime int64, message string) (*AddCommentOperation, error) { return AddCommentWithFiles(b, author, unixTime, message, nil) } -func AddCommentWithFiles(b Interface, author Person, unixTime int64, message string, files []git.Hash) (*AddCommentOperation, error) { +func AddCommentWithFiles(b Interface, author identity.Interface, unixTime int64, message string, files []git.Hash) (*AddCommentOperation, error) { addCommentOp := NewAddCommentOp(author, unixTime, message, files) if err := addCommentOp.Validate(); err != nil { return nil, err diff --git a/bug/op_create.go b/bug/op_create.go index 3816d8b7..01b2bf03 100644 --- a/bug/op_create.go +++ b/bug/op_create.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" + "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" ) @@ -84,7 +86,7 @@ func (op *CreateOperation) Validate() error { // Sign post method for gqlgen func (op *CreateOperation) IsAuthored() {} -func NewCreateOp(author Person, unixTime int64, title, message string, files []git.Hash) *CreateOperation { +func NewCreateOp(author identity.Interface, unixTime int64, title, message string, files []git.Hash) *CreateOperation { return &CreateOperation{ OpBase: newOpBase(CreateOp, author, unixTime), Title: title, @@ -99,11 +101,11 @@ type CreateTimelineItem struct { } // Convenience function to apply the operation -func Create(author Person, unixTime int64, title, message string) (*Bug, *CreateOperation, error) { +func Create(author identity.Interface, unixTime int64, title, message string) (*Bug, *CreateOperation, error) { return CreateWithFiles(author, unixTime, title, message, nil) } -func CreateWithFiles(author Person, unixTime int64, title, message string, files []git.Hash) (*Bug, *CreateOperation, error) { +func CreateWithFiles(author identity.Interface, unixTime int64, title, message string, files []git.Hash) (*Bug, *CreateOperation, error) { newBug := NewBug() createOp := NewCreateOp(author, unixTime, title, message, files) diff --git a/bug/op_create_test.go b/bug/op_create_test.go index d74051ec..227dea27 100644 --- a/bug/op_create_test.go +++ b/bug/op_create_test.go @@ -4,16 +4,14 @@ import ( "testing" "time" + "github.com/MichaelMure/git-bug/identity" "github.com/go-test/deep" ) func TestCreate(t *testing.T) { snapshot := Snapshot{} - var rene = Person{ - Name: "René Descartes", - Email: "rene@descartes.fr", - } + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") unix := time.Now().Unix() diff --git a/bug/op_edit_comment.go b/bug/op_edit_comment.go index bc87310a..9e0afc02 100644 --- a/bug/op_edit_comment.go +++ b/bug/op_edit_comment.go @@ -3,6 +3,8 @@ package bug import ( "fmt" + "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" ) @@ -95,7 +97,7 @@ func (op *EditCommentOperation) Validate() error { // Sign post method for gqlgen func (op *EditCommentOperation) IsAuthored() {} -func NewEditCommentOp(author Person, unixTime int64, target git.Hash, message string, files []git.Hash) *EditCommentOperation { +func NewEditCommentOp(author identity.Interface, unixTime int64, target git.Hash, message string, files []git.Hash) *EditCommentOperation { return &EditCommentOperation{ OpBase: newOpBase(EditCommentOp, author, unixTime), Target: target, @@ -105,11 +107,11 @@ func NewEditCommentOp(author Person, unixTime int64, target git.Hash, message st } // Convenience function to apply the operation -func EditComment(b Interface, author Person, unixTime int64, target git.Hash, message string) (*EditCommentOperation, error) { +func EditComment(b Interface, author identity.Interface, unixTime int64, target git.Hash, message string) (*EditCommentOperation, error) { return EditCommentWithFiles(b, author, unixTime, target, message, nil) } -func EditCommentWithFiles(b Interface, author Person, unixTime int64, target git.Hash, message string, files []git.Hash) (*EditCommentOperation, error) { +func EditCommentWithFiles(b Interface, author identity.Interface, unixTime int64, target git.Hash, message string, files []git.Hash) (*EditCommentOperation, error) { editCommentOp := NewEditCommentOp(author, unixTime, target, message, files) if err := editCommentOp.Validate(); err != nil { return nil, err diff --git a/bug/op_edit_comment_test.go b/bug/op_edit_comment_test.go index 71a7dda2..ba9bc9d5 100644 --- a/bug/op_edit_comment_test.go +++ b/bug/op_edit_comment_test.go @@ -4,16 +4,14 @@ import ( "testing" "time" + "github.com/MichaelMure/git-bug/identity" "gotest.tools/assert" ) func TestEdit(t *testing.T) { snapshot := Snapshot{} - var rene = Person{ - Name: "René Descartes", - Email: "rene@descartes.fr", - } + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") unix := time.Now().Unix() diff --git a/bug/op_label_change.go b/bug/op_label_change.go index d7aab06b..5d0b6a78 100644 --- a/bug/op_label_change.go +++ b/bug/op_label_change.go @@ -4,6 +4,8 @@ import ( "fmt" "sort" + "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/git" "github.com/pkg/errors" ) @@ -100,7 +102,7 @@ func (op *LabelChangeOperation) Validate() error { // Sign post method for gqlgen func (op *LabelChangeOperation) IsAuthored() {} -func NewLabelChangeOperation(author Person, unixTime int64, added, removed []Label) *LabelChangeOperation { +func NewLabelChangeOperation(author identity.Interface, unixTime int64, added, removed []Label) *LabelChangeOperation { return &LabelChangeOperation{ OpBase: newOpBase(LabelChangeOp, author, unixTime), Added: added, @@ -110,7 +112,7 @@ func NewLabelChangeOperation(author Person, unixTime int64, added, removed []Lab type LabelChangeTimelineItem struct { hash git.Hash - Author Person + Author identity.Interface UnixTime Timestamp Added []Label Removed []Label @@ -121,7 +123,7 @@ func (l LabelChangeTimelineItem) Hash() git.Hash { } // ChangeLabels is a convenience function to apply the operation -func ChangeLabels(b Interface, author Person, unixTime int64, add, remove []string) ([]LabelChangeResult, *LabelChangeOperation, error) { +func ChangeLabels(b Interface, author identity.Interface, unixTime int64, add, remove []string) ([]LabelChangeResult, *LabelChangeOperation, error) { var added, removed []Label var results []LabelChangeResult diff --git a/bug/op_noop.go b/bug/op_noop.go index ac898dde..410799b3 100644 --- a/bug/op_noop.go +++ b/bug/op_noop.go @@ -1,6 +1,9 @@ package bug -import "github.com/MichaelMure/git-bug/util/git" +import ( + "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/git" +) var _ Operation = &NoOpOperation{} @@ -30,14 +33,14 @@ func (op *NoOpOperation) Validate() error { // Sign post method for gqlgen func (op *NoOpOperation) IsAuthored() {} -func NewNoOpOp(author Person, unixTime int64) *NoOpOperation { +func NewNoOpOp(author identity.Interface, unixTime int64) *NoOpOperation { return &NoOpOperation{ OpBase: newOpBase(NoOpOp, author, unixTime), } } // Convenience function to apply the operation -func NoOp(b Interface, author Person, unixTime int64, metadata map[string]string) (*NoOpOperation, error) { +func NoOp(b Interface, author identity.Interface, unixTime int64, metadata map[string]string) (*NoOpOperation, error) { op := NewNoOpOp(author, unixTime) for key, value := range metadata { diff --git a/bug/op_set_metadata.go b/bug/op_set_metadata.go index aac81f3b..e18f1cb6 100644 --- a/bug/op_set_metadata.go +++ b/bug/op_set_metadata.go @@ -1,6 +1,9 @@ package bug -import "github.com/MichaelMure/git-bug/util/git" +import ( + "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/git" +) var _ Operation = &SetMetadataOperation{} @@ -56,7 +59,7 @@ func (op *SetMetadataOperation) Validate() error { // Sign post method for gqlgen func (op *SetMetadataOperation) IsAuthored() {} -func NewSetMetadataOp(author Person, unixTime int64, target git.Hash, newMetadata map[string]string) *SetMetadataOperation { +func NewSetMetadataOp(author identity.Interface, unixTime int64, target git.Hash, newMetadata map[string]string) *SetMetadataOperation { return &SetMetadataOperation{ OpBase: newOpBase(SetMetadataOp, author, unixTime), Target: target, @@ -65,7 +68,7 @@ func NewSetMetadataOp(author Person, unixTime int64, target git.Hash, newMetadat } // Convenience function to apply the operation -func SetMetadata(b Interface, author Person, unixTime int64, target git.Hash, newMetadata map[string]string) (*SetMetadataOperation, error) { +func SetMetadata(b Interface, author identity.Interface, unixTime int64, target git.Hash, newMetadata map[string]string) (*SetMetadataOperation, error) { SetMetadataOp := NewSetMetadataOp(author, unixTime, target, newMetadata) if err := SetMetadataOp.Validate(); err != nil { return nil, err diff --git a/bug/op_set_metadata_test.go b/bug/op_set_metadata_test.go index 068e2bb0..c6f5c3c1 100644 --- a/bug/op_set_metadata_test.go +++ b/bug/op_set_metadata_test.go @@ -4,16 +4,14 @@ import ( "testing" "time" + "github.com/MichaelMure/git-bug/identity" "github.com/stretchr/testify/assert" ) func TestSetMetadata(t *testing.T) { snapshot := Snapshot{} - var rene = Person{ - Name: "René Descartes", - Email: "rene@descartes.fr", - } + var rene = identity.NewBare("René Descartes", "rene@descartes.fr") unix := time.Now().Unix() diff --git a/bug/op_set_status.go b/bug/op_set_status.go index 54f476cb..9fc64e52 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/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/pkg/errors" ) @@ -56,7 +57,7 @@ func (op *SetStatusOperation) Validate() error { // Sign post method for gqlgen func (op *SetStatusOperation) IsAuthored() {} -func NewSetStatusOp(author Person, unixTime int64, status Status) *SetStatusOperation { +func NewSetStatusOp(author identity.Interface, unixTime int64, status Status) *SetStatusOperation { return &SetStatusOperation{ OpBase: newOpBase(SetStatusOp, author, unixTime), Status: status, @@ -65,7 +66,7 @@ func NewSetStatusOp(author Person, unixTime int64, status Status) *SetStatusOper type SetStatusTimelineItem struct { hash git.Hash - Author Person + Author identity.Interface UnixTime Timestamp Status Status } @@ -75,7 +76,7 @@ func (s SetStatusTimelineItem) Hash() git.Hash { } // Convenience function to apply the operation -func Open(b Interface, author Person, unixTime int64) (*SetStatusOperation, error) { +func Open(b Interface, author identity.Interface, unixTime int64) (*SetStatusOperation, error) { op := NewSetStatusOp(author, unixTime, OpenStatus) if err := op.Validate(); err != nil { return nil, err @@ -85,7 +86,7 @@ func Open(b Interface, author Person, unixTime int64) (*SetStatusOperation, erro } // Convenience function to apply the operation -func Close(b Interface, author Person, unixTime int64) (*SetStatusOperation, error) { +func Close(b Interface, author identity.Interface, unixTime int64) (*SetStatusOperation, error) { op := NewSetStatusOp(author, unixTime, ClosedStatus) if err := op.Validate(); err != nil { return nil, err diff --git a/bug/op_set_title.go b/bug/op_set_title.go index b631ca18..3b253c06 100644 --- a/bug/op_set_title.go +++ b/bug/op_set_title.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" + "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" ) @@ -77,7 +79,7 @@ func (op *SetTitleOperation) Validate() error { // Sign post method for gqlgen func (op *SetTitleOperation) IsAuthored() {} -func NewSetTitleOp(author Person, unixTime int64, title string, was string) *SetTitleOperation { +func NewSetTitleOp(author identity.Interface, unixTime int64, title string, was string) *SetTitleOperation { return &SetTitleOperation{ OpBase: newOpBase(SetTitleOp, author, unixTime), Title: title, @@ -87,7 +89,7 @@ func NewSetTitleOp(author Person, unixTime int64, title string, was string) *Set type SetTitleTimelineItem struct { hash git.Hash - Author Person + Author identity.Interface UnixTime Timestamp Title string Was string @@ -98,7 +100,7 @@ func (s SetTitleTimelineItem) Hash() git.Hash { } // Convenience function to apply the operation -func SetTitle(b Interface, author Person, unixTime int64, title string) (*SetTitleOperation, error) { +func SetTitle(b Interface, author identity.Interface, unixTime int64, title string) (*SetTitleOperation, error) { it := NewOperationIterator(b) var lastTitleOp Operation diff --git a/bug/operation.go b/bug/operation.go index 592b5616..8dec5644 100644 --- a/bug/operation.go +++ b/bug/operation.go @@ -6,6 +6,8 @@ import ( "fmt" "time" + "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/git" "github.com/pkg/errors" ) @@ -74,21 +76,23 @@ 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 `json:"type"` - Author Person `json:"author"` - UnixTime int64 `json:"timestamp"` - Metadata map[string]string `json:"metadata,omitempty"` + OperationType OperationType + Author identity.Interface + UnixTime int64 + Metadata map[string]string // Not serialized. Store the op's hash in memory. hash git.Hash - // Not serialized. Store the extra metadata compiled from SetMetadataOperation - // in memory. + // Not serialized. Store the extra metadata in memory, + // compiled from SetMetadataOperation. extraMetadata map[string]string } // newOpBase is the constructor for an OpBase -func newOpBase(opType OperationType, author Person, unixTime int64) OpBase { +func newOpBase(opType OperationType, author identity.Interface, unixTime int64) OpBase { return OpBase{ OperationType: opType, Author: author, @@ -96,6 +100,34 @@ func newOpBase(opType OperationType, author Person, unixTime int64) OpBase { } } +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{ + OperationType: op.OperationType, + UnixTime: op.UnixTime, + Metadata: op.Metadata, + }) +} + +func (op *OpBase) UnmarshalJSON(data []byte) error { + aux := opBaseJson{} + + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + + op.OperationType = aux.OperationType + op.UnixTime = aux.UnixTime + op.Metadata = aux.Metadata + + return nil +} + // Time return the time when the operation was added func (op *OpBase) Time() time.Time { return time.Unix(op.UnixTime, 0) @@ -125,6 +157,10 @@ func opBaseValidate(op Operation, opType OperationType) error { return fmt.Errorf("time not set") } + if op.base().Author == nil { + return fmt.Errorf("author not set") + } + if err := op.base().Author.Validate(); err != nil { return errors.Wrap(err, "author") } diff --git a/bug/operation_iterator_test.go b/bug/operation_iterator_test.go index 506cc94f..6b32cfc4 100644 --- a/bug/operation_iterator_test.go +++ b/bug/operation_iterator_test.go @@ -1,17 +1,14 @@ package bug import ( + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "testing" "time" ) var ( - rene = Person{ - Name: "René Descartes", - Email: "rene@descartes.fr", - } - + rene = identity.NewBare("René Descartes", "rene@descartes.fr") unix = time.Now().Unix() createOp = NewCreateOp(rene, unix, "title", "message", nil) diff --git a/bug/operation_pack.go b/bug/operation_pack.go index f33d94bf..fc395d90 100644 --- a/bug/operation_pack.go +++ b/bug/operation_pack.go @@ -20,7 +20,7 @@ const formatVersion = 1 type OperationPack struct { Operations []Operation - // Private field so not serialized by gob + // Private field so not serialized commitHash git.Hash } @@ -57,6 +57,7 @@ func (opp *OperationPack) UnmarshalJSON(data []byte) error { return err } + // delegate to specialized unmarshal function op, err := opp.unmarshalOp(raw, t.OperationType) if err != nil { return err @@ -73,28 +74,36 @@ func (opp *OperationPack) UnmarshalJSON(data []byte) error { func (opp *OperationPack) unmarshalOp(raw []byte, _type OperationType) (Operation, error) { switch _type { + case AddCommentOp: + op := &AddCommentOperation{} + err := json.Unmarshal(raw, &op) + return op, err case CreateOp: op := &CreateOperation{} err := json.Unmarshal(raw, &op) return op, err - case SetTitleOp: - op := &SetTitleOperation{} + case EditCommentOp: + op := &EditCommentOperation{} err := json.Unmarshal(raw, &op) return op, err - case AddCommentOp: - op := &AddCommentOperation{} + case LabelChangeOp: + op := &LabelChangeOperation{} err := json.Unmarshal(raw, &op) return op, err - case SetStatusOp: - op := &SetStatusOperation{} + case NoOpOp: + op := &NoOpOperation{} err := json.Unmarshal(raw, &op) return op, err - case LabelChangeOp: - op := &LabelChangeOperation{} + case SetMetadataOp: + op := &SetMetadataOperation{} err := json.Unmarshal(raw, &op) return op, err - case EditCommentOp: - op := &EditCommentOperation{} + case SetStatusOp: + op := &SetStatusOperation{} + err := json.Unmarshal(raw, &op) + return op, err + case SetTitleOp: + op := &SetTitleOperation{} err := json.Unmarshal(raw, &op) return op, err default: diff --git a/bug/operation_test.go b/bug/operation_test.go index 255d6d98..0e2afc6c 100644 --- a/bug/operation_test.go +++ b/bug/operation_test.go @@ -3,6 +3,7 @@ package bug import ( "testing" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/git" "github.com/stretchr/testify/require" @@ -25,11 +26,11 @@ func TestValidate(t *testing.T) { bad := []Operation{ // opbase - NewSetStatusOp(Person{Name: "", Email: "rene@descartes.fr"}, unix, ClosedStatus), - NewSetStatusOp(Person{Name: "René Descartes\u001b", Email: "rene@descartes.fr"}, unix, ClosedStatus), - NewSetStatusOp(Person{Name: "René Descartes", Email: "rene@descartes.fr\u001b"}, unix, ClosedStatus), - NewSetStatusOp(Person{Name: "René \nDescartes", Email: "rene@descartes.fr"}, unix, ClosedStatus), - NewSetStatusOp(Person{Name: "René Descartes", Email: "rene@\ndescartes.fr"}, unix, ClosedStatus), + NewSetStatusOp(identity.NewBare("", "rene@descartes.fr"), unix, ClosedStatus), + NewSetStatusOp(identity.NewBare("René Descartes\u001b", "rene@descartes.fr"), unix, ClosedStatus), + NewSetStatusOp(identity.NewBare("René Descartes", "rene@descartes.fr\u001b"), unix, ClosedStatus), + NewSetStatusOp(identity.NewBare("René \nDescartes", "rene@descartes.fr"), unix, ClosedStatus), + NewSetStatusOp(identity.NewBare("René Descartes", "rene@\ndescartes.fr"), unix, ClosedStatus), &CreateOperation{OpBase: OpBase{ Author: rene, UnixTime: 0, diff --git a/bug/person.go b/bug/person.go deleted file mode 100644 index 449e2262..00000000 --- a/bug/person.go +++ /dev/null @@ -1,95 +0,0 @@ -package bug - -import ( - "errors" - "fmt" - "strings" - - "github.com/MichaelMure/git-bug/repository" - "github.com/MichaelMure/git-bug/util/text" -) - -type Person struct { - Name string `json:"name"` - Email string `json:"email"` - Login string `json:"login"` - AvatarUrl string `json:"avatar_url"` -} - -// GetUser will query the repository for user detail and build the corresponding Person -func GetUser(repo repository.Repo) (Person, error) { - name, err := repo.GetUserName() - if err != nil { - return Person{}, err - } - if name == "" { - return Person{}, errors.New("User name is not configured in git yet. Please use `git config --global user.name \"John Doe\"`") - } - - email, err := repo.GetUserEmail() - if err != nil { - return Person{}, err - } - if email == "" { - return Person{}, errors.New("User name is not configured in git yet. Please use `git config --global user.email johndoe@example.com`") - } - - return Person{Name: name, Email: email}, nil -} - -// Match tell is the Person match the given query string -func (p Person) Match(query string) bool { - query = strings.ToLower(query) - - return strings.Contains(strings.ToLower(p.Name), query) || - strings.Contains(strings.ToLower(p.Login), query) -} - -func (p Person) Validate() error { - if text.Empty(p.Name) && text.Empty(p.Login) { - return fmt.Errorf("either name or login should be set") - } - - if strings.Contains(p.Name, "\n") { - return fmt.Errorf("name should be a single line") - } - - if !text.Safe(p.Name) { - return fmt.Errorf("name is not fully printable") - } - - if strings.Contains(p.Login, "\n") { - return fmt.Errorf("login should be a single line") - } - - if !text.Safe(p.Login) { - return fmt.Errorf("login is not fully printable") - } - - if strings.Contains(p.Email, "\n") { - return fmt.Errorf("email should be a single line") - } - - if !text.Safe(p.Email) { - return fmt.Errorf("email is not fully printable") - } - - if p.AvatarUrl != "" && !text.ValidUrl(p.AvatarUrl) { - return fmt.Errorf("avatarUrl is not a valid URL") - } - - return nil -} - -func (p Person) DisplayName() string { - switch { - case p.Name == "" && p.Login != "": - return p.Login - case p.Name != "" && p.Login == "": - return p.Name - case p.Name != "" && p.Login != "": - return fmt.Sprintf("%s (%s)", p.Name, p.Login) - } - - panic("invalid person data") -} diff --git a/bug/snapshot.go b/bug/snapshot.go index 72e673d4..46618ebd 100644 --- a/bug/snapshot.go +++ b/bug/snapshot.go @@ -4,6 +4,7 @@ import ( "fmt" "time" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" ) @@ -15,7 +16,7 @@ type Snapshot struct { Title string Comments []Comment Labels []Label - Author Person + Author identity.Interface CreatedAt time.Time Timeline []TimelineItem diff --git a/bug/timeline.go b/bug/timeline.go index a84c45e4..306ffa9e 100644 --- a/bug/timeline.go +++ b/bug/timeline.go @@ -3,6 +3,7 @@ package bug import ( "strings" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" ) @@ -15,7 +16,7 @@ type TimelineItem interface { type CommentHistoryStep struct { // The author of the edition, not necessarily the same as the author of the // original comment - Author Person + Author identity.Interface // The new message Message string UnixTime Timestamp @@ -24,7 +25,7 @@ type CommentHistoryStep struct { // CommentTimelineItem is a TimelineItem that holds a Comment and its edition history type CommentTimelineItem struct { hash git.Hash - Author Person + Author identity.Interface Message string Files []git.Hash CreatedAt Timestamp -- cgit From 06d9c6872655b85f1a47599add92d49d570e7b2e Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Wed, 16 Jan 2019 21:23:49 +0100 Subject: identity: implement the loading from git --- bug/bug.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'bug') diff --git a/bug/bug.go b/bug/bug.go index b6d09c50..be3e2661 100644 --- a/bug/bug.go +++ b/bug/bug.go @@ -113,13 +113,6 @@ func ReadRemoteBug(repo repository.ClockedRepo, remote string, id string) (*Bug, // readBug will read and parse a Bug from git func readBug(repo repository.ClockedRepo, ref string) (*Bug, error) { - hashes, err := repo.ListCommits(ref) - - // TODO: this is not perfect, it might be a command invoke error - if err != nil { - return nil, ErrBugNotExist - } - refSplit := strings.Split(ref, "/") id := refSplit[len(refSplit)-1] @@ -127,6 +120,13 @@ func readBug(repo repository.ClockedRepo, ref string) (*Bug, error) { return nil, fmt.Errorf("invalid ref length") } + hashes, err := repo.ListCommits(ref) + + // TODO: this is not perfect, it might be a command invoke error + if err != nil { + return nil, ErrBugNotExist + } + bug := Bug{ id: id, } -- cgit From 844616baf8dc628360942d57fd69f24e298e08da Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sat, 19 Jan 2019 16:01:06 +0100 Subject: identity: more progress and fixes --- bug/op_create_test.go | 2 +- bug/op_edit_comment_test.go | 2 +- bug/op_set_metadata_test.go | 2 +- bug/operation_iterator_test.go | 2 +- bug/operation_test.go | 10 +++++----- 5 files changed, 9 insertions(+), 9 deletions(-) (limited to 'bug') diff --git a/bug/op_create_test.go b/bug/op_create_test.go index 227dea27..aff58acc 100644 --- a/bug/op_create_test.go +++ b/bug/op_create_test.go @@ -11,7 +11,7 @@ import ( func TestCreate(t *testing.T) { snapshot := Snapshot{} - var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + var rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") unix := time.Now().Unix() diff --git a/bug/op_edit_comment_test.go b/bug/op_edit_comment_test.go index ba9bc9d5..7eee2fc1 100644 --- a/bug/op_edit_comment_test.go +++ b/bug/op_edit_comment_test.go @@ -11,7 +11,7 @@ import ( func TestEdit(t *testing.T) { snapshot := Snapshot{} - var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + var rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") unix := time.Now().Unix() diff --git a/bug/op_set_metadata_test.go b/bug/op_set_metadata_test.go index c6f5c3c1..6e62c9a3 100644 --- a/bug/op_set_metadata_test.go +++ b/bug/op_set_metadata_test.go @@ -11,7 +11,7 @@ import ( func TestSetMetadata(t *testing.T) { snapshot := Snapshot{} - var rene = identity.NewBare("René Descartes", "rene@descartes.fr") + var rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") unix := time.Now().Unix() diff --git a/bug/operation_iterator_test.go b/bug/operation_iterator_test.go index 6b32cfc4..b8e1bf09 100644 --- a/bug/operation_iterator_test.go +++ b/bug/operation_iterator_test.go @@ -8,7 +8,7 @@ import ( ) var ( - rene = identity.NewBare("René Descartes", "rene@descartes.fr") + rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") unix = time.Now().Unix() createOp = NewCreateOp(rene, unix, "title", "message", nil) diff --git a/bug/operation_test.go b/bug/operation_test.go index 0e2afc6c..083ccb1e 100644 --- a/bug/operation_test.go +++ b/bug/operation_test.go @@ -26,11 +26,11 @@ func TestValidate(t *testing.T) { bad := []Operation{ // opbase - NewSetStatusOp(identity.NewBare("", "rene@descartes.fr"), unix, ClosedStatus), - NewSetStatusOp(identity.NewBare("René Descartes\u001b", "rene@descartes.fr"), unix, ClosedStatus), - NewSetStatusOp(identity.NewBare("René Descartes", "rene@descartes.fr\u001b"), unix, ClosedStatus), - NewSetStatusOp(identity.NewBare("René \nDescartes", "rene@descartes.fr"), unix, ClosedStatus), - NewSetStatusOp(identity.NewBare("René Descartes", "rene@\ndescartes.fr"), unix, ClosedStatus), + NewSetStatusOp(identity.NewIdentity("", "rene@descartes.fr"), unix, ClosedStatus), + NewSetStatusOp(identity.NewIdentity("René Descartes\u001b", "rene@descartes.fr"), unix, ClosedStatus), + NewSetStatusOp(identity.NewIdentity("René Descartes", "rene@descartes.fr\u001b"), unix, ClosedStatus), + NewSetStatusOp(identity.NewIdentity("René \nDescartes", "rene@descartes.fr"), unix, ClosedStatus), + NewSetStatusOp(identity.NewIdentity("René Descartes", "rene@\ndescartes.fr"), unix, ClosedStatus), &CreateOperation{OpBase: OpBase{ Author: rene, UnixTime: 0, -- cgit From d10c76469d40f13e27739fd363145e89bf74c3e0 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sat, 19 Jan 2019 19:23:31 +0100 Subject: identity: somewhat getting closer ! --- bug/bug_actions_test.go | 149 +++++++++++++++++++++-------------------- bug/bug_test.go | 6 +- bug/op_add_comment.go | 54 ++++++++++++++- bug/op_add_comment_test.go | 25 +++++++ bug/op_create.go | 59 ++++++++++++++-- bug/op_create_test.go | 17 +++++ bug/op_edit_comment.go | 58 +++++++++++++++- bug/op_edit_comment_test.go | 18 ++++- bug/op_label_change.go | 53 ++++++++++++++- bug/op_label_change_test.go | 25 +++++++ bug/op_noop.go | 42 ++++++++++++ bug/op_noop_test.go | 25 +++++++ bug/op_set_metadata.go | 54 ++++++++++++++- bug/op_set_metadata_test.go | 19 ++++++ bug/op_set_status.go | 49 +++++++++++++- bug/op_set_status_test.go | 25 +++++++ bug/op_set_title.go | 53 ++++++++++++++- bug/op_set_title_test.go | 25 +++++++ bug/operation.go | 36 +++++----- bug/operation_iterator_test.go | 8 ++- bug/operation_pack.go | 8 +++ 21 files changed, 695 insertions(+), 113 deletions(-) create mode 100644 bug/op_add_comment_test.go create mode 100644 bug/op_label_change_test.go create mode 100644 bug/op_noop_test.go create mode 100644 bug/op_set_status_test.go create mode 100644 bug/op_set_title_test.go (limited to 'bug') 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 { -- cgit From 14b240af8fef269d2c1d5dde2fff192b656c50f3 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sun, 20 Jan 2019 15:41:27 +0100 Subject: identity: more cleaning and fixes after a code review --- bug/bug_actions_test.go | 2 +- bug/op_create_test.go | 10 ++-------- bug/operation_pack.go | 6 ++++++ bug/operation_pack_test.go | 25 +++++++------------------ 4 files changed, 16 insertions(+), 27 deletions(-) (limited to 'bug') diff --git a/bug/bug_actions_test.go b/bug/bug_actions_test.go index 95ca01c9..af561bf6 100644 --- a/bug/bug_actions_test.go +++ b/bug/bug_actions_test.go @@ -50,7 +50,7 @@ func cleanupRepo(repo repository.Repo) error { func setupRepos(t testing.TB) (repoA, repoB, remote *repository.GitRepo) { repoA = createRepo(false) repoB = createRepo(false) - remote = createRepo(false) + remote = createRepo(true) remoteAddr := "file://" + remote.GetPath() diff --git a/bug/op_create_test.go b/bug/op_create_test.go index 31693a4a..065b81c5 100644 --- a/bug/op_create_test.go +++ b/bug/op_create_test.go @@ -6,7 +6,6 @@ import ( "time" "github.com/MichaelMure/git-bug/identity" - "github.com/go-test/deep" "github.com/stretchr/testify/assert" ) @@ -22,9 +21,7 @@ func TestCreate(t *testing.T) { create.Apply(&snapshot) hash, err := create.Hash() - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) comment := Comment{Author: rene, Message: "message", UnixTime: Timestamp(create.UnixTime)} @@ -42,10 +39,7 @@ func TestCreate(t *testing.T) { }, } - deep.CompareUnexportedFields = true - if diff := deep.Equal(snapshot, expected); diff != nil { - t.Fatal(diff) - } + assert.Equal(t, expected, snapshot) } func TestCreateSerialize(t *testing.T) { diff --git a/bug/operation_pack.go b/bug/operation_pack.go index 18b2a478..1ffc1d1a 100644 --- a/bug/operation_pack.go +++ b/bug/operation_pack.go @@ -139,6 +139,12 @@ 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) { + // make sure we don't write invalid data + err := opp.Validate() + if err != nil { + return "", errors.Wrap(err, "validation error") + } + // First, make sure that all the identities are properly Commit as well for _, op := range opp.Operations { err := op.base().Author.Commit(repo) diff --git a/bug/operation_pack_test.go b/bug/operation_pack_test.go index 48f9f80c..8a8c7e62 100644 --- a/bug/operation_pack_test.go +++ b/bug/operation_pack_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/MichaelMure/git-bug/util/git" - "github.com/go-test/deep" + "github.com/stretchr/testify/assert" ) func TestOperationPackSerialize(t *testing.T) { @@ -21,9 +21,7 @@ func TestOperationPackSerialize(t *testing.T) { opMeta.SetMetadata("key", "value") opp.Append(opMeta) - if len(opMeta.Metadata) != 1 { - t.Fatal() - } + assert.Equal(t, 1, len(opMeta.Metadata)) opFile := NewCreateOp(rene, unix, "title", "message", []git.Hash{ "abcdef", @@ -31,23 +29,14 @@ func TestOperationPackSerialize(t *testing.T) { }) opp.Append(opFile) - if len(opFile.Files) != 2 { - t.Fatal() - } + assert.Equal(t, 2, len(opFile.Files)) data, err := json.Marshal(opp) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) var opp2 *OperationPack err = json.Unmarshal(data, &opp2) - if err != nil { - t.Fatal(err) - } - - deep.CompareUnexportedFields = false - if diff := deep.Equal(opp, opp2); diff != nil { - t.Fatal(diff) - } + + assert.NoError(t, err) + assert.Equal(t, opp, opp2) } -- cgit From 56c6147eb6012252cf0b723b9eb6d1e841fc2f94 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Fri, 1 Feb 2019 12:22:00 +0100 Subject: identity: more refactoring progress --- bug/bug.go | 9 +++++++++ bug/identity.go | 27 +++++++++++++++++++++++++++ bug/operation_iterator_test.go | 13 +++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 bug/identity.go (limited to 'bug') diff --git a/bug/bug.go b/bug/bug.go index be3e2661..aec9a12e 100644 --- a/bug/bug.go +++ b/bug/bug.go @@ -6,6 +6,8 @@ import ( "fmt" "strings" + "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/lamport" @@ -217,6 +219,13 @@ func readBug(repo repository.ClockedRepo, ref string) (*Bug, error) { bug.packs = append(bug.packs, *opp) } + // Make sure that the identities are properly loaded + resolver := identity.NewSimpleResolver(repo) + err = bug.EnsureIdentities(resolver) + if err != nil { + return nil, err + } + return &bug, nil } diff --git a/bug/identity.go b/bug/identity.go new file mode 100644 index 00000000..2eb2bcaf --- /dev/null +++ b/bug/identity.go @@ -0,0 +1,27 @@ +package bug + +import ( + "github.com/MichaelMure/git-bug/identity" +) + +// EnsureIdentities walk the graph of operations and make sure that all Identity +// are properly loaded. That is, it replace all the IdentityStub with the full +// Identity, loaded through a Resolver. +func (bug *Bug) EnsureIdentities(resolver identity.Resolver) error { + it := NewOperationIterator(bug) + + for it.Next() { + op := it.Value() + base := op.base() + + if stub, ok := base.Author.(*identity.IdentityStub); ok { + i, err := resolver.ResolveIdentity(stub.Id()) + if err != nil { + return err + } + + base.Author = i + } + } + return nil +} diff --git a/bug/operation_iterator_test.go b/bug/operation_iterator_test.go index e1aa8911..a41120e2 100644 --- a/bug/operation_iterator_test.go +++ b/bug/operation_iterator_test.go @@ -20,6 +20,19 @@ var ( labelChangeOp = NewLabelChangeOperation(rene, unix, []Label{"added"}, []Label{"removed"}) ) +func ExampleOperationIterator() { + b := NewBug() + + // add operations + + it := NewOperationIterator(b) + + for it.Next() { + // do something with each operations + _ = it.Value() + } +} + func TestOpIterator(t *testing.T) { mockRepo := repository.NewMockRepoForTest() -- cgit From 328a4e5abf3ec8ea41f89575fcfb83cf9f086c80 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sun, 3 Feb 2019 19:55:35 +0100 Subject: identity: wip push/pull --- bug/bug.go | 4 ++-- bug/bug_actions.go | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'bug') diff --git a/bug/bug.go b/bug/bug.go index aec9a12e..1717dd66 100644 --- a/bug/bug.go +++ b/bug/bug.go @@ -6,12 +6,12 @@ import ( "fmt" "strings" - "github.com/MichaelMure/git-bug/identity" + "github.com/pkg/errors" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/lamport" - "github.com/pkg/errors" ) const bugsRefPattern = "refs/bugs/" diff --git a/bug/bug_actions.go b/bug/bug_actions.go index a21db826..6b9135b0 100644 --- a/bug/bug_actions.go +++ b/bug/bug_actions.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" ) -// Fetch retrieve update from a remote +// Fetch retrieve updates from a remote // This does not change the local bugs state func Fetch(repo repository.Repo, remote string) (string, error) { remoteRefSpec := fmt.Sprintf(bugsRemoteRefPattern, remote) @@ -23,7 +23,7 @@ func Push(repo repository.Repo, remote string) (string, error) { } // Pull will do a Fetch + MergeAll -// This function won't give details on the underlying process. If you need more +// This function won't give details on the underlying process. If you need more, // use Fetch and MergeAll separately. func Pull(repo repository.ClockedRepo, remote string) error { _, err := Fetch(repo, remote) @@ -45,7 +45,13 @@ func Pull(repo repository.ClockedRepo, remote string) error { return nil } -// MergeAll will merge all the available remote bug +// MergeAll will merge all the available remote bug: +// +// - If the remote has new commit, the local bug is updated to match the same history +// (fast-forward update) +// - if the local bug has new commits but the remote don't, nothing is changed +// - if both local and remote bug have new commits (that is, we have a concurrent edition), +// new local commits are rewritten at the head of the remote history (that is, a rebase) func MergeAll(repo repository.ClockedRepo, remote string) <-chan MergeResult { out := make(chan MergeResult) -- cgit From 21048e785d976a04e26798e4a385ee675c95b88f Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Wed, 6 Feb 2019 22:06:42 +0100 Subject: identity: wip --- bug/bug.go | 4 ++-- bug/bug_test.go | 36 ++++++++++++++++++++++-------------- 2 files changed, 24 insertions(+), 16 deletions(-) (limited to 'bug') diff --git a/bug/bug.go b/bug/bug.go index 1717dd66..f84753fa 100644 --- a/bug/bug.go +++ b/bug/bug.go @@ -459,6 +459,7 @@ func (bug *Bug) Commit(repo repository.ClockedRepo) error { return err } + bug.staging.commitHash = hash bug.packs = append(bug.packs, bug.staging) bug.staging = OperationPack{} @@ -513,9 +514,8 @@ func (bug *Bug) Merge(repo repository.Repo, other Interface) (bool, error) { } ancestor, err := repo.FindCommonAncestor(bug.lastCommit, otherBug.lastCommit) - if err != nil { - return false, err + return false, errors.Wrap(err, "can't find common ancestor") } ancestorIndex := 0 diff --git a/bug/bug_test.go b/bug/bug_test.go index 41a5b03d..001bfc56 100644 --- a/bug/bug_test.go +++ b/bug/bug_test.go @@ -55,7 +55,7 @@ func TestBugValidity(t *testing.T) { } } -func TestBugSerialisation(t *testing.T) { +func TestBugCommitLoad(t *testing.T) { bug1 := NewBug() bug1.Append(createOp) @@ -69,22 +69,30 @@ func TestBugSerialisation(t *testing.T) { assert.Nil(t, err) bug2, err := ReadLocalBug(repo, bug1.Id()) - if err != nil { - t.Error(err) - } + assert.NoError(t, err) + equivalentBug(t, bug1, bug2) - // 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 - } + // add more op + + bug1.Append(setTitleOp) + bug1.Append(addCommentOp) + + err = bug1.Commit(repo) + assert.Nil(t, err) + + bug3, err := ReadLocalBug(repo, bug1.Id()) + assert.NoError(t, err) + equivalentBug(t, bug1, bug3) +} + +func equivalentBug(t *testing.T, expected, actual *Bug) { + assert.Equal(t, len(expected.packs), len(actual.packs)) - // check hashes - for i := range bug1.packs[0].Operations { - if !bug2.packs[0].Operations[i].base().hash.IsValid() { - t.Fatal("invalid hash") + for i := range expected.packs { + for j := range expected.packs[i].Operations { + actual.packs[i].Operations[j].base().hash = expected.packs[i].Operations[j].base().hash } } - assert.Equal(t, bug1, bug2) + assert.Equal(t, expected, actual) } -- cgit From cd7ed7ff9e3250c10e97fe16c934b5a6151527bb Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sat, 16 Feb 2019 13:48:46 +0100 Subject: identity: add more test for serialisation and push/pull/merge + fixes --- bug/bug_actions.go | 7 ++--- bug/bug_actions_test.go | 84 ++++++------------------------------------------- bug/operation_test.go | 3 +- 3 files changed, 13 insertions(+), 81 deletions(-) (limited to 'bug') diff --git a/bug/bug_actions.go b/bug/bug_actions.go index 6b9135b0..f214716d 100644 --- a/bug/bug_actions.go +++ b/bug/bug_actions.go @@ -23,8 +23,7 @@ func Push(repo repository.Repo, remote string) (string, error) { } // Pull will do a Fetch + MergeAll -// This function won't give details on the underlying process. If you need more, -// use Fetch and MergeAll separately. +// This function will return an error if a merge fail func Pull(repo repository.ClockedRepo, remote string) error { _, err := Fetch(repo, remote) if err != nil { @@ -36,9 +35,7 @@ func Pull(repo repository.ClockedRepo, remote string) error { return merge.Err } if merge.Status == MergeStatusInvalid { - // Not awesome: simply output the merge failure here as this function - // is only used in tests for now. - fmt.Println(merge) + return errors.Errorf("merge failure: %s", merge.Reason) } } diff --git a/bug/bug_actions_test.go b/bug/bug_actions_test.go index af561bf6..39438ec7 100644 --- a/bug/bug_actions_test.go +++ b/bug/bug_actions_test.go @@ -1,81 +1,15 @@ package bug import ( - "github.com/MichaelMure/git-bug/repository" + "github.com/MichaelMure/git-bug/util/test" "github.com/stretchr/testify/assert" - "io/ioutil" - "log" - "os" "testing" ) -func createRepo(bare bool) *repository.GitRepo { - dir, err := ioutil.TempDir("", "") - if err != nil { - log.Fatal(err) - } - - // fmt.Println("Creating repo:", dir) - - var creator func(string) (*repository.GitRepo, error) - - if bare { - creator = repository.InitBareGitRepo - } else { - creator = repository.InitGitRepo - } - - repo, err := creator(dir) - if err != nil { - log.Fatal(err) - } - - if err := repo.StoreConfig("user.name", "testuser"); err != nil { - log.Fatal("failed to set user.name for test repository: ", err) - } - if err := repo.StoreConfig("user.email", "testuser@example.com"); err != nil { - log.Fatal("failed to set user.email for test repository: ", err) - } - - return repo -} - -func cleanupRepo(repo repository.Repo) error { - path := repo.GetPath() - // fmt.Println("Cleaning repo:", path) - return os.RemoveAll(path) -} - -func setupRepos(t testing.TB) (repoA, repoB, remote *repository.GitRepo) { - repoA = createRepo(false) - repoB = createRepo(false) - remote = createRepo(true) - - remoteAddr := "file://" + remote.GetPath() - - err := repoA.AddRemote("origin", remoteAddr) - if err != nil { - t.Fatal(err) - } - - err = repoB.AddRemote("origin", remoteAddr) - if err != nil { - t.Fatal(err) - } - - return repoA, repoB, remote -} - -func cleanupRepos(repoA, repoB, remote *repository.GitRepo) { - cleanupRepo(repoA) - cleanupRepo(repoB) - cleanupRepo(remote) -} - func TestPushPull(t *testing.T) { - repoA, repoB, remote := setupRepos(t) - defer cleanupRepos(repoA, repoB, remote) + repoA, repoB, remote := test.SetupReposAndRemote(t) + defer test.CleanupRepos(repoA, repoB, remote) err := rene.Commit(repoA) assert.NoError(t, err) @@ -139,8 +73,8 @@ func BenchmarkRebaseTheirs(b *testing.B) { } func _RebaseTheirs(t testing.TB) { - repoA, repoB, remote := setupRepos(t) - defer cleanupRepos(repoA, repoB, remote) + repoA, repoB, remote := test.SetupReposAndRemote(t) + defer test.CleanupRepos(repoA, repoB, remote) bug1, _, err := Create(rene, unix, "bug1", "message") assert.NoError(t, err) @@ -200,8 +134,8 @@ func BenchmarkRebaseOurs(b *testing.B) { } func _RebaseOurs(t testing.TB) { - repoA, repoB, remote := setupRepos(t) - defer cleanupRepos(repoA, repoB, remote) + repoA, repoB, remote := test.SetupReposAndRemote(t) + defer test.CleanupRepos(repoA, repoB, remote) bug1, _, err := Create(rene, unix, "bug1", "message") assert.NoError(t, err) @@ -281,8 +215,8 @@ func BenchmarkRebaseConflict(b *testing.B) { } func _RebaseConflict(t testing.TB) { - repoA, repoB, remote := setupRepos(t) - defer cleanupRepos(repoA, repoB, remote) + repoA, repoB, remote := test.SetupReposAndRemote(t) + defer test.CleanupRepos(repoA, repoB, remote) bug1, _, err := Create(rene, unix, "bug1", "message") assert.NoError(t, err) diff --git a/bug/operation_test.go b/bug/operation_test.go index 083ccb1e..d5cb5090 100644 --- a/bug/operation_test.go +++ b/bug/operation_test.go @@ -6,6 +6,7 @@ import ( "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/git" + "github.com/MichaelMure/git-bug/util/test" "github.com/stretchr/testify/require" ) @@ -76,7 +77,7 @@ func TestMetadata(t *testing.T) { func TestHash(t *testing.T) { repos := []repository.ClockedRepo{ repository.NewMockRepoForTest(), - createRepo(false), + test.CreateRepo(false), } for _, repo := range repos { -- cgit From d2483d83dd52365741f51eca106aa18c4e8d6420 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sat, 16 Feb 2019 17:32:30 +0100 Subject: identity: I can compile again !! --- bug/bug.go | 19 ++- bug/bug_actions.go | 46 +++++++- bug/bug_actions_test.go | 259 ++++++++++++++++++++++------------------- bug/bug_test.go | 14 +++ bug/op_create_test.go | 3 +- bug/op_edit_comment_test.go | 12 +- bug/op_set_metadata_test.go | 12 +- bug/operation_iterator_test.go | 28 +++-- bug/operation_pack.go | 2 +- bug/operation_pack_test.go | 25 +++- bug/operation_test.go | 11 +- 11 files changed, 274 insertions(+), 157 deletions(-) (limited to 'bug') diff --git a/bug/bug.go b/bug/bug.go index f84753fa..f1bd1114 100644 --- a/bug/bug.go +++ b/bug/bug.go @@ -321,6 +321,11 @@ func (bug *Bug) Validate() error { return fmt.Errorf("first operation should be a Create op") } + // The bug ID should be the hash of the first commit + if len(bug.packs) > 0 && string(bug.packs[0].commitHash) != bug.id { + return fmt.Errorf("bug id should be the first commit hash") + } + // Check that there is no more CreateOp op it := NewOperationIterator(bug) createCount := 0 @@ -349,7 +354,8 @@ func (bug *Bug) HasPendingOp() bool { // Commit write the staging area in Git and move the operations to the packs func (bug *Bug) Commit(repo repository.ClockedRepo) error { - if bug.staging.IsEmpty() { + + if !bug.NeedCommit() { return fmt.Errorf("can't commit a bug with no pending operation") } @@ -466,6 +472,17 @@ func (bug *Bug) Commit(repo repository.ClockedRepo) error { return nil } +func (bug *Bug) CommitAsNeeded(repo repository.ClockedRepo) error { + if !bug.NeedCommit() { + return nil + } + return bug.Commit(repo) +} + +func (bug *Bug) NeedCommit() bool { + return !bug.staging.IsEmpty() +} + func makeMediaTree(pack OperationPack) []repository.TreeEntry { var tree []repository.TreeEntry counter := 0 diff --git a/bug/bug_actions.go b/bug/bug_actions.go index f214716d..b906b938 100644 --- a/bug/bug_actions.go +++ b/bug/bug_actions.go @@ -4,28 +4,68 @@ import ( "fmt" "strings" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "github.com/pkg/errors" ) +// Note: +// +// For the actions (fetch/push/pull/merge), this package act as a master for +// the identity package and will also drive the needed identity actions. That is, +// if bug.Push() is called, identity.Push will also be called to make sure that +// the dependant identities are also present and up to date on the remote. +// +// I'm not entirely sure this is the correct way to do it, as it might introduce +// too much complexity and hard coupling, but it does make this package easier +// to use. + // Fetch retrieve updates from a remote // This does not change the local bugs state func Fetch(repo repository.Repo, remote string) (string, error) { + stdout, err := identity.Fetch(repo, remote) + if err != nil { + return stdout, err + } + remoteRefSpec := fmt.Sprintf(bugsRemoteRefPattern, remote) fetchRefSpec := fmt.Sprintf("%s*:%s*", bugsRefPattern, remoteRefSpec) - return repo.FetchRefs(remote, fetchRefSpec) + stdout2, err := repo.FetchRefs(remote, fetchRefSpec) + + return stdout + "\n" + stdout2, err } // Push update a remote with the local changes func Push(repo repository.Repo, remote string) (string, error) { - return repo.PushRefs(remote, bugsRefPattern+"*") + stdout, err := identity.Push(repo, remote) + if err != nil { + return stdout, err + } + + stdout2, err := repo.PushRefs(remote, bugsRefPattern+"*") + + return stdout + "\n" + stdout2, err } // Pull will do a Fetch + MergeAll // This function will return an error if a merge fail func Pull(repo repository.ClockedRepo, remote string) error { - _, err := Fetch(repo, remote) + _, err := identity.Fetch(repo, remote) + if err != nil { + return err + } + + for merge := range identity.MergeAll(repo, remote) { + if merge.Err != nil { + return merge.Err + } + if merge.Status == identity.MergeStatusInvalid { + return errors.Errorf("merge failure: %s", merge.Reason) + } + } + + _, err = Fetch(repo, remote) if err != nil { return err } diff --git a/bug/bug_actions_test.go b/bug/bug_actions_test.go index 39438ec7..4d42fb1d 100644 --- a/bug/bug_actions_test.go +++ b/bug/bug_actions_test.go @@ -1,8 +1,11 @@ package bug import ( + "time" + + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/test" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "testing" ) @@ -11,20 +14,19 @@ func TestPushPull(t *testing.T) { repoA, repoB, remote := test.SetupReposAndRemote(t) defer test.CleanupRepos(repoA, repoB, remote) - err := rene.Commit(repoA) - assert.NoError(t, err) + reneA := identity.NewIdentity("René Descartes", "rene@descartes.fr") - bug1, _, err := Create(rene, unix, "bug1", "message") - assert.NoError(t, err) + bug1, _, err := Create(reneA, time.Now().Unix(), "bug1", "message") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) + require.NoError(t, err) // A --> remote --> B _, err = Push(repoA, "origin") - assert.NoError(t, err) + require.NoError(t, err) err = Pull(repoB, "origin") - assert.NoError(t, err) + require.NoError(t, err) bugs := allBugs(t, ReadAllLocalBugs(repoB)) @@ -33,16 +35,19 @@ func TestPushPull(t *testing.T) { } // B --> remote --> A - bug2, _, err := Create(rene, unix, "bug2", "message") - assert.NoError(t, err) + reneB, err := identity.ReadLocal(repoA, reneA.Id()) + require.NoError(t, err) + + bug2, _, err := Create(reneB, time.Now().Unix(), "bug2", "message") + require.NoError(t, err) err = bug2.Commit(repoB) - assert.NoError(t, err) + require.NoError(t, err) _, err = Push(repoB, "origin") - assert.NoError(t, err) + require.NoError(t, err) err = Pull(repoA, "origin") - assert.NoError(t, err) + require.NoError(t, err) bugs = allBugs(t, ReadAllLocalBugs(repoA)) @@ -76,38 +81,43 @@ func _RebaseTheirs(t testing.TB) { repoA, repoB, remote := test.SetupReposAndRemote(t) defer test.CleanupRepos(repoA, repoB, remote) - bug1, _, err := Create(rene, unix, "bug1", "message") - assert.NoError(t, err) + reneA := identity.NewIdentity("René Descartes", "rene@descartes.fr") + + bug1, _, err := Create(reneA, time.Now().Unix(), "bug1", "message") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) + require.NoError(t, err) // A --> remote _, err = Push(repoA, "origin") - assert.NoError(t, err) + require.NoError(t, err) // remote --> B err = Pull(repoB, "origin") - assert.NoError(t, err) + require.NoError(t, err) bug2, err := ReadLocalBug(repoB, bug1.Id()) - assert.NoError(t, err) - - _, err = AddComment(bug2, rene, unix, "message2") - assert.NoError(t, err) - _, err = AddComment(bug2, rene, unix, "message3") - assert.NoError(t, err) - _, err = AddComment(bug2, rene, unix, "message4") - assert.NoError(t, err) + require.NoError(t, err) + + reneB, err := identity.ReadLocal(repoA, reneA.Id()) + require.NoError(t, err) + + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message2") + require.NoError(t, err) + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message3") + require.NoError(t, err) + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message4") + require.NoError(t, err) err = bug2.Commit(repoB) - assert.NoError(t, err) + require.NoError(t, err) // B --> remote _, err = Push(repoB, "origin") - assert.NoError(t, err) + require.NoError(t, err) // remote --> A err = Pull(repoA, "origin") - assert.NoError(t, err) + require.NoError(t, err) bugs := allBugs(t, ReadAllLocalBugs(repoB)) @@ -116,7 +126,7 @@ func _RebaseTheirs(t testing.TB) { } bug3, err := ReadLocalBug(repoA, bug1.Id()) - assert.NoError(t, err) + require.NoError(t, err) if nbOps(bug3) != 4 { t.Fatal("Unexpected number of operations") @@ -137,49 +147,51 @@ func _RebaseOurs(t testing.TB) { repoA, repoB, remote := test.SetupReposAndRemote(t) defer test.CleanupRepos(repoA, repoB, remote) - bug1, _, err := Create(rene, unix, "bug1", "message") - assert.NoError(t, err) + reneA := identity.NewIdentity("René Descartes", "rene@descartes.fr") + + bug1, _, err := Create(reneA, time.Now().Unix(), "bug1", "message") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) + require.NoError(t, err) // A --> remote _, err = Push(repoA, "origin") - assert.NoError(t, err) + require.NoError(t, err) // remote --> B err = Pull(repoB, "origin") - assert.NoError(t, err) - - _, err = AddComment(bug1, rene, unix, "message2") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message3") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message4") - assert.NoError(t, err) + require.NoError(t, err) + + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message2") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message3") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message4") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) - - _, err = AddComment(bug1, rene, unix, "message5") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message6") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message7") - assert.NoError(t, err) + require.NoError(t, err) + + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message5") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message6") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message7") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) - - _, err = AddComment(bug1, rene, unix, "message8") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message9") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message10") - assert.NoError(t, err) + require.NoError(t, err) + + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message8") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message9") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message10") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) + require.NoError(t, err) // remote --> A err = Pull(repoA, "origin") - assert.NoError(t, err) + require.NoError(t, err) bugs := allBugs(t, ReadAllLocalBugs(repoA)) @@ -188,7 +200,7 @@ func _RebaseOurs(t testing.TB) { } bug2, err := ReadLocalBug(repoA, bug1.Id()) - assert.NoError(t, err) + require.NoError(t, err) if nbOps(bug2) != 10 { t.Fatal("Unexpected number of operations") @@ -218,83 +230,88 @@ func _RebaseConflict(t testing.TB) { repoA, repoB, remote := test.SetupReposAndRemote(t) defer test.CleanupRepos(repoA, repoB, remote) - bug1, _, err := Create(rene, unix, "bug1", "message") - assert.NoError(t, err) + reneA := identity.NewIdentity("René Descartes", "rene@descartes.fr") + + bug1, _, err := Create(reneA, time.Now().Unix(), "bug1", "message") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) + require.NoError(t, err) // A --> remote _, err = Push(repoA, "origin") - assert.NoError(t, err) + require.NoError(t, err) // remote --> B err = Pull(repoB, "origin") - assert.NoError(t, err) - - _, err = AddComment(bug1, rene, unix, "message2") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message3") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message4") - assert.NoError(t, err) + require.NoError(t, err) + + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message2") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message3") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message4") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) - - _, err = AddComment(bug1, rene, unix, "message5") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message6") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message7") - assert.NoError(t, err) + require.NoError(t, err) + + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message5") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message6") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message7") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) - - _, err = AddComment(bug1, rene, unix, "message8") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message9") - assert.NoError(t, err) - _, err = AddComment(bug1, rene, unix, "message10") - assert.NoError(t, err) + require.NoError(t, err) + + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message8") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message9") + require.NoError(t, err) + _, err = AddComment(bug1, reneA, time.Now().Unix(), "message10") + require.NoError(t, err) err = bug1.Commit(repoA) - assert.NoError(t, err) + require.NoError(t, err) bug2, err := ReadLocalBug(repoB, bug1.Id()) - assert.NoError(t, err) - - _, err = AddComment(bug2, rene, unix, "message11") - assert.NoError(t, err) - _, err = AddComment(bug2, rene, unix, "message12") - assert.NoError(t, err) - _, err = AddComment(bug2, rene, unix, "message13") - assert.NoError(t, err) + require.NoError(t, err) + + reneB, err := identity.ReadLocal(repoA, reneA.Id()) + require.NoError(t, err) + + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message11") + require.NoError(t, err) + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message12") + require.NoError(t, err) + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message13") + require.NoError(t, err) err = bug2.Commit(repoB) - assert.NoError(t, err) - - _, err = AddComment(bug2, rene, unix, "message14") - assert.NoError(t, err) - _, err = AddComment(bug2, rene, unix, "message15") - assert.NoError(t, err) - _, err = AddComment(bug2, rene, unix, "message16") - assert.NoError(t, err) + require.NoError(t, err) + + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message14") + require.NoError(t, err) + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message15") + require.NoError(t, err) + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message16") + require.NoError(t, err) err = bug2.Commit(repoB) - assert.NoError(t, err) - - _, err = AddComment(bug2, rene, unix, "message17") - assert.NoError(t, err) - _, err = AddComment(bug2, rene, unix, "message18") - assert.NoError(t, err) - _, err = AddComment(bug2, rene, unix, "message19") - assert.NoError(t, err) + require.NoError(t, err) + + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message17") + require.NoError(t, err) + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message18") + require.NoError(t, err) + _, err = AddComment(bug2, reneB, time.Now().Unix(), "message19") + require.NoError(t, err) err = bug2.Commit(repoB) - assert.NoError(t, err) + require.NoError(t, err) // A --> remote _, err = Push(repoA, "origin") - assert.NoError(t, err) + require.NoError(t, err) // remote --> B err = Pull(repoB, "origin") - assert.NoError(t, err) + require.NoError(t, err) bugs := allBugs(t, ReadAllLocalBugs(repoB)) @@ -303,7 +320,7 @@ func _RebaseConflict(t testing.TB) { } bug3, err := ReadLocalBug(repoB, bug1.Id()) - assert.NoError(t, err) + require.NoError(t, err) if nbOps(bug3) != 19 { t.Fatal("Unexpected number of operations") @@ -311,11 +328,11 @@ func _RebaseConflict(t testing.TB) { // B --> remote _, err = Push(repoB, "origin") - assert.NoError(t, err) + require.NoError(t, err) // remote --> A err = Pull(repoA, "origin") - assert.NoError(t, err) + require.NoError(t, err) bugs = allBugs(t, ReadAllLocalBugs(repoA)) @@ -324,7 +341,7 @@ func _RebaseConflict(t testing.TB) { } bug4, err := ReadLocalBug(repoA, bug1.Id()) - assert.NoError(t, err) + require.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 001bfc56..e104f921 100644 --- a/bug/bug_test.go +++ b/bug/bug_test.go @@ -1,6 +1,9 @@ package bug import ( + "time" + + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "github.com/stretchr/testify/assert" @@ -12,6 +15,9 @@ func TestBugId(t *testing.T) { bug1 := NewBug() + rene := identity.NewIdentity("René Descartes", "rene@descartes.fr") + createOp := NewCreateOp(rene, time.Now().Unix(), "title", "message", nil) + bug1.Append(createOp) err := bug1.Commit(mockRepo) @@ -28,6 +34,9 @@ func TestBugValidity(t *testing.T) { bug1 := NewBug() + rene := identity.NewIdentity("René Descartes", "rene@descartes.fr") + createOp := NewCreateOp(rene, time.Now().Unix(), "title", "message", nil) + if bug1.Validate() == nil { t.Fatal("Empty bug should be invalid") } @@ -58,6 +67,11 @@ func TestBugValidity(t *testing.T) { func TestBugCommitLoad(t *testing.T) { bug1 := NewBug() + rene := identity.NewIdentity("René Descartes", "rene@descartes.fr") + createOp := NewCreateOp(rene, time.Now().Unix(), "title", "message", nil) + setTitleOp := NewSetTitleOp(rene, time.Now().Unix(), "title2", "title1") + addCommentOp := NewAddCommentOp(rene, time.Now().Unix(), "message2", nil) + bug1.Append(createOp) bug1.Append(setTitleOp) bug1.Append(setTitleOp) diff --git a/bug/op_create_test.go b/bug/op_create_test.go index 065b81c5..c41c5687 100644 --- a/bug/op_create_test.go +++ b/bug/op_create_test.go @@ -12,8 +12,7 @@ import ( func TestCreate(t *testing.T) { snapshot := Snapshot{} - var rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") - + rene := identity.NewBare("René Descartes", "rene@descartes.fr") unix := time.Now().Unix() create := NewCreateOp(rene, unix, "title", "message", nil) diff --git a/bug/op_edit_comment_test.go b/bug/op_edit_comment_test.go index dbdf341d..72f8a168 100644 --- a/bug/op_edit_comment_test.go +++ b/bug/op_edit_comment_test.go @@ -7,30 +7,26 @@ import ( "github.com/MichaelMure/git-bug/identity" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestEdit(t *testing.T) { snapshot := Snapshot{} - var rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") - + rene := identity.NewBare("René Descartes", "rene@descartes.fr") unix := time.Now().Unix() create := NewCreateOp(rene, unix, "title", "create", nil) create.Apply(&snapshot) hash1, err := create.Hash() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) comment := NewAddCommentOp(rene, unix, "comment", nil) comment.Apply(&snapshot) hash2, err := comment.Hash() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) edit := NewEditCommentOp(rene, unix, hash1, "create edited", nil) edit.Apply(&snapshot) diff --git a/bug/op_set_metadata_test.go b/bug/op_set_metadata_test.go index 847164f3..a7f9f313 100644 --- a/bug/op_set_metadata_test.go +++ b/bug/op_set_metadata_test.go @@ -7,13 +7,13 @@ import ( "github.com/MichaelMure/git-bug/identity" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestSetMetadata(t *testing.T) { snapshot := Snapshot{} - var rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") - + rene := identity.NewBare("René Descartes", "rene@descartes.fr") unix := time.Now().Unix() create := NewCreateOp(rene, unix, "title", "create", nil) @@ -22,9 +22,7 @@ func TestSetMetadata(t *testing.T) { snapshot.Operations = append(snapshot.Operations, create) hash1, err := create.Hash() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) comment := NewAddCommentOp(rene, unix, "comment", nil) comment.SetMetadata("key2", "value2") @@ -32,9 +30,7 @@ func TestSetMetadata(t *testing.T) { snapshot.Operations = append(snapshot.Operations, comment) hash2, err := comment.Hash() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) op1 := NewSetMetadataOp(rene, unix, hash1, map[string]string{ "key": "override", diff --git a/bug/operation_iterator_test.go b/bug/operation_iterator_test.go index a41120e2..2865d25d 100644 --- a/bug/operation_iterator_test.go +++ b/bug/operation_iterator_test.go @@ -10,14 +10,17 @@ import ( ) var ( - rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") - unix = time.Now().Unix() - - createOp = NewCreateOp(rene, unix, "title", "message", nil) - setTitleOp = NewSetTitleOp(rene, unix, "title2", "title1") - addCommentOp = NewAddCommentOp(rene, unix, "message2", nil) - setStatusOp = NewSetStatusOp(rene, unix, ClosedStatus) - labelChangeOp = NewLabelChangeOperation(rene, unix, []Label{"added"}, []Label{"removed"}) +// Beware, don't those test data in multi-repo situation ! +// As an example, the Identity would be considered commited after a commit +// in one repo, +// rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") +// unix = time.Now().Unix() + +// createOp = NewCreateOp(rene, unix, "title", "message", nil) +// setTitleOp = NewSetTitleOp(rene, unix, "title2", "title1") +// addCommentOp = NewAddCommentOp(rene, unix, "message2", nil) +// setStatusOp = NewSetStatusOp(rene, unix, ClosedStatus) +// labelChangeOp = NewLabelChangeOperation(rene, unix, []Label{"added"}, []Label{"removed"}) ) func ExampleOperationIterator() { @@ -36,6 +39,15 @@ func ExampleOperationIterator() { func TestOpIterator(t *testing.T) { mockRepo := repository.NewMockRepoForTest() + rene := identity.NewIdentity("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + + createOp := NewCreateOp(rene, unix, "title", "message", nil) + setTitleOp := NewSetTitleOp(rene, unix, "title2", "title1") + addCommentOp := NewAddCommentOp(rene, unix, "message2", nil) + setStatusOp := NewSetStatusOp(rene, unix, ClosedStatus) + labelChangeOp := NewLabelChangeOperation(rene, unix, []Label{"added"}, []Label{"removed"}) + bug1 := NewBug() // first pack diff --git a/bug/operation_pack.go b/bug/operation_pack.go index 1ffc1d1a..55fc018e 100644 --- a/bug/operation_pack.go +++ b/bug/operation_pack.go @@ -147,7 +147,7 @@ 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) + err := op.base().Author.CommitAsNeeded(repo) if err != nil { return "", err } diff --git a/bug/operation_pack_test.go b/bug/operation_pack_test.go index 8a8c7e62..09d159af 100644 --- a/bug/operation_pack_test.go +++ b/bug/operation_pack_test.go @@ -3,27 +3,37 @@ package bug import ( "encoding/json" "testing" + "time" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestOperationPackSerialize(t *testing.T) { opp := &OperationPack{} + rene := identity.NewBare("René Descartes", "rene@descartes.fr") + createOp := NewCreateOp(rene, time.Now().Unix(), "title", "message", nil) + setTitleOp := NewSetTitleOp(rene, time.Now().Unix(), "title2", "title1") + addCommentOp := NewAddCommentOp(rene, time.Now().Unix(), "message2", nil) + setStatusOp := NewSetStatusOp(rene, time.Now().Unix(), ClosedStatus) + labelChangeOp := NewLabelChangeOperation(rene, time.Now().Unix(), []Label{"added"}, []Label{"removed"}) + opp.Append(createOp) opp.Append(setTitleOp) opp.Append(addCommentOp) opp.Append(setStatusOp) opp.Append(labelChangeOp) - opMeta := NewCreateOp(rene, unix, "title", "message", nil) + opMeta := NewSetTitleOp(rene, time.Now().Unix(), "title3", "title2") opMeta.SetMetadata("key", "value") opp.Append(opMeta) assert.Equal(t, 1, len(opMeta.Metadata)) - opFile := NewCreateOp(rene, unix, "title", "message", []git.Hash{ + opFile := NewAddCommentOp(rene, time.Now().Unix(), "message", []git.Hash{ "abcdef", "ghijkl", }) @@ -36,7 +46,16 @@ func TestOperationPackSerialize(t *testing.T) { var opp2 *OperationPack err = json.Unmarshal(data, &opp2) - assert.NoError(t, err) + + ensureHash(t, opp) + assert.Equal(t, opp, opp2) } + +func ensureHash(t *testing.T, opp *OperationPack) { + for _, op := range opp.Operations { + _, err := op.Hash() + require.NoError(t, err) + } +} diff --git a/bug/operation_test.go b/bug/operation_test.go index d5cb5090..f9a7d191 100644 --- a/bug/operation_test.go +++ b/bug/operation_test.go @@ -2,6 +2,7 @@ package bug import ( "testing" + "time" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" @@ -11,6 +12,9 @@ import ( ) func TestValidate(t *testing.T) { + rene := identity.NewIdentity("René Descartes", "rene@descartes.fr") + unix := time.Now().Unix() + good := []Operation{ NewCreateOp(rene, unix, "title", "message", nil), NewSetTitleOp(rene, unix, "title2", "title1"), @@ -65,7 +69,8 @@ func TestValidate(t *testing.T) { } func TestMetadata(t *testing.T) { - op := NewCreateOp(rene, unix, "title", "message", nil) + rene := identity.NewIdentity("René Descartes", "rene@descartes.fr") + op := NewCreateOp(rene, time.Now().Unix(), "title", "message", nil) op.SetMetadata("key", "value") @@ -81,7 +86,9 @@ func TestHash(t *testing.T) { } for _, repo := range repos { - b, op, err := Create(rene, unix, "title", "message") + rene := identity.NewBare("René Descartes", "rene@descartes.fr") + + b, op, err := Create(rene, time.Now().Unix(), "title", "message") require.Nil(t, err) h1, err := op.Hash() -- cgit From 71f9290fdae7551f3d3ada2179ece4084304d734 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Tue, 19 Feb 2019 00:19:27 +0100 Subject: identity: store the times properly --- bug/operation_pack.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'bug') diff --git a/bug/operation_pack.go b/bug/operation_pack.go index 55fc018e..5f3e9da8 100644 --- a/bug/operation_pack.go +++ b/bug/operation_pack.go @@ -138,7 +138,7 @@ 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) { +func (opp *OperationPack) Write(repo repository.ClockedRepo) (git.Hash, error) { // make sure we don't write invalid data err := opp.Validate() if err != nil { -- cgit From 475b7b4c490bc3729772932f2d7bbcabb8f781a7 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sun, 24 Feb 2019 17:40:52 +0100 Subject: a round of cleanup --- bug/bug_actions_test.go | 3 +-- bug/bug_test.go | 3 +-- bug/label.go | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) (limited to 'bug') diff --git a/bug/bug_actions_test.go b/bug/bug_actions_test.go index 4d42fb1d..345b5e9a 100644 --- a/bug/bug_actions_test.go +++ b/bug/bug_actions_test.go @@ -1,13 +1,12 @@ package bug import ( + "testing" "time" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/test" "github.com/stretchr/testify/require" - - "testing" ) func TestPushPull(t *testing.T) { diff --git a/bug/bug_test.go b/bug/bug_test.go index e104f921..4c3952eb 100644 --- a/bug/bug_test.go +++ b/bug/bug_test.go @@ -1,13 +1,12 @@ package bug import ( + "testing" "time" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "github.com/stretchr/testify/assert" - - "testing" ) func TestBugId(t *testing.T) { diff --git a/bug/label.go b/bug/label.go index b73222dd..0ad84f22 100644 --- a/bug/label.go +++ b/bug/label.go @@ -28,7 +28,7 @@ func (l *Label) UnmarshalGQL(v interface{}) error { // MarshalGQL implements the graphql.Marshaler interface func (l Label) MarshalGQL(w io.Writer) { - w.Write([]byte(`"` + l.String() + `"`)) + _, _ = w.Write([]byte(`"` + l.String() + `"`)) } func (l Label) Validate() error { -- cgit From 46beb4b886761ff69abe2ce45c2498a4fafe50d9 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sun, 24 Feb 2019 18:49:12 +0100 Subject: identity: another round of cleanups --- bug/bug_actions.go | 2 +- bug/operation_iterator_test.go | 14 -------------- 2 files changed, 1 insertion(+), 15 deletions(-) (limited to 'bug') diff --git a/bug/bug_actions.go b/bug/bug_actions.go index b906b938..20360200 100644 --- a/bug/bug_actions.go +++ b/bug/bug_actions.go @@ -11,7 +11,7 @@ import ( // Note: // -// For the actions (fetch/push/pull/merge), this package act as a master for +// For the actions (fetch/push/pull/merge/commit), this package act as a master for // the identity package and will also drive the needed identity actions. That is, // if bug.Push() is called, identity.Push will also be called to make sure that // the dependant identities are also present and up to date on the remote. diff --git a/bug/operation_iterator_test.go b/bug/operation_iterator_test.go index 2865d25d..b922bec1 100644 --- a/bug/operation_iterator_test.go +++ b/bug/operation_iterator_test.go @@ -9,20 +9,6 @@ import ( "time" ) -var ( -// Beware, don't those test data in multi-repo situation ! -// As an example, the Identity would be considered commited after a commit -// in one repo, -// rene = identity.NewIdentity("René Descartes", "rene@descartes.fr") -// unix = time.Now().Unix() - -// createOp = NewCreateOp(rene, unix, "title", "message", nil) -// setTitleOp = NewSetTitleOp(rene, unix, "title2", "title1") -// addCommentOp = NewAddCommentOp(rene, unix, "message2", nil) -// setStatusOp = NewSetStatusOp(rene, unix, ClosedStatus) -// labelChangeOp = NewLabelChangeOperation(rene, unix, []Label{"added"}, []Label{"removed"}) -) - func ExampleOperationIterator() { b := NewBug() -- cgit From c235d89d36500e58e3bcadda94e9cab06023dd55 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sun, 24 Feb 2019 23:05:03 +0100 Subject: commands: show the last modification time in "user" --- bug/comment.go | 3 ++- bug/op_add_comment.go | 3 ++- bug/op_create.go | 3 ++- bug/op_create_test.go | 3 ++- bug/op_edit_comment.go | 3 ++- bug/op_label_change.go | 5 +++-- bug/op_noop.go | 2 +- bug/op_set_metadata.go | 5 +++++ bug/op_set_status.go | 5 +++-- bug/op_set_title.go | 5 +++-- bug/time.go | 9 --------- bug/timeline.go | 7 ++++--- 12 files changed, 29 insertions(+), 24 deletions(-) delete mode 100644 bug/time.go (limited to 'bug') diff --git a/bug/comment.go b/bug/comment.go index 84d34299..f7a6eada 100644 --- a/bug/comment.go +++ b/bug/comment.go @@ -3,6 +3,7 @@ package bug import ( "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" + "github.com/MichaelMure/git-bug/util/timestamp" "github.com/dustin/go-humanize" ) @@ -14,7 +15,7 @@ type Comment struct { // Creation time of the comment. // Should be used only for human display, never for ordering as we can't rely on it in a distributed system. - UnixTime Timestamp + UnixTime timestamp.Timestamp } // FormatTimeRel format the UnixTime of the comment for human consumption diff --git a/bug/op_add_comment.go b/bug/op_add_comment.go index ba5d611e..9ecef941 100644 --- a/bug/op_add_comment.go +++ b/bug/op_add_comment.go @@ -7,6 +7,7 @@ import ( "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" + "github.com/MichaelMure/git-bug/util/timestamp" ) var _ Operation = &AddCommentOperation{} @@ -32,7 +33,7 @@ func (op *AddCommentOperation) Apply(snapshot *Snapshot) { Message: op.Message, Author: op.Author, Files: op.Files, - UnixTime: Timestamp(op.UnixTime), + UnixTime: timestamp.Timestamp(op.UnixTime), } snapshot.Comments = append(snapshot.Comments, comment) diff --git a/bug/op_create.go b/bug/op_create.go index 1d157e67..42d40f71 100644 --- a/bug/op_create.go +++ b/bug/op_create.go @@ -8,6 +8,7 @@ import ( "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" + "github.com/MichaelMure/git-bug/util/timestamp" ) var _ Operation = &CreateOperation{} @@ -34,7 +35,7 @@ func (op *CreateOperation) Apply(snapshot *Snapshot) { comment := Comment{ Message: op.Message, Author: op.Author, - UnixTime: Timestamp(op.UnixTime), + UnixTime: timestamp.Timestamp(op.UnixTime), } snapshot.Comments = []Comment{comment} diff --git a/bug/op_create_test.go b/bug/op_create_test.go index c41c5687..92ac191d 100644 --- a/bug/op_create_test.go +++ b/bug/op_create_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/timestamp" "github.com/stretchr/testify/assert" ) @@ -22,7 +23,7 @@ func TestCreate(t *testing.T) { hash, err := create.Hash() assert.NoError(t, err) - comment := Comment{Author: rene, Message: "message", UnixTime: Timestamp(create.UnixTime)} + comment := Comment{Author: rene, Message: "message", UnixTime: timestamp.Timestamp(create.UnixTime)} expected := Snapshot{ Title: "title", diff --git a/bug/op_edit_comment.go b/bug/op_edit_comment.go index 3ff16653..527b7440 100644 --- a/bug/op_edit_comment.go +++ b/bug/op_edit_comment.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/timestamp" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" @@ -58,7 +59,7 @@ func (op *EditCommentOperation) Apply(snapshot *Snapshot) { comment := Comment{ Message: op.Message, Files: op.Files, - UnixTime: Timestamp(op.UnixTime), + UnixTime: timestamp.Timestamp(op.UnixTime), } switch target.(type) { diff --git a/bug/op_label_change.go b/bug/op_label_change.go index b0dd2c33..84542b6e 100644 --- a/bug/op_label_change.go +++ b/bug/op_label_change.go @@ -6,6 +6,7 @@ import ( "sort" "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/timestamp" "github.com/MichaelMure/git-bug/util/git" "github.com/pkg/errors" @@ -68,7 +69,7 @@ AddLoop: item := &LabelChangeTimelineItem{ hash: hash, Author: op.Author, - UnixTime: Timestamp(op.UnixTime), + UnixTime: timestamp.Timestamp(op.UnixTime), Added: op.Added, Removed: op.Removed, } @@ -162,7 +163,7 @@ func NewLabelChangeOperation(author identity.Interface, unixTime int64, added, r type LabelChangeTimelineItem struct { hash git.Hash Author identity.Interface - UnixTime Timestamp + UnixTime timestamp.Timestamp Added []Label Removed []Label } diff --git a/bug/op_noop.go b/bug/op_noop.go index fbc112a8..3cd9f39a 100644 --- a/bug/op_noop.go +++ b/bug/op_noop.go @@ -11,7 +11,7 @@ var _ Operation = &NoOpOperation{} // NoOpOperation is an operation that does not change the bug state. It can // however be used to store arbitrary metadata in the bug history, for example -// to support a bridge feature +// to support a bridge feature. type NoOpOperation struct { OpBase } diff --git a/bug/op_set_metadata.go b/bug/op_set_metadata.go index 57b78667..7616a591 100644 --- a/bug/op_set_metadata.go +++ b/bug/op_set_metadata.go @@ -2,6 +2,7 @@ package bug import ( "encoding/json" + "fmt" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" @@ -55,6 +56,10 @@ func (op *SetMetadataOperation) Validate() error { return err } + if !op.Target.IsValid() { + return fmt.Errorf("target hash is invalid") + } + return nil } diff --git a/bug/op_set_status.go b/bug/op_set_status.go index 6deb1675..0105d78d 100644 --- a/bug/op_set_status.go +++ b/bug/op_set_status.go @@ -5,6 +5,7 @@ import ( "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" + "github.com/MichaelMure/git-bug/util/timestamp" "github.com/pkg/errors" ) @@ -37,7 +38,7 @@ func (op *SetStatusOperation) Apply(snapshot *Snapshot) { item := &SetStatusTimelineItem{ hash: hash, Author: op.Author, - UnixTime: Timestamp(op.UnixTime), + UnixTime: timestamp.Timestamp(op.UnixTime), Status: op.Status, } @@ -114,7 +115,7 @@ func NewSetStatusOp(author identity.Interface, unixTime int64, status Status) *S type SetStatusTimelineItem struct { hash git.Hash Author identity.Interface - UnixTime Timestamp + UnixTime timestamp.Timestamp Status Status } diff --git a/bug/op_set_title.go b/bug/op_set_title.go index ae6484c6..084838cb 100644 --- a/bug/op_set_title.go +++ b/bug/op_set_title.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/MichaelMure/git-bug/identity" + "github.com/MichaelMure/git-bug/util/timestamp" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" @@ -41,7 +42,7 @@ func (op *SetTitleOperation) Apply(snapshot *Snapshot) { item := &SetTitleTimelineItem{ hash: hash, Author: op.Author, - UnixTime: Timestamp(op.UnixTime), + UnixTime: timestamp.Timestamp(op.UnixTime), Title: op.Title, Was: op.Was, } @@ -139,7 +140,7 @@ func NewSetTitleOp(author identity.Interface, unixTime int64, title string, was type SetTitleTimelineItem struct { hash git.Hash Author identity.Interface - UnixTime Timestamp + UnixTime timestamp.Timestamp Title string Was string } diff --git a/bug/time.go b/bug/time.go deleted file mode 100644 index a085e8e9..00000000 --- a/bug/time.go +++ /dev/null @@ -1,9 +0,0 @@ -package bug - -import "time" - -type Timestamp int64 - -func (t Timestamp) Time() time.Time { - return time.Unix(int64(t), 0) -} diff --git a/bug/timeline.go b/bug/timeline.go index 306ffa9e..d8ee2c6b 100644 --- a/bug/timeline.go +++ b/bug/timeline.go @@ -5,6 +5,7 @@ import ( "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" + "github.com/MichaelMure/git-bug/util/timestamp" ) type TimelineItem interface { @@ -19,7 +20,7 @@ type CommentHistoryStep struct { Author identity.Interface // The new message Message string - UnixTime Timestamp + UnixTime timestamp.Timestamp } // CommentTimelineItem is a TimelineItem that holds a Comment and its edition history @@ -28,8 +29,8 @@ type CommentTimelineItem struct { Author identity.Interface Message string Files []git.Hash - CreatedAt Timestamp - LastEdit Timestamp + CreatedAt timestamp.Timestamp + LastEdit timestamp.Timestamp History []CommentHistoryStep } -- cgit