From 1bf268cebc84a9de1e538cbb54bcc0f434022192 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Fri, 28 Sep 2018 20:39:39 +0200 Subject: merge package operations into bug, they are tightly coupled anyway --- bug/op_label_change.go | 189 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 bug/op_label_change.go (limited to 'bug/op_label_change.go') diff --git a/bug/op_label_change.go b/bug/op_label_change.go new file mode 100644 index 00000000..120671fb --- /dev/null +++ b/bug/op_label_change.go @@ -0,0 +1,189 @@ +package bug + +import ( + "fmt" + "sort" + + "github.com/pkg/errors" +) + +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"` +} + +func (op LabelChangeOperation) base() *OpBase { + return op.OpBase +} + +// Apply apply the operation +func (op LabelChangeOperation) Apply(snapshot Snapshot) Snapshot { + // Add in the set +AddLoop: + for _, added := range op.Added { + for _, label := range snapshot.Labels { + if label == added { + // Already exist + continue AddLoop + } + } + + snapshot.Labels = append(snapshot.Labels, added) + } + + // Remove in the set + for _, removed := range op.Removed { + for i, label := range snapshot.Labels { + if label == removed { + snapshot.Labels[i] = snapshot.Labels[len(snapshot.Labels)-1] + snapshot.Labels = snapshot.Labels[:len(snapshot.Labels)-1] + } + } + } + + // Sort + sort.Slice(snapshot.Labels, func(i, j int) bool { + return string(snapshot.Labels[i]) < string(snapshot.Labels[j]) + }) + + return snapshot +} + +func (op LabelChangeOperation) Validate() error { + if err := opBaseValidate(op, LabelChangeOp); err != nil { + return err + } + + for _, l := range op.Added { + if err := l.Validate(); err != nil { + return errors.Wrap(err, "added label") + } + } + + for _, l := range op.Removed { + if err := l.Validate(); err != nil { + return errors.Wrap(err, "removed label") + } + } + + if len(op.Added)+len(op.Removed) <= 0 { + return fmt.Errorf("no label change") + } + + return nil +} + +func NewLabelChangeOperation(author Person, unixTime int64, added, removed []Label) LabelChangeOperation { + return LabelChangeOperation{ + OpBase: newOpBase(LabelChangeOp, author, unixTime), + Added: added, + Removed: removed, + } +} + +// ChangeLabels is a convenience function to apply the operation +func ChangeLabels(b Interface, author Person, unixTime int64, add, remove []string) ([]LabelChangeResult, error) { + var added, removed []Label + var results []LabelChangeResult + + snap := b.Compile() + + for _, str := range add { + label := Label(str) + + // check for duplicate + if labelExist(added, label) { + results = append(results, LabelChangeResult{Label: label, Status: LabelChangeDuplicateInOp}) + continue + } + + // check that the label doesn't already exist + if labelExist(snap.Labels, label) { + results = append(results, LabelChangeResult{Label: label, Status: LabelChangeAlreadySet}) + continue + } + + added = append(added, label) + results = append(results, LabelChangeResult{Label: label, Status: LabelChangeAdded}) + } + + for _, str := range remove { + label := Label(str) + + // check for duplicate + if labelExist(removed, label) { + results = append(results, LabelChangeResult{Label: label, Status: LabelChangeDuplicateInOp}) + continue + } + + // check that the label actually exist + if !labelExist(snap.Labels, label) { + results = append(results, LabelChangeResult{Label: label, Status: LabelChangeDoesntExist}) + continue + } + + removed = append(removed, label) + results = append(results, LabelChangeResult{Label: label, Status: LabelChangeRemoved}) + } + + if len(added) == 0 && len(removed) == 0 { + return results, fmt.Errorf("no label added or removed") + } + + labelOp := NewLabelChangeOperation(author, unixTime, added, removed) + + if err := labelOp.Validate(); err != nil { + return nil, err + } + + b.Append(labelOp) + + return results, nil +} + +func labelExist(labels []Label, label Label) bool { + for _, l := range labels { + if l == label { + return true + } + } + + return false +} + +type LabelChangeStatus int + +const ( + _ LabelChangeStatus = iota + LabelChangeAdded + LabelChangeRemoved + LabelChangeDuplicateInOp + LabelChangeAlreadySet + LabelChangeDoesntExist +) + +type LabelChangeResult struct { + Label Label + Status LabelChangeStatus +} + +func (l LabelChangeResult) String() string { + switch l.Status { + case LabelChangeAdded: + return fmt.Sprintf("label %s added", l.Label) + case LabelChangeRemoved: + return fmt.Sprintf("label %s removed", l.Label) + case LabelChangeDuplicateInOp: + return fmt.Sprintf("label %s is a duplicate", l.Label) + case LabelChangeAlreadySet: + return fmt.Sprintf("label %s was already set", l.Label) + case LabelChangeDoesntExist: + return fmt.Sprintf("label %s doesn't exist on this bug", l.Label) + default: + panic(fmt.Sprintf("unknown label change status %v", l.Status)) + } +} -- cgit From 794d014fae9a78bd8664e6628a20902bd6dc767a Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Fri, 28 Sep 2018 23:51:47 +0200 Subject: bug: define a hash-based identifier for an operation --- bug/op_label_change.go | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'bug/op_label_change.go') diff --git a/bug/op_label_change.go b/bug/op_label_change.go index 120671fb..c245d1a5 100644 --- a/bug/op_label_change.go +++ b/bug/op_label_change.go @@ -4,6 +4,7 @@ import ( "fmt" "sort" + "github.com/MichaelMure/git-bug/util/git" "github.com/pkg/errors" ) @@ -20,6 +21,10 @@ func (op LabelChangeOperation) base() *OpBase { return op.OpBase } +func (op LabelChangeOperation) Hash() (git.Hash, error) { + return hashOperation(op) +} + // Apply apply the operation func (op LabelChangeOperation) Apply(snapshot Snapshot) Snapshot { // Add in the set -- cgit From 41e61a67b63e4d6c517005cf6f427115a664bdb5 Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sat, 29 Sep 2018 11:28:18 +0200 Subject: bug: apply an operation with a pointer to the snapshot --- bug/op_label_change.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'bug/op_label_change.go') diff --git a/bug/op_label_change.go b/bug/op_label_change.go index c245d1a5..8909cf56 100644 --- a/bug/op_label_change.go +++ b/bug/op_label_change.go @@ -26,7 +26,7 @@ func (op LabelChangeOperation) Hash() (git.Hash, error) { } // Apply apply the operation -func (op LabelChangeOperation) Apply(snapshot Snapshot) Snapshot { +func (op LabelChangeOperation) Apply(snapshot *Snapshot) { // Add in the set AddLoop: for _, added := range op.Added { @@ -54,8 +54,6 @@ AddLoop: sort.Slice(snapshot.Labels, func(i, j int) bool { return string(snapshot.Labels[i]) < string(snapshot.Labels[j]) }) - - return snapshot } func (op LabelChangeOperation) Validate() error { -- cgit From c46d01f8c10e6363b680fa6876e91bd8eaf3bb3e Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Sat, 29 Sep 2018 20:41:19 +0200 Subject: bug: implement comment edition - add a new operation - add a new "timeline" in the snapshot that hold a processed version of the operations --- bug/op_label_change.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'bug/op_label_change.go') diff --git a/bug/op_label_change.go b/bug/op_label_change.go index 8909cf56..5f2dbd6f 100644 --- a/bug/op_label_change.go +++ b/bug/op_label_change.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" ) -var _ Operation = LabelChangeOperation{} +var _ Operation = &LabelChangeOperation{} // LabelChangeOperation define a Bug operation to add or remove labels type LabelChangeOperation struct { @@ -17,16 +17,16 @@ type LabelChangeOperation struct { Removed []Label `json:"removed"` } -func (op LabelChangeOperation) base() *OpBase { +func (op *LabelChangeOperation) base() *OpBase { return op.OpBase } -func (op LabelChangeOperation) Hash() (git.Hash, error) { +func (op *LabelChangeOperation) Hash() (git.Hash, error) { return hashOperation(op) } // Apply apply the operation -func (op LabelChangeOperation) Apply(snapshot *Snapshot) { +func (op *LabelChangeOperation) Apply(snapshot *Snapshot) { // Add in the set AddLoop: for _, added := range op.Added { @@ -54,9 +54,11 @@ AddLoop: sort.Slice(snapshot.Labels, func(i, j int) bool { return string(snapshot.Labels[i]) < string(snapshot.Labels[j]) }) + + snapshot.Timeline = append(snapshot.Timeline, op) } -func (op LabelChangeOperation) Validate() error { +func (op *LabelChangeOperation) Validate() error { if err := opBaseValidate(op, LabelChangeOp); err != nil { return err } @@ -80,8 +82,8 @@ func (op LabelChangeOperation) Validate() error { return nil } -func NewLabelChangeOperation(author Person, unixTime int64, added, removed []Label) LabelChangeOperation { - return LabelChangeOperation{ +func NewLabelChangeOperation(author Person, unixTime int64, added, removed []Label) *LabelChangeOperation { + return &LabelChangeOperation{ OpBase: newOpBase(LabelChangeOp, author, unixTime), Added: added, Removed: removed, -- cgit