diff options
Diffstat (limited to 'operations')
-rw-r--r-- | operations/add_comment.go | 75 | ||||
-rw-r--r-- | operations/create.go | 90 | ||||
-rw-r--r-- | operations/create_test.go | 36 | ||||
-rw-r--r-- | operations/label_change.go | 186 | ||||
-rw-r--r-- | operations/operations.go | 17 | ||||
-rw-r--r-- | operations/operations_test.go | 72 | ||||
-rw-r--r-- | operations/set_status.go | 60 | ||||
-rw-r--r-- | operations/set_title.go | 90 |
8 files changed, 0 insertions, 626 deletions
diff --git a/operations/add_comment.go b/operations/add_comment.go deleted file mode 100644 index 56a2c606..00000000 --- a/operations/add_comment.go +++ /dev/null @@ -1,75 +0,0 @@ -package operations - -import ( - "fmt" - - "github.com/MichaelMure/git-bug/bug" - "github.com/MichaelMure/git-bug/util/git" - "github.com/MichaelMure/git-bug/util/text" -) - -// AddCommentOperation will add a new comment in the bug - -var _ bug.Operation = AddCommentOperation{} - -type AddCommentOperation struct { - *bug.OpBase - Message string `json:"message"` - // TODO: change for a map[string]util.hash to store the filename ? - Files []git.Hash `json:"files"` -} - -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) GetFiles() []git.Hash { - return op.Files -} - -func (op AddCommentOperation) Validate() error { - if err := bug.OpBaseValidate(op, bug.AddCommentOp); err != nil { - return err - } - - if text.Empty(op.Message) { - return fmt.Errorf("message is empty") - } - - if !text.Safe(op.Message) { - return fmt.Errorf("message is not fully printable") - } - - return nil -} - -func NewAddCommentOp(author bug.Person, unixTime int64, message string, files []git.Hash) AddCommentOperation { - return AddCommentOperation{ - OpBase: bug.NewOpBase(bug.AddCommentOp, author, unixTime), - Message: message, - Files: files, - } -} - -// Convenience function to apply the operation -func Comment(b bug.Interface, author bug.Person, unixTime int64, message string) error { - return CommentWithFiles(b, author, unixTime, message, nil) -} - -func CommentWithFiles(b bug.Interface, author bug.Person, unixTime int64, message string, files []git.Hash) error { - addCommentOp := NewAddCommentOp(author, unixTime, message, files) - if err := addCommentOp.Validate(); err != nil { - return err - } - b.Append(addCommentOp) - return nil -} diff --git a/operations/create.go b/operations/create.go deleted file mode 100644 index fd66e732..00000000 --- a/operations/create.go +++ /dev/null @@ -1,90 +0,0 @@ -package operations - -import ( - "fmt" - "strings" - - "github.com/MichaelMure/git-bug/bug" - "github.com/MichaelMure/git-bug/util/git" - "github.com/MichaelMure/git-bug/util/text" -) - -// CreateOperation define the initial creation of a bug - -var _ bug.Operation = CreateOperation{} - -type CreateOperation struct { - *bug.OpBase - Title string `json:"title"` - Message string `json:"message"` - Files []git.Hash `json:"files"` -} - -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) GetFiles() []git.Hash { - return op.Files -} - -func (op CreateOperation) Validate() error { - if err := bug.OpBaseValidate(op, bug.CreateOp); err != nil { - return err - } - - if text.Empty(op.Title) { - return fmt.Errorf("title is empty") - } - - if strings.Contains(op.Title, "\n") { - return fmt.Errorf("title should be a single line") - } - - if !text.Safe(op.Title) { - return fmt.Errorf("title is not fully printable") - } - - if !text.Safe(op.Message) { - return fmt.Errorf("message is not fully printable") - } - - return nil -} - -func NewCreateOp(author bug.Person, unixTime int64, title, message string, files []git.Hash) CreateOperation { - return CreateOperation{ - OpBase: bug.NewOpBase(bug.CreateOp, author, unixTime), - Title: title, - Message: message, - Files: files, - } -} - -// Convenience function to apply the operation -func Create(author bug.Person, unixTime int64, title, message string) (*bug.Bug, error) { - return CreateWithFiles(author, unixTime, title, message, nil) -} - -func CreateWithFiles(author bug.Person, unixTime int64, title, message string, files []git.Hash) (*bug.Bug, error) { - newBug := bug.NewBug() - createOp := NewCreateOp(author, unixTime, title, message, files) - - if err := createOp.Validate(); err != nil { - return nil, err - } - - newBug.Append(createOp) - - return newBug, nil -} diff --git a/operations/create_test.go b/operations/create_test.go deleted file mode 100644 index c32b2868..00000000 --- a/operations/create_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package operations - -import ( - "github.com/MichaelMure/git-bug/bug" - "reflect" - "testing" - "time" -) - -func TestCreate(t *testing.T) { - snapshot := bug.Snapshot{} - - var rene = bug.Person{ - Name: "René Descartes", - Email: "rene@descartes.fr", - } - - unix := time.Now().Unix() - - create := NewCreateOp(rene, unix, "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 deleted file mode 100644 index 83e3e692..00000000 --- a/operations/label_change.go +++ /dev/null @@ -1,186 +0,0 @@ -package operations - -import ( - "fmt" - "sort" - - "github.com/MichaelMure/git-bug/bug" - "github.com/pkg/errors" -) - -var _ bug.Operation = LabelChangeOperation{} - -// LabelChangeOperation define a Bug operation to add or remove labels -type LabelChangeOperation struct { - *bug.OpBase - Added []bug.Label `json:"added"` - Removed []bug.Label `json:"removed"` -} - -// 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 (op LabelChangeOperation) Validate() error { - if err := bug.OpBaseValidate(op, bug.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 bug.Person, unixTime int64, added, removed []bug.Label) LabelChangeOperation { - return LabelChangeOperation{ - OpBase: bug.NewOpBase(bug.LabelChangeOp, author, unixTime), - Added: added, - Removed: removed, - } -} - -// ChangeLabels is a convenience function to apply the operation -func ChangeLabels(b bug.Interface, author bug.Person, unixTime int64, add, remove []string) ([]LabelChangeResult, error) { - var added, removed []bug.Label - var results []LabelChangeResult - - snap := b.Compile() - - for _, str := range add { - label := bug.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 := bug.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 []bug.Label, label bug.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 bug.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)) - } -} diff --git a/operations/operations.go b/operations/operations.go deleted file mode 100644 index 020b8151..00000000 --- a/operations/operations.go +++ /dev/null @@ -1,17 +0,0 @@ -// Package operations contains the various bug operations. A bug operation is -// an atomic edit operation of a bug state. These operations are applied -// sequentially to compile the current state of the bug. -package operations - -import ( - "github.com/MichaelMure/git-bug/bug" -) - -// Package initialisation used to register operation's type for (de)serialization -func init() { - bug.Register(bug.CreateOp, CreateOperation{}) - bug.Register(bug.SetTitleOp, SetTitleOperation{}) - bug.Register(bug.AddCommentOp, AddCommentOperation{}) - bug.Register(bug.SetStatusOp, SetStatusOperation{}) - bug.Register(bug.LabelChangeOp, LabelChangeOperation{}) -} diff --git a/operations/operations_test.go b/operations/operations_test.go deleted file mode 100644 index b94c2c0c..00000000 --- a/operations/operations_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package operations - -import ( - "testing" - "time" - - "github.com/MichaelMure/git-bug/bug" - "github.com/MichaelMure/git-bug/util/git" -) - -func TestValidate(t *testing.T) { - rene := bug.Person{ - Name: "René Descartes", - Email: "rene@descartes.fr", - } - - unix := time.Now().Unix() - - good := []bug.Operation{ - NewCreateOp(rene, unix, "title", "message", nil), - NewSetTitleOp(rene, unix, "title2", "title1"), - NewAddCommentOp(rene, unix, "message2", nil), - NewSetStatusOp(rene, unix, bug.ClosedStatus), - NewLabelChangeOperation(rene, unix, []bug.Label{"added"}, []bug.Label{"removed"}), - } - - for _, op := range good { - if err := op.Validate(); err != nil { - t.Fatal(err) - } - } - - bad := []bug.Operation{ - // opbase - NewSetStatusOp(bug.Person{Name: "", Email: "rene@descartes.fr"}, unix, bug.ClosedStatus), - NewSetStatusOp(bug.Person{Name: "René Descartes\u001b", Email: "rene@descartes.fr"}, unix, bug.ClosedStatus), - NewSetStatusOp(bug.Person{Name: "René Descartes", Email: "rene@descartes.fr\u001b"}, unix, bug.ClosedStatus), - NewSetStatusOp(bug.Person{Name: "René \nDescartes", Email: "rene@descartes.fr"}, unix, bug.ClosedStatus), - NewSetStatusOp(bug.Person{Name: "René Descartes", Email: "rene@\ndescartes.fr"}, unix, bug.ClosedStatus), - CreateOperation{OpBase: &bug.OpBase{ - Author: rene, - UnixTime: 0, - OperationType: bug.CreateOp, - }, - Title: "title", - Message: "message", - }, - - NewCreateOp(rene, unix, "multi\nline", "message", nil), - NewCreateOp(rene, unix, "title", "message", []git.Hash{git.Hash("invalid")}), - NewCreateOp(rene, unix, "title\u001b", "message", nil), - NewCreateOp(rene, unix, "title", "message\u001b", nil), - NewSetTitleOp(rene, unix, "multi\nline", "title1"), - NewSetTitleOp(rene, unix, "title", "multi\nline"), - NewSetTitleOp(rene, unix, "title\u001b", "title2"), - NewSetTitleOp(rene, unix, "title", "title2\u001b"), - NewAddCommentOp(rene, unix, "", nil), - NewAddCommentOp(rene, unix, "message\u001b", nil), - NewAddCommentOp(rene, unix, "message", []git.Hash{git.Hash("invalid")}), - NewSetStatusOp(rene, unix, 1000), - NewSetStatusOp(rene, unix, 0), - NewLabelChangeOperation(rene, unix, []bug.Label{}, []bug.Label{}), - NewLabelChangeOperation(rene, unix, []bug.Label{"multi\nline"}, []bug.Label{}), - } - - for i, op := range bad { - if err := op.Validate(); err == nil { - t.Fatal("validation should have failed", i, op) - } - } - -} diff --git a/operations/set_status.go b/operations/set_status.go deleted file mode 100644 index 3e7eae4a..00000000 --- a/operations/set_status.go +++ /dev/null @@ -1,60 +0,0 @@ -package operations - -import ( - "github.com/MichaelMure/git-bug/bug" - "github.com/pkg/errors" -) - -// SetStatusOperation will change the status of a bug - -var _ bug.Operation = SetStatusOperation{} - -type SetStatusOperation struct { - *bug.OpBase - Status bug.Status `json:"status"` -} - -func (op SetStatusOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { - snapshot.Status = op.Status - - return snapshot -} - -func (op SetStatusOperation) Validate() error { - if err := bug.OpBaseValidate(op, bug.SetStatusOp); err != nil { - return err - } - - if err := op.Status.Validate(); err != nil { - return errors.Wrap(err, "status") - } - - return nil -} - -func NewSetStatusOp(author bug.Person, unixTime int64, status bug.Status) SetStatusOperation { - return SetStatusOperation{ - OpBase: bug.NewOpBase(bug.SetStatusOp, author, unixTime), - Status: status, - } -} - -// Convenience function to apply the operation -func Open(b bug.Interface, author bug.Person, unixTime int64) error { - op := NewSetStatusOp(author, unixTime, bug.OpenStatus) - if err := op.Validate(); err != nil { - return err - } - b.Append(op) - return nil -} - -// Convenience function to apply the operation -func Close(b bug.Interface, author bug.Person, unixTime int64) error { - op := NewSetStatusOp(author, unixTime, bug.ClosedStatus) - if err := op.Validate(); err != nil { - return err - } - b.Append(op) - return nil -} diff --git a/operations/set_title.go b/operations/set_title.go deleted file mode 100644 index e6964a65..00000000 --- a/operations/set_title.go +++ /dev/null @@ -1,90 +0,0 @@ -package operations - -import ( - "fmt" - "strings" - - "github.com/MichaelMure/git-bug/bug" - "github.com/MichaelMure/git-bug/util/text" -) - -// SetTitleOperation will change the title of a bug - -var _ bug.Operation = SetTitleOperation{} - -type SetTitleOperation struct { - *bug.OpBase - Title string `json:"title"` - Was string `json:"was"` -} - -func (op SetTitleOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { - snapshot.Title = op.Title - - return snapshot -} - -func (op SetTitleOperation) Validate() error { - if err := bug.OpBaseValidate(op, bug.SetTitleOp); err != nil { - return err - } - - if text.Empty(op.Title) { - return fmt.Errorf("title is empty") - } - - if strings.Contains(op.Title, "\n") { - return fmt.Errorf("title should be a single line") - } - - if !text.Safe(op.Title) { - return fmt.Errorf("title should be fully printable") - } - - if strings.Contains(op.Was, "\n") { - return fmt.Errorf("previous title should be a single line") - } - - if !text.Safe(op.Was) { - return fmt.Errorf("previous title should be fully printable") - } - - return nil -} - -func NewSetTitleOp(author bug.Person, unixTime int64, title string, was string) SetTitleOperation { - return SetTitleOperation{ - OpBase: bug.NewOpBase(bug.SetTitleOp, author, unixTime), - Title: title, - Was: was, - } -} - -// Convenience function to apply the operation -func SetTitle(b bug.Interface, author bug.Person, unixTime int64, title string) error { - 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, unixTime, title, was) - - if err := setTitleOp.Validate(); err != nil { - return err - } - - b.Append(setTitleOp) - return nil -} |