diff options
Diffstat (limited to 'operations')
-rw-r--r-- | operations/add_comment.go | 52 | ||||
-rw-r--r-- | operations/create.go | 57 | ||||
-rw-r--r-- | operations/create_test.go | 33 | ||||
-rw-r--r-- | operations/label_change.go | 128 | ||||
-rw-r--r-- | operations/operations.go | 12 | ||||
-rw-r--r-- | operations/set_status.go | 39 | ||||
-rw-r--r-- | operations/set_title.go | 52 |
7 files changed, 373 insertions, 0 deletions
diff --git a/operations/add_comment.go b/operations/add_comment.go new file mode 100644 index 00000000..24fa2696 --- /dev/null +++ b/operations/add_comment.go @@ -0,0 +1,52 @@ +package operations + +import ( + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/util/git" +) + +// AddCommentOperation will add a new comment in the bug + +var _ bug.Operation = AddCommentOperation{} + +type AddCommentOperation struct { + bug.OpBase + Message string + // TODO: change for a map[string]util.hash to store the filename ? + files []git.Hash +} + +func (op AddCommentOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { + comment := bug.Comment{ + Message: op.Message, + Author: op.Author, + Files: op.files, + UnixTime: op.UnixTime, + } + + snapshot.Comments = append(snapshot.Comments, comment) + + return snapshot +} + +func (op AddCommentOperation) Files() []git.Hash { + return op.files +} + +func NewAddCommentOp(author bug.Person, message string, files []git.Hash) AddCommentOperation { + return AddCommentOperation{ + OpBase: bug.NewOpBase(bug.AddCommentOp, author), + Message: message, + files: files, + } +} + +// Convenience function to apply the operation +func Comment(b bug.Interface, author bug.Person, message string) { + CommentWithFiles(b, author, message, nil) +} + +func CommentWithFiles(b bug.Interface, author bug.Person, message string, files []git.Hash) { + addCommentOp := NewAddCommentOp(author, message, files) + b.Append(addCommentOp) +} diff --git a/operations/create.go b/operations/create.go new file mode 100644 index 00000000..81e5af93 --- /dev/null +++ b/operations/create.go @@ -0,0 +1,57 @@ +package operations + +import ( + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/util/git" +) + +// CreateOperation define the initial creation of a bug + +var _ bug.Operation = CreateOperation{} + +type CreateOperation struct { + bug.OpBase + Title string + Message string + files []git.Hash +} + +func (op CreateOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { + snapshot.Title = op.Title + snapshot.Comments = []bug.Comment{ + { + Message: op.Message, + Author: op.Author, + UnixTime: op.UnixTime, + }, + } + snapshot.Author = op.Author + snapshot.CreatedAt = op.Time() + return snapshot +} + +func (op CreateOperation) Files() []git.Hash { + return op.files +} + +func NewCreateOp(author bug.Person, title, message string, files []git.Hash) CreateOperation { + return CreateOperation{ + OpBase: bug.NewOpBase(bug.CreateOp, author), + Title: title, + Message: message, + files: files, + } +} + +// Convenience function to apply the operation +func Create(author bug.Person, title, message string) (*bug.Bug, error) { + return CreateWithFiles(author, title, message, nil) +} + +func CreateWithFiles(author bug.Person, title, message string, files []git.Hash) (*bug.Bug, error) { + newBug := bug.NewBug() + createOp := NewCreateOp(author, title, message, files) + newBug.Append(createOp) + + return newBug, nil +} diff --git a/operations/create_test.go b/operations/create_test.go new file mode 100644 index 00000000..a20472d3 --- /dev/null +++ b/operations/create_test.go @@ -0,0 +1,33 @@ +package operations + +import ( + "github.com/MichaelMure/git-bug/bug" + "reflect" + "testing" +) + +func TestCreate(t *testing.T) { + snapshot := bug.Snapshot{} + + var rene = bug.Person{ + Name: "René Descartes", + Email: "rene@descartes.fr", + } + + create := NewCreateOp(rene, "title", "message", nil) + + snapshot = create.Apply(snapshot) + + expected := bug.Snapshot{ + Title: "title", + Comments: []bug.Comment{ + {Author: rene, Message: "message", UnixTime: create.UnixTime}, + }, + Author: rene, + CreatedAt: create.Time(), + } + + if !reflect.DeepEqual(snapshot, expected) { + t.Fatalf("%v different than %v", snapshot, expected) + } +} diff --git a/operations/label_change.go b/operations/label_change.go new file mode 100644 index 00000000..551b8be0 --- /dev/null +++ b/operations/label_change.go @@ -0,0 +1,128 @@ +package operations + +import ( + "fmt" + "io" + "io/ioutil" + "sort" + + "github.com/MichaelMure/git-bug/bug" +) + +var _ bug.Operation = LabelChangeOperation{} + +// LabelChangeOperation define a Bug operation to add or remove labels +type LabelChangeOperation struct { + bug.OpBase + Added []bug.Label + Removed []bug.Label +} + +// Apply apply the operation +func (op LabelChangeOperation) Apply(snapshot bug.Snapshot) bug.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 NewLabelChangeOperation(author bug.Person, added, removed []bug.Label) LabelChangeOperation { + return LabelChangeOperation{ + OpBase: bug.NewOpBase(bug.LabelChangeOp, author), + Added: added, + Removed: removed, + } +} + +// ChangeLabels is a convenience function to apply the operation +func ChangeLabels(out io.Writer, b bug.Interface, author bug.Person, add, remove []string) error { + // TODO: return a channel of result (like MergeAll) instead of formatting the result for the upper layers + var added, removed []bug.Label + + if out == nil { + out = ioutil.Discard + } + + snap := b.Compile() + + for _, str := range add { + label := bug.Label(str) + + // check for duplicate + if labelExist(added, label) { + fmt.Fprintf(out, "label \"%s\" is a duplicate\n", str) + continue + } + + // check that the label doesn't already exist + if labelExist(snap.Labels, label) { + fmt.Fprintf(out, "label \"%s\" is already set on this bug\n", str) + continue + } + + added = append(added, label) + } + + for _, str := range remove { + label := bug.Label(str) + + // check for duplicate + if labelExist(removed, label) { + fmt.Fprintf(out, "label \"%s\" is a duplicate\n", str) + continue + } + + // check that the label actually exist + if !labelExist(snap.Labels, label) { + fmt.Fprintf(out, "label \"%s\" doesn't exist on this bug\n", str) + continue + } + + removed = append(removed, label) + } + + if len(added) == 0 && len(removed) == 0 { + return fmt.Errorf("no label added or removed") + } + + labelOp := NewLabelChangeOperation(author, added, removed) + + b.Append(labelOp) + + return nil +} + +func labelExist(labels []bug.Label, label bug.Label) bool { + for _, l := range labels { + if l == label { + return true + } + } + + return false +} diff --git a/operations/operations.go b/operations/operations.go new file mode 100644 index 00000000..0bfd3b84 --- /dev/null +++ b/operations/operations.go @@ -0,0 +1,12 @@ +package operations + +import "encoding/gob" + +// Package initialisation used to register operation's type for (de)serialization +func init() { + gob.Register(AddCommentOperation{}) + gob.Register(CreateOperation{}) + gob.Register(SetTitleOperation{}) + gob.Register(SetStatusOperation{}) + gob.Register(LabelChangeOperation{}) +} diff --git a/operations/set_status.go b/operations/set_status.go new file mode 100644 index 00000000..bafcf5ee --- /dev/null +++ b/operations/set_status.go @@ -0,0 +1,39 @@ +package operations + +import ( + "github.com/MichaelMure/git-bug/bug" +) + +// SetStatusOperation will change the status of a bug + +var _ bug.Operation = SetStatusOperation{} + +type SetStatusOperation struct { + bug.OpBase + Status bug.Status +} + +func (op SetStatusOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { + snapshot.Status = op.Status + + return snapshot +} + +func NewSetStatusOp(author bug.Person, status bug.Status) SetStatusOperation { + return SetStatusOperation{ + OpBase: bug.NewOpBase(bug.SetStatusOp, author), + Status: status, + } +} + +// Convenience function to apply the operation +func Open(b bug.Interface, author bug.Person) { + op := NewSetStatusOp(author, bug.OpenStatus) + b.Append(op) +} + +// Convenience function to apply the operation +func Close(b bug.Interface, author bug.Person) { + op := NewSetStatusOp(author, bug.ClosedStatus) + b.Append(op) +} diff --git a/operations/set_title.go b/operations/set_title.go new file mode 100644 index 00000000..5bd6260a --- /dev/null +++ b/operations/set_title.go @@ -0,0 +1,52 @@ +package operations + +import ( + "github.com/MichaelMure/git-bug/bug" +) + +// SetTitleOperation will change the title of a bug + +var _ bug.Operation = SetTitleOperation{} + +type SetTitleOperation struct { + bug.OpBase + Title string + Was string +} + +func (op SetTitleOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { + snapshot.Title = op.Title + + return snapshot +} + +func NewSetTitleOp(author bug.Person, title string, was string) SetTitleOperation { + return SetTitleOperation{ + OpBase: bug.NewOpBase(bug.SetTitleOp, author), + Title: title, + Was: was, + } +} + +// Convenience function to apply the operation +func SetTitle(b bug.Interface, author bug.Person, title string) { + it := bug.NewOperationIterator(b) + + var lastTitleOp bug.Operation + for it.Next() { + op := it.Value() + if op.OpType() == bug.SetTitleOp { + lastTitleOp = op + } + } + + var was string + if lastTitleOp != nil { + was = lastTitleOp.(SetTitleOperation).Title + } else { + was = b.FirstOp().(CreateOperation).Title + } + + setTitleOp := NewSetTitleOp(author, title, was) + b.Append(setTitleOp) +} |