diff options
Diffstat (limited to 'bug')
-rw-r--r-- | bug/bug.go | 59 | ||||
-rw-r--r-- | bug/bug_actions.go | 2 | ||||
-rw-r--r-- | bug/comment.go | 10 | ||||
-rw-r--r-- | bug/interface.go | 6 | ||||
-rw-r--r-- | bug/op_add_comment.go | 36 | ||||
-rw-r--r-- | bug/op_add_comment_test.go | 6 | ||||
-rw-r--r-- | bug/op_create.go | 39 | ||||
-rw-r--r-- | bug/op_create_test.go | 11 | ||||
-rw-r--r-- | bug/op_edit_comment.go | 51 | ||||
-rw-r--r-- | bug/op_edit_comment_test.go | 23 | ||||
-rw-r--r-- | bug/op_label_change.go | 38 | ||||
-rw-r--r-- | bug/op_label_change_test.go | 5 | ||||
-rw-r--r-- | bug/op_noop.go | 25 | ||||
-rw-r--r-- | bug/op_noop_test.go | 5 | ||||
-rw-r--r-- | bug/op_set_metadata.go | 47 | ||||
-rw-r--r-- | bug/op_set_metadata_test.go | 19 | ||||
-rw-r--r-- | bug/op_set_status.go | 35 | ||||
-rw-r--r-- | bug/op_set_status_test.go | 5 | ||||
-rw-r--r-- | bug/op_set_title.go | 38 | ||||
-rw-r--r-- | bug/op_set_title_test.go | 5 | ||||
-rw-r--r-- | bug/operation.go | 76 | ||||
-rw-r--r-- | bug/operation_pack_test.go | 10 | ||||
-rw-r--r-- | bug/operation_test.go | 14 | ||||
-rw-r--r-- | bug/snapshot.go | 24 | ||||
-rw-r--r-- | bug/timeline.go | 9 |
25 files changed, 213 insertions, 385 deletions
@@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/git" @@ -26,20 +27,24 @@ const createClockEntryPattern = "create-clock-%d" const editClockEntryPrefix = "edit-clock-" const editClockEntryPattern = "edit-clock-%d" -const idLength = 40 -const humanIdLength = 7 - var ErrBugNotExist = errors.New("bug doesn't exist") type ErrMultipleMatch struct { - Matching []string + Matching []entity.Id } func (e ErrMultipleMatch) Error() string { - return fmt.Sprintf("Multiple matching bug found:\n%s", strings.Join(e.Matching, "\n")) + matching := make([]string, len(e.Matching)) + + for i, match := range e.Matching { + matching[i] = match.String() + } + + return fmt.Sprintf("Multiple matching bug found:\n%s", strings.Join(matching, "\n")) } var _ Interface = &Bug{} +var _ entity.Interface = &Bug{} // Bug hold the data of a bug thread, organized in a way close to // how it will be persisted inside Git. This is the data structure @@ -53,7 +58,7 @@ type Bug struct { editTime lamport.Time // Id used as unique identifier - id string + id entity.Id lastCommit git.Hash rootPack git.Hash @@ -82,10 +87,10 @@ func FindLocalBug(repo repository.ClockedRepo, prefix string) (*Bug, error) { } // preallocate but empty - matching := make([]string, 0, 5) + matching := make([]entity.Id, 0, 5) for _, id := range ids { - if strings.HasPrefix(id, prefix) { + if id.HasPrefix(prefix) { matching = append(matching, id) } } @@ -102,8 +107,8 @@ func FindLocalBug(repo repository.ClockedRepo, prefix string) (*Bug, error) { } // ReadLocalBug will read a local bug from its hash -func ReadLocalBug(repo repository.ClockedRepo, id string) (*Bug, error) { - ref := bugsRefPattern + id +func ReadLocalBug(repo repository.ClockedRepo, id entity.Id) (*Bug, error) { + ref := bugsRefPattern + id.String() return readBug(repo, ref) } @@ -116,10 +121,10 @@ 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) { refSplit := strings.Split(ref, "/") - id := refSplit[len(refSplit)-1] + id := entity.Id(refSplit[len(refSplit)-1]) - if len(id) != idLength { - return nil, fmt.Errorf("invalid ref length") + if err := id.Validate(); err != nil { + return nil, errors.Wrap(err, "invalid ref ") } hashes, err := repo.ListCommits(ref) @@ -278,7 +283,7 @@ func readAllBugs(repo repository.ClockedRepo, refPrefix string) <-chan StreamedB } // ListLocalIds list all the available local bug ids -func ListLocalIds(repo repository.Repo) ([]string, error) { +func ListLocalIds(repo repository.Repo) ([]entity.Id, error) { refs, err := repo.ListRefs(bugsRefPattern) if err != nil { return nil, err @@ -287,12 +292,12 @@ func ListLocalIds(repo repository.Repo) ([]string, error) { return refsToIds(refs), nil } -func refsToIds(refs []string) []string { - ids := make([]string, len(refs)) +func refsToIds(refs []string) []entity.Id { + ids := make([]entity.Id, len(refs)) for i, ref := range refs { split := strings.Split(ref, "/") - ids[i] = split[len(split)-1] + ids[i] = entity.Id(split[len(split)-1]) } return ids @@ -325,8 +330,8 @@ 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 { + // The bug Id should be the hash of the first commit + if len(bug.packs) > 0 && string(bug.packs[0].commitHash) != bug.id.String() { return fmt.Errorf("bug id should be the first commit hash") } @@ -456,7 +461,7 @@ func (bug *Bug) Commit(repo repository.ClockedRepo) error { // if it was the first commit, use the commit hash as bug id if bug.id == "" { - bug.id = string(hash) + bug.id = entity.Id(hash) } // Create or update the Git reference for this bug @@ -594,7 +599,7 @@ func (bug *Bug) Merge(repo repository.Repo, other Interface) (bool, error) { } // Update the git ref - err = repo.UpdateRef(bugsRefPattern+bug.id, bug.lastCommit) + err = repo.UpdateRef(bugsRefPattern+bug.id.String(), bug.lastCommit) if err != nil { return false, err } @@ -603,7 +608,7 @@ func (bug *Bug) Merge(repo repository.Repo, other Interface) (bool, error) { } // Id return the Bug identifier -func (bug *Bug) Id() string { +func (bug *Bug) Id() entity.Id { if bug.id == "" { // simply panic as it would be a coding error // (using an id of a bug not stored yet) @@ -612,16 +617,6 @@ func (bug *Bug) Id() string { return bug.id } -// HumanId return the Bug identifier truncated for human consumption -func (bug *Bug) HumanId() string { - return FormatHumanID(bug.Id()) -} - -func FormatHumanID(id string) string { - format := fmt.Sprintf("%%.%ds", humanIdLength) - return fmt.Sprintf(format, id) -} - // CreateLamportTime return the Lamport time of creation func (bug *Bug) CreateLamportTime() lamport.Time { return bug.createTime diff --git a/bug/bug_actions.go b/bug/bug_actions.go index b26d080f..e6fc12d5 100644 --- a/bug/bug_actions.go +++ b/bug/bug_actions.go @@ -81,7 +81,7 @@ func MergeAll(repo repository.ClockedRepo, remote string) <-chan entity.MergeRes continue } - localRef := bugsRefPattern + remoteBug.Id() + localRef := bugsRefPattern + remoteBug.Id().String() localExist, err := repo.RefExist(localRef) if err != nil { diff --git a/bug/comment.go b/bug/comment.go index 5db0b18d..47c1ff05 100644 --- a/bug/comment.go +++ b/bug/comment.go @@ -1,6 +1,7 @@ package bug import ( + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/timestamp" @@ -9,7 +10,7 @@ import ( // Comment represent a comment in a Bug type Comment struct { - id string + id entity.Id Author identity.Interface Message string Files []git.Hash @@ -20,7 +21,7 @@ type Comment struct { } // Id return the Comment identifier -func (c Comment) Id() string { +func (c Comment) Id() entity.Id { if c.id == "" { // simply panic as it would be a coding error // (using an id of an identity not stored yet) @@ -29,11 +30,6 @@ func (c Comment) Id() string { return c.id } -// HumanId return the Comment identifier truncated for human consumption -func (c Comment) HumanId() string { - return FormatHumanID(c.Id()) -} - // FormatTimeRel format the UnixTime of the comment for human consumption func (c Comment) FormatTimeRel() string { return humanize.Time(c.UnixTime.Time()) diff --git a/bug/interface.go b/bug/interface.go index 186c26fc..8266e99e 100644 --- a/bug/interface.go +++ b/bug/interface.go @@ -1,16 +1,14 @@ package bug import ( + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/lamport" ) type Interface interface { // Id return the Bug identifier - Id() string - - // HumanId return the Bug identifier truncated for human consumption - HumanId() string + Id() entity.Id // Validate check if the Bug data is valid Validate() error diff --git a/bug/op_add_comment.go b/bug/op_add_comment.go index 1ff2ae87..e16ea0dd 100644 --- a/bug/op_add_comment.go +++ b/bug/op_add_comment.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" @@ -15,16 +16,16 @@ var _ Operation = &AddCommentOperation{} // AddCommentOperation will add a new comment in the bug type AddCommentOperation struct { OpBase - Message string + Message string `json:"message"` // TODO: change for a map[string]util.hash to store the filename ? - Files []git.Hash + Files []git.Hash `json:"files"` } func (op *AddCommentOperation) base() *OpBase { return &op.OpBase } -func (op *AddCommentOperation) ID() string { +func (op *AddCommentOperation) Id() entity.Id { return idOperation(op) } @@ -33,7 +34,7 @@ func (op *AddCommentOperation) Apply(snapshot *Snapshot) { snapshot.addParticipant(op.Author) comment := Comment{ - id: op.ID(), + id: op.Id(), Message: op.Message, Author: op.Author, Files: op.Files, @@ -43,7 +44,7 @@ func (op *AddCommentOperation) Apply(snapshot *Snapshot) { snapshot.Comments = append(snapshot.Comments, comment) item := &AddCommentTimelineItem{ - CommentTimelineItem: NewCommentTimelineItem(op.ID(), comment), + CommentTimelineItem: NewCommentTimelineItem(op.Id(), comment), } snapshot.Timeline = append(snapshot.Timeline, item) @@ -65,28 +66,9 @@ 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 +// UnmarshalJSON is a two step JSON unmarshaling +// This workaround is necessary to avoid the inner OpBase.MarshalJSON +// overriding the outer op's MarshalJSON func (op *AddCommentOperation) UnmarshalJSON(data []byte) error { // Unmarshal OpBase and the op separately diff --git a/bug/op_add_comment_test.go b/bug/op_add_comment_test.go index a1789aa0..55bafe36 100644 --- a/bug/op_add_comment_test.go +++ b/bug/op_add_comment_test.go @@ -2,6 +2,7 @@ package bug import ( "encoding/json" + "fmt" "testing" "time" @@ -21,8 +22,9 @@ func TestAddCommentSerialize(t *testing.T) { err = json.Unmarshal(data, &after) assert.NoError(t, err) - // enforce creating the ID - before.ID() + // enforce creating the IDs + before.Id() + rene.Id() assert.Equal(t, before, &after) } diff --git a/bug/op_create.go b/bug/op_create.go index e3d0a63a..0da95d4d 100644 --- a/bug/op_create.go +++ b/bug/op_create.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/text" @@ -16,16 +17,16 @@ var _ Operation = &CreateOperation{} // CreateOperation define the initial creation of a bug type CreateOperation struct { OpBase - Title string - Message string - Files []git.Hash + Title string `json:"title"` + Message string `json:"message"` + Files []git.Hash `json:"files"` } func (op *CreateOperation) base() *OpBase { return &op.OpBase } -func (op *CreateOperation) ID() string { +func (op *CreateOperation) Id() entity.Id { return idOperation(op) } @@ -36,7 +37,7 @@ func (op *CreateOperation) Apply(snapshot *Snapshot) { snapshot.Title = op.Title comment := Comment{ - id: op.ID(), + id: op.Id(), Message: op.Message, Author: op.Author, UnixTime: timestamp.Timestamp(op.UnixTime), @@ -48,7 +49,7 @@ func (op *CreateOperation) Apply(snapshot *Snapshot) { snapshot.Timeline = []TimelineItem{ &CreateTimelineItem{ - CommentTimelineItem: NewCommentTimelineItem(op.ID(), comment), + CommentTimelineItem: NewCommentTimelineItem(op.Id(), comment), }, } } @@ -81,29 +82,9 @@ 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 +// UnmarshalJSON is a two step JSON unmarshaling +// This workaround is necessary to avoid the inner OpBase.MarshalJSON +// overriding the outer op's MarshalJSON func (op *CreateOperation) UnmarshalJSON(data []byte) error { // Unmarshal OpBase and the op separately diff --git a/bug/op_create_test.go b/bug/op_create_test.go index 20c8ec69..ec53b04b 100644 --- a/bug/op_create_test.go +++ b/bug/op_create_test.go @@ -20,11 +20,11 @@ func TestCreate(t *testing.T) { create.Apply(&snapshot) - id := create.ID() - assert.True(t, IDIsValid(id)) + id := create.Id() + assert.NoError(t, id.Validate()) comment := Comment{ - id: string(id), + id: id, Author: rene, Message: "message", UnixTime: timestamp.Timestamp(create.UnixTime), @@ -61,8 +61,9 @@ func TestCreateSerialize(t *testing.T) { err = json.Unmarshal(data, &after) assert.NoError(t, err) - // enforce creating the ID - before.ID() + // enforce creating the IDs + before.Id() + rene.Id() assert.Equal(t, before, &after) } diff --git a/bug/op_edit_comment.go b/bug/op_edit_comment.go index 2f269b02..a37ce8f7 100644 --- a/bug/op_edit_comment.go +++ b/bug/op_edit_comment.go @@ -4,6 +4,9 @@ import ( "encoding/json" "fmt" + "github.com/pkg/errors" + + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/timestamp" @@ -16,16 +19,16 @@ var _ Operation = &EditCommentOperation{} // EditCommentOperation will change a comment in the bug type EditCommentOperation struct { OpBase - Target string - Message string - Files []git.Hash + Target entity.Id `json:"target"` + Message string `json:"message"` + Files []git.Hash `json:"files"` } func (op *EditCommentOperation) base() *OpBase { return &op.OpBase } -func (op *EditCommentOperation) ID() string { +func (op *EditCommentOperation) Id() entity.Id { return idOperation(op) } @@ -38,7 +41,7 @@ func (op *EditCommentOperation) Apply(snapshot *Snapshot) { var target TimelineItem for i, item := range snapshot.Timeline { - if item.ID() == op.Target { + if item.Id() == op.Target { target = snapshot.Timeline[i] break } @@ -86,8 +89,8 @@ func (op *EditCommentOperation) Validate() error { return err } - if !IDIsValid(op.Target) { - return fmt.Errorf("target hash is invalid") + if err := op.Target.Validate(); err != nil { + return errors.Wrap(err, "target hash is invalid") } if !text.Safe(op.Message) { @@ -97,29 +100,9 @@ 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 +// UnmarshalJSON is a two step JSON unmarshaling +// This workaround is necessary to avoid the inner OpBase.MarshalJSON +// overriding the outer op's MarshalJSON func (op *EditCommentOperation) UnmarshalJSON(data []byte) error { // Unmarshal OpBase and the op separately @@ -130,7 +113,7 @@ func (op *EditCommentOperation) UnmarshalJSON(data []byte) error { } aux := struct { - Target string `json:"target"` + Target entity.Id `json:"target"` Message string `json:"message"` Files []git.Hash `json:"files"` }{} @@ -151,7 +134,7 @@ func (op *EditCommentOperation) UnmarshalJSON(data []byte) error { // Sign post method for gqlgen func (op *EditCommentOperation) IsAuthored() {} -func NewEditCommentOp(author identity.Interface, unixTime int64, target string, message string, files []git.Hash) *EditCommentOperation { +func NewEditCommentOp(author identity.Interface, unixTime int64, target entity.Id, message string, files []git.Hash) *EditCommentOperation { return &EditCommentOperation{ OpBase: newOpBase(EditCommentOp, author, unixTime), Target: target, @@ -161,11 +144,11 @@ func NewEditCommentOp(author identity.Interface, unixTime int64, target string, } // Convenience function to apply the operation -func EditComment(b Interface, author identity.Interface, unixTime int64, target string, message string) (*EditCommentOperation, error) { +func EditComment(b Interface, author identity.Interface, unixTime int64, target entity.Id, message string) (*EditCommentOperation, error) { return EditCommentWithFiles(b, author, unixTime, target, message, nil) } -func EditCommentWithFiles(b Interface, author identity.Interface, unixTime int64, target string, message string, files []git.Hash) (*EditCommentOperation, error) { +func EditCommentWithFiles(b Interface, author identity.Interface, unixTime int64, target entity.Id, 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 9e8739da..abd550cb 100644 --- a/bug/op_edit_comment_test.go +++ b/bug/op_edit_comment_test.go @@ -20,14 +20,14 @@ func TestEdit(t *testing.T) { create := NewCreateOp(rene, unix, "title", "create", nil) create.Apply(&snapshot) - hash1 := create.ID() - require.True(t, IDIsValid(hash1)) + id1 := create.Id() + require.NoError(t, id1.Validate()) comment1 := NewAddCommentOp(rene, unix, "comment 1", nil) comment1.Apply(&snapshot) - hash2 := comment1.ID() - require.True(t, IDIsValid(hash2)) + id2 := comment1.Id() + require.NoError(t, id2.Validate()) // add another unrelated op in between setTitle := NewSetTitleOp(rene, unix, "edited title", "title") @@ -36,10 +36,10 @@ func TestEdit(t *testing.T) { comment2 := NewAddCommentOp(rene, unix, "comment 2", nil) comment2.Apply(&snapshot) - hash3 := comment2.ID() - require.True(t, IDIsValid(hash3)) + id3 := comment2.Id() + require.NoError(t, id3.Validate()) - edit := NewEditCommentOp(rene, unix, hash1, "create edited", nil) + edit := NewEditCommentOp(rene, unix, id1, "create edited", nil) edit.Apply(&snapshot) assert.Equal(t, len(snapshot.Timeline), 4) @@ -50,7 +50,7 @@ func TestEdit(t *testing.T) { assert.Equal(t, snapshot.Comments[1].Message, "comment 1") assert.Equal(t, snapshot.Comments[2].Message, "comment 2") - edit2 := NewEditCommentOp(rene, unix, hash2, "comment 1 edited", nil) + edit2 := NewEditCommentOp(rene, unix, id2, "comment 1 edited", nil) edit2.Apply(&snapshot) assert.Equal(t, len(snapshot.Timeline), 4) @@ -61,7 +61,7 @@ func TestEdit(t *testing.T) { assert.Equal(t, snapshot.Comments[1].Message, "comment 1 edited") assert.Equal(t, snapshot.Comments[2].Message, "comment 2") - edit3 := NewEditCommentOp(rene, unix, hash3, "comment 2 edited", nil) + edit3 := NewEditCommentOp(rene, unix, id3, "comment 2 edited", nil) edit3.Apply(&snapshot) assert.Equal(t, len(snapshot.Timeline), 4) @@ -85,8 +85,9 @@ func TestEditCommentSerialize(t *testing.T) { err = json.Unmarshal(data, &after) assert.NoError(t, err) - // enforce creating the ID - before.ID() + // enforce creating the IDs + before.Id() + rene.Id() assert.Equal(t, before, &after) } diff --git a/bug/op_label_change.go b/bug/op_label_change.go index 5afcceb7..c911de26 100644 --- a/bug/op_label_change.go +++ b/bug/op_label_change.go @@ -7,6 +7,7 @@ import ( "github.com/pkg/errors" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/timestamp" ) @@ -16,15 +17,15 @@ var _ Operation = &LabelChangeOperation{} // LabelChangeOperation define a Bug operation to add or remove labels type LabelChangeOperation struct { OpBase - Added []Label - Removed []Label + Added []Label `json:"added"` + Removed []Label `json:"removed"` } func (op *LabelChangeOperation) base() *OpBase { return &op.OpBase } -func (op *LabelChangeOperation) ID() string { +func (op *LabelChangeOperation) Id() entity.Id { return idOperation(op) } @@ -61,7 +62,7 @@ AddLoop: }) item := &LabelChangeTimelineItem{ - id: op.ID(), + id: op.Id(), Author: op.Author, UnixTime: timestamp.Timestamp(op.UnixTime), Added: op.Added, @@ -95,28 +96,9 @@ 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 +// UnmarshalJSON is a two step JSON unmarshaling +// This workaround is necessary to avoid the inner OpBase.MarshalJSON +// overriding the outer op's MarshalJSON func (op *LabelChangeOperation) UnmarshalJSON(data []byte) error { // Unmarshal OpBase and the op separately @@ -155,14 +137,14 @@ func NewLabelChangeOperation(author identity.Interface, unixTime int64, added, r } type LabelChangeTimelineItem struct { - id string + id entity.Id Author identity.Interface UnixTime timestamp.Timestamp Added []Label Removed []Label } -func (l LabelChangeTimelineItem) ID() string { +func (l LabelChangeTimelineItem) Id() entity.Id { return l.id } diff --git a/bug/op_label_change_test.go b/bug/op_label_change_test.go index 7c311a8b..2a93e362 100644 --- a/bug/op_label_change_test.go +++ b/bug/op_label_change_test.go @@ -21,8 +21,9 @@ func TestLabelChangeSerialize(t *testing.T) { err = json.Unmarshal(data, &after) assert.NoError(t, err) - // enforce creating the ID - before.ID() + // enforce creating the IDs + before.Id() + rene.Id() assert.Equal(t, before, &after) } diff --git a/bug/op_noop.go b/bug/op_noop.go index a1648434..16d32297 100644 --- a/bug/op_noop.go +++ b/bug/op_noop.go @@ -3,6 +3,7 @@ package bug import ( "encoding/json" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" ) @@ -19,7 +20,7 @@ func (op *NoOpOperation) base() *OpBase { return &op.OpBase } -func (op *NoOpOperation) ID() string { +func (op *NoOpOperation) Id() entity.Id { return idOperation(op) } @@ -31,25 +32,9 @@ 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 +// UnmarshalJSON is a two step JSON unmarshaling +// This workaround is necessary to avoid the inner OpBase.MarshalJSON +// overriding the outer op's MarshalJSON func (op *NoOpOperation) UnmarshalJSON(data []byte) error { // Unmarshal OpBase and the op separately diff --git a/bug/op_noop_test.go b/bug/op_noop_test.go index 33e37bec..ea815948 100644 --- a/bug/op_noop_test.go +++ b/bug/op_noop_test.go @@ -21,8 +21,9 @@ func TestNoopSerialize(t *testing.T) { err = json.Unmarshal(data, &after) assert.NoError(t, err) - // enforce creating the ID - before.ID() + // enforce creating the IDs + before.Id() + rene.Id() assert.Equal(t, before, &after) } diff --git a/bug/op_set_metadata.go b/bug/op_set_metadata.go index 19ddc3e3..f99f836b 100644 --- a/bug/op_set_metadata.go +++ b/bug/op_set_metadata.go @@ -2,8 +2,10 @@ package bug import ( "encoding/json" - "fmt" + "github.com/pkg/errors" + + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" ) @@ -11,21 +13,21 @@ var _ Operation = &SetMetadataOperation{} type SetMetadataOperation struct { OpBase - Target string - NewMetadata map[string]string + Target entity.Id `json:"target"` + NewMetadata map[string]string `json:"new_metadata"` } func (op *SetMetadataOperation) base() *OpBase { return &op.OpBase } -func (op *SetMetadataOperation) ID() string { +func (op *SetMetadataOperation) Id() entity.Id { return idOperation(op) } func (op *SetMetadataOperation) Apply(snapshot *Snapshot) { for _, target := range snapshot.Operations { - if target.ID() == op.Target { + if target.Id() == op.Target { base := target.base() if base.extraMetadata == nil { @@ -48,35 +50,16 @@ func (op *SetMetadataOperation) Validate() error { return err } - if !IDIsValid(op.Target) { - return fmt.Errorf("target hash is invalid") + if err := op.Target.Validate(); err != nil { + return errors.Wrap(err, "target invalid") } 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 +// UnmarshalJSON is a two step JSON unmarshaling +// This workaround is necessary to avoid the inner OpBase.MarshalJSON +// overriding the outer op's MarshalJSON func (op *SetMetadataOperation) UnmarshalJSON(data []byte) error { // Unmarshal OpBase and the op separately @@ -87,7 +70,7 @@ func (op *SetMetadataOperation) UnmarshalJSON(data []byte) error { } aux := struct { - Target string `json:"target"` + Target entity.Id `json:"target"` NewMetadata map[string]string `json:"new_metadata"` }{} @@ -106,7 +89,7 @@ func (op *SetMetadataOperation) UnmarshalJSON(data []byte) error { // Sign post method for gqlgen func (op *SetMetadataOperation) IsAuthored() {} -func NewSetMetadataOp(author identity.Interface, unixTime int64, target string, newMetadata map[string]string) *SetMetadataOperation { +func NewSetMetadataOp(author identity.Interface, unixTime int64, target entity.Id, newMetadata map[string]string) *SetMetadataOperation { return &SetMetadataOperation{ OpBase: newOpBase(SetMetadataOp, author, unixTime), Target: target, @@ -115,7 +98,7 @@ func NewSetMetadataOp(author identity.Interface, unixTime int64, target string, } // Convenience function to apply the operation -func SetMetadata(b Interface, author identity.Interface, unixTime int64, target string, newMetadata map[string]string) (*SetMetadataOperation, error) { +func SetMetadata(b Interface, author identity.Interface, unixTime int64, target entity.Id, 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 97e70cf4..389e91ac 100644 --- a/bug/op_set_metadata_test.go +++ b/bug/op_set_metadata_test.go @@ -21,18 +21,18 @@ func TestSetMetadata(t *testing.T) { create.Apply(&snapshot) snapshot.Operations = append(snapshot.Operations, create) - hash1 := create.ID() - require.True(t, IDIsValid(hash1)) + id1 := create.Id() + require.NoError(t, id1.Validate()) comment := NewAddCommentOp(rene, unix, "comment", nil) comment.SetMetadata("key2", "value2") comment.Apply(&snapshot) snapshot.Operations = append(snapshot.Operations, comment) - hash2 := comment.ID() - require.True(t, IDIsValid(hash2)) + id2 := comment.Id() + require.NoError(t, id2.Validate()) - op1 := NewSetMetadataOp(rene, unix, hash1, map[string]string{ + op1 := NewSetMetadataOp(rene, unix, id1, map[string]string{ "key": "override", "key2": "value", }) @@ -51,7 +51,7 @@ func TestSetMetadata(t *testing.T) { assert.Equal(t, len(commentMetadata), 1) assert.Equal(t, commentMetadata["key2"], "value2") - op2 := NewSetMetadataOp(rene, unix, hash2, map[string]string{ + op2 := NewSetMetadataOp(rene, unix, id2, map[string]string{ "key2": "value", "key3": "value3", }) @@ -71,7 +71,7 @@ func TestSetMetadata(t *testing.T) { // new key is set assert.Equal(t, commentMetadata["key3"], "value3") - op3 := NewSetMetadataOp(rene, unix, hash1, map[string]string{ + op3 := NewSetMetadataOp(rene, unix, id1, map[string]string{ "key": "override", "key2": "override", }) @@ -107,8 +107,9 @@ func TestSetMetadataSerialize(t *testing.T) { err = json.Unmarshal(data, &after) assert.NoError(t, err) - // enforce creating the ID - before.ID() + // enforce creating the IDs + before.Id() + rene.Id() assert.Equal(t, before, &after) } diff --git a/bug/op_set_status.go b/bug/op_set_status.go index 76117b19..8a245184 100644 --- a/bug/op_set_status.go +++ b/bug/op_set_status.go @@ -5,6 +5,7 @@ import ( "github.com/pkg/errors" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/timestamp" ) @@ -14,14 +15,14 @@ var _ Operation = &SetStatusOperation{} // SetStatusOperation will change the status of a bug type SetStatusOperation struct { OpBase - Status Status + Status Status `json:"status"` } func (op *SetStatusOperation) base() *OpBase { return &op.OpBase } -func (op *SetStatusOperation) ID() string { +func (op *SetStatusOperation) Id() entity.Id { return idOperation(op) } @@ -30,7 +31,7 @@ func (op *SetStatusOperation) Apply(snapshot *Snapshot) { snapshot.addActor(op.Author) item := &SetStatusTimelineItem{ - id: op.ID(), + id: op.Id(), Author: op.Author, UnixTime: timestamp.Timestamp(op.UnixTime), Status: op.Status, @@ -51,27 +52,9 @@ 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 +// UnmarshalJSON is a two step JSON unmarshaling +// This workaround is necessary to avoid the inner OpBase.MarshalJSON +// overriding the outer op's MarshalJSON func (op *SetStatusOperation) UnmarshalJSON(data []byte) error { // Unmarshal OpBase and the op separately @@ -107,13 +90,13 @@ func NewSetStatusOp(author identity.Interface, unixTime int64, status Status) *S } type SetStatusTimelineItem struct { - id string + id entity.Id Author identity.Interface UnixTime timestamp.Timestamp Status Status } -func (s SetStatusTimelineItem) ID() string { +func (s SetStatusTimelineItem) Id() entity.Id { return s.id } diff --git a/bug/op_set_status_test.go b/bug/op_set_status_test.go index fc999234..ea032184 100644 --- a/bug/op_set_status_test.go +++ b/bug/op_set_status_test.go @@ -21,8 +21,9 @@ func TestSetStatusSerialize(t *testing.T) { err = json.Unmarshal(data, &after) assert.NoError(t, err) - // enforce creating the ID - before.ID() + // enforce creating the IDs + before.Id() + rene.Id() assert.Equal(t, before, &after) } diff --git a/bug/op_set_title.go b/bug/op_set_title.go index 7bebfadc..fadd29a9 100644 --- a/bug/op_set_title.go +++ b/bug/op_set_title.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/timestamp" @@ -16,15 +17,15 @@ var _ Operation = &SetTitleOperation{} // SetTitleOperation will change the title of a bug type SetTitleOperation struct { OpBase - Title string - Was string + Title string `json:"title"` + Was string `json:"was"` } func (op *SetTitleOperation) base() *OpBase { return &op.OpBase } -func (op *SetTitleOperation) ID() string { +func (op *SetTitleOperation) Id() entity.Id { return idOperation(op) } @@ -33,7 +34,7 @@ func (op *SetTitleOperation) Apply(snapshot *Snapshot) { snapshot.addActor(op.Author) item := &SetTitleTimelineItem{ - id: op.ID(), + id: op.Id(), Author: op.Author, UnixTime: timestamp.Timestamp(op.UnixTime), Title: op.Title, @@ -71,28 +72,9 @@ 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 +// UnmarshalJSON is a two step JSON unmarshaling +// This workaround is necessary to avoid the inner OpBase.MarshalJSON +// overriding the outer op's MarshalJSON func (op *SetTitleOperation) UnmarshalJSON(data []byte) error { // Unmarshal OpBase and the op separately @@ -131,14 +113,14 @@ func NewSetTitleOp(author identity.Interface, unixTime int64, title string, was } type SetTitleTimelineItem struct { - id string + id entity.Id Author identity.Interface UnixTime timestamp.Timestamp Title string Was string } -func (s SetTitleTimelineItem) ID() string { +func (s SetTitleTimelineItem) Id() entity.Id { return s.id } diff --git a/bug/op_set_title_test.go b/bug/op_set_title_test.go index 8ffe4f3c..19cbb12b 100644 --- a/bug/op_set_title_test.go +++ b/bug/op_set_title_test.go @@ -21,8 +21,9 @@ func TestSetTitleSerialize(t *testing.T) { err = json.Unmarshal(data, &after) assert.NoError(t, err) - // enforce creating the ID - before.ID() + // enforce creating the IDs + before.Id() + rene.Id() assert.Equal(t, before, &after) } diff --git a/bug/operation.go b/bug/operation.go index 2298a008..dd95e096 100644 --- a/bug/operation.go +++ b/bug/operation.go @@ -6,10 +6,11 @@ import ( "fmt" "time" - "github.com/MichaelMure/git-bug/identity" + "github.com/pkg/errors" + "github.com/MichaelMure/git-bug/entity" + "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" - "github.com/pkg/errors" ) // OperationType is an operation type identifier @@ -27,14 +28,12 @@ const ( SetMetadataOp ) -const unsetIDMarker = "unset" - // Operation define the interface to fulfill for an edit operation of a Bug type Operation interface { // base return the OpBase of the Operation, for package internal use base() *OpBase - // ID return the identifier of the operation, to be used for back references - ID() string + // Id return the identifier of the operation, to be used for back references + Id() entity.Id // Time return the time when the operation was added Time() time.Time // GetUnixTime return the unix timestamp when the operation was added @@ -55,57 +54,42 @@ type Operation interface { GetAuthor() identity.Interface } -func hashRaw(data []byte) string { - hasher := sha256.New() - // Write can't fail - _, _ = hasher.Write(data) - return fmt.Sprintf("%x", hasher.Sum(nil)) +func deriveId(data []byte) entity.Id { + sum := sha256.Sum256(data) + return entity.Id(fmt.Sprintf("%x", sum)) } -func idOperation(op Operation) string { +func idOperation(op Operation) entity.Id { base := op.base() if base.id == "" { // something went really wrong panic("op's id not set") } - if base.id == "unset" { - // This means we are trying to get the op's ID *before* it has been stored, for instance when + if base.id == entity.UnsetId { + // This means we are trying to get the op's Id *before* it has been stored, for instance when // adding multiple ops in one go in an OperationPack. - // As the ID is computed based on the actual bytes written on the disk, we are going to predict - // those and then get the ID. This is safe as it will be the exact same code writing on disk later. + // As the Id is computed based on the actual bytes written on the disk, we are going to predict + // those and then get the Id. This is safe as it will be the exact same code writing on disk later. data, err := json.Marshal(op) if err != nil { panic(err) } - base.id = hashRaw(data) + base.id = deriveId(data) } return base.id } -func IDIsValid(id string) bool { - // IDs have the same format as a git hash - if len(id) != 40 && len(id) != 64 { - return false - } - for _, r := range id { - if (r < 'a' || r > 'z') && (r < '0' || r > '9') { - return false - } - } - return true -} - // OpBase implement the common code for all operations type OpBase struct { - OperationType OperationType - Author identity.Interface - UnixTime int64 - Metadata map[string]string + OperationType OperationType `json:"type"` + Author identity.Interface `json:"author"` + UnixTime int64 `json:"timestamp"` + Metadata map[string]string `json:"metadata,omitempty"` // Not serialized. Store the op's id in memory. - id string + id entity.Id // Not serialized. Store the extra metadata in memory, // compiled from SetMetadataOperation. extraMetadata map[string]string @@ -117,27 +101,13 @@ func newOpBase(opType OperationType, author identity.Interface, unixTime int64) OperationType: opType, Author: author, UnixTime: unixTime, - id: unsetIDMarker, + id: entity.UnsetId, } } -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 { - // Compute the ID when loading the op from disk. - op.id = hashRaw(data) + // Compute the Id when loading the op from disk. + op.id = deriveId(data) aux := struct { OperationType OperationType `json:"type"` @@ -213,7 +183,7 @@ func (op *OpBase) SetMetadata(key string, value string) { } op.Metadata[key] = value - op.id = unsetIDMarker + op.id = entity.UnsetId } // GetMetadata retrieve arbitrary metadata about the operation diff --git a/bug/operation_pack_test.go b/bug/operation_pack_test.go index 713be7f0..21ac0a00 100644 --- a/bug/operation_pack_test.go +++ b/bug/operation_pack_test.go @@ -48,14 +48,16 @@ func TestOperationPackSerialize(t *testing.T) { err = json.Unmarshal(data, &opp2) assert.NoError(t, err) - ensureID(t, opp) + ensureIDs(t, opp) assert.Equal(t, opp, opp2) } -func ensureID(t *testing.T, opp *OperationPack) { +func ensureIDs(t *testing.T, opp *OperationPack) { for _, op := range opp.Operations { - id := op.ID() - require.True(t, IDIsValid(id)) + id := op.Id() + require.NoError(t, id.Validate()) + id = op.GetAuthor().Id() + require.NoError(t, id.Validate()) } } diff --git a/bug/operation_test.go b/bug/operation_test.go index c8dc246e..69c66dc8 100644 --- a/bug/operation_test.go +++ b/bug/operation_test.go @@ -94,26 +94,26 @@ func TestID(t *testing.T) { b, op, err := Create(rene, time.Now().Unix(), "title", "message") require.Nil(t, err) - id1 := op.ID() - require.True(t, IDIsValid(id1)) + id1 := op.Id() + require.NoError(t, id1.Validate()) err = b.Commit(repo) require.Nil(t, err) op2 := b.FirstOp() - id2 := op2.ID() - require.True(t, IDIsValid(id2)) + id2 := op2.Id() + require.NoError(t, id2.Validate()) require.Equal(t, id1, id2) - b2, err := ReadLocalBug(repo, b.id) + b2, err := ReadLocalBug(repo, b.Id()) require.Nil(t, err) op3 := b2.FirstOp() - id3 := op3.ID() - require.True(t, IDIsValid(id3)) + id3 := op3.Id() + require.NoError(t, id3.Validate()) require.Equal(t, id1, id3) } diff --git a/bug/snapshot.go b/bug/snapshot.go index b2e6f130..a937200f 100644 --- a/bug/snapshot.go +++ b/bug/snapshot.go @@ -4,12 +4,13 @@ import ( "fmt" "time" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" ) // Snapshot is a compiled form of the Bug data structure used for storage and merge type Snapshot struct { - id string + id entity.Id Status Status Title string @@ -26,15 +27,10 @@ type Snapshot struct { } // Return the Bug identifier -func (snap *Snapshot) Id() string { +func (snap *Snapshot) Id() entity.Id { return snap.id } -// Return the Bug identifier truncated for human consumption -func (snap *Snapshot) HumanId() string { - return FormatHumanID(snap.id) -} - // Return the last time a bug was modified func (snap *Snapshot) LastEditTime() time.Time { if len(snap.Operations) == 0 { @@ -59,9 +55,9 @@ func (snap *Snapshot) GetCreateMetadata(key string) (string, bool) { } // SearchTimelineItem will search in the timeline for an item matching the given hash -func (snap *Snapshot) SearchTimelineItem(ID string) (TimelineItem, error) { +func (snap *Snapshot) SearchTimelineItem(id entity.Id) (TimelineItem, error) { for i := range snap.Timeline { - if snap.Timeline[i].ID() == ID { + if snap.Timeline[i].Id() == id { return snap.Timeline[i], nil } } @@ -72,7 +68,7 @@ func (snap *Snapshot) SearchTimelineItem(ID string) (TimelineItem, error) { // SearchComment will search for a comment matching the given hash func (snap *Snapshot) SearchComment(id string) (*Comment, error) { for _, c := range snap.Comments { - if c.id == id { + if c.id.String() == id { return &c, nil } } @@ -103,7 +99,7 @@ func (snap *Snapshot) addParticipant(participant identity.Interface) { } // HasParticipant return true if the id is a participant -func (snap *Snapshot) HasParticipant(id string) bool { +func (snap *Snapshot) HasParticipant(id entity.Id) bool { for _, p := range snap.Participants { if p.Id() == id { return true @@ -113,7 +109,7 @@ func (snap *Snapshot) HasParticipant(id string) bool { } // HasAnyParticipant return true if one of the ids is a participant -func (snap *Snapshot) HasAnyParticipant(ids ...string) bool { +func (snap *Snapshot) HasAnyParticipant(ids ...entity.Id) bool { for _, id := range ids { if snap.HasParticipant(id) { return true @@ -123,7 +119,7 @@ func (snap *Snapshot) HasAnyParticipant(ids ...string) bool { } // HasActor return true if the id is a actor -func (snap *Snapshot) HasActor(id string) bool { +func (snap *Snapshot) HasActor(id entity.Id) bool { for _, p := range snap.Actors { if p.Id() == id { return true @@ -133,7 +129,7 @@ func (snap *Snapshot) HasActor(id string) bool { } // HasAnyActor return true if one of the ids is a actor -func (snap *Snapshot) HasAnyActor(ids ...string) bool { +func (snap *Snapshot) HasAnyActor(ids ...entity.Id) bool { for _, id := range ids { if snap.HasActor(id) { return true diff --git a/bug/timeline.go b/bug/timeline.go index 247c2927..4af1b92a 100644 --- a/bug/timeline.go +++ b/bug/timeline.go @@ -3,6 +3,7 @@ package bug import ( "strings" + "github.com/MichaelMure/git-bug/entity" "github.com/MichaelMure/git-bug/identity" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/timestamp" @@ -10,7 +11,7 @@ import ( type TimelineItem interface { // ID return the identifier of the item - ID() string + Id() entity.Id } // CommentHistoryStep hold one version of a message in the history @@ -25,7 +26,7 @@ type CommentHistoryStep struct { // CommentTimelineItem is a TimelineItem that holds a Comment and its edition history type CommentTimelineItem struct { - id string + id entity.Id Author identity.Interface Message string Files []git.Hash @@ -34,7 +35,7 @@ type CommentTimelineItem struct { History []CommentHistoryStep } -func NewCommentTimelineItem(ID string, comment Comment) CommentTimelineItem { +func NewCommentTimelineItem(ID entity.Id, comment Comment) CommentTimelineItem { return CommentTimelineItem{ id: ID, Author: comment.Author, @@ -51,7 +52,7 @@ func NewCommentTimelineItem(ID string, comment Comment) CommentTimelineItem { } } -func (c *CommentTimelineItem) ID() string { +func (c *CommentTimelineItem) Id() entity.Id { return c.id } |