From 76ac1787b8de8698b878d1837c5fa8f6fe6403fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Mur=C3=A9?= Date: Tue, 17 Jul 2018 19:28:37 +0200 Subject: [PATCH] add bug status + open/close commands --- bug/bug.go | 15 +++++++----- bug/operation.go | 9 ++++---- bug/operations/add_comment.go | 2 +- bug/operations/create.go | 9 +------- bug/operations/operations.go | 1 + bug/operations/set_status.go | 24 ++++++++++++++++++++ bug/operations/set_title.go | 2 +- bug/snapshot.go | 12 ++++++++++ bug/status.go | 20 ++++++++++++++++ commands/close.go | 39 ++++++++++++++++++++++++++++++++ commands/command.go | 2 ++ commands/comment.go | 9 ++++---- commands/ls.go | 2 +- commands/open.go | 39 ++++++++++++++++++++++++++++++++ tests/bug_test.go | 6 ++--- tests/operation_iterator_test.go | 2 ++ 16 files changed, 165 insertions(+), 28 deletions(-) create mode 100644 bug/operations/set_status.go create mode 100644 bug/status.go create mode 100644 commands/close.go create mode 100644 commands/open.go diff --git a/bug/bug.go b/bug/bug.go index c5268cc23a78680892a26c4bbade46488f9b0207..7f068c05b06893896ba7258f8dff76407653d1cf 100644 --- a/bug/bug.go +++ b/bug/bug.go @@ -182,17 +182,17 @@ func (bug *Bug) IsValid() bool { } } - // The very first Op should be a CREATE + // The very first Op should be a CreateOp firstOp := bug.firstOp() - if firstOp == nil || firstOp.OpType() != CREATE { + if firstOp == nil || firstOp.OpType() != CreateOp { return false } - // Check that there is no more CREATE op + // Check that there is no more CreateOp op it := NewOperationIterator(bug) createCount := 0 for it.Next() { - if it.Value().OpType() == CREATE { + if it.Value().OpType() == CreateOp { createCount++ } } @@ -351,7 +351,7 @@ func (bug *Bug) HumanId() string { } // Lookup for the very first operation of the bug. -// For a valid Bug, this operation should be a CREATE +// For a valid Bug, this operation should be a CreateOp func (bug *Bug) firstOp() Operation { for _, pack := range bug.packs { for _, op := range pack.Operations { @@ -368,7 +368,10 @@ func (bug *Bug) firstOp() Operation { // Compile a bug in a easily usable snapshot func (bug *Bug) Compile() Snapshot { - snap := Snapshot{} + snap := Snapshot{ + id: bug.id, + Status: OpenStatus, + } it := NewOperationIterator(bug) diff --git a/bug/operation.go b/bug/operation.go index 4414f2ad00a5c097a61cc41124898264945496b3..c9e7a555060d563221c5033c1bddc2a0af36f735 100644 --- a/bug/operation.go +++ b/bug/operation.go @@ -3,10 +3,11 @@ package bug type OperationType int const ( - UNKNOWN OperationType = iota - CREATE - SET_TITLE - ADD_COMMENT + _ OperationType = iota + CreateOp + SetTitleOp + AddCommentOp + SetStatusOp ) type Operation interface { diff --git a/bug/operations/add_comment.go b/bug/operations/add_comment.go index ce33522c155dd63d12e4e0d255cd082876021f13..2927295a3cfbc13c29460b919cde90ffda1a58bf 100644 --- a/bug/operations/add_comment.go +++ b/bug/operations/add_comment.go @@ -16,7 +16,7 @@ type AddCommentOperation struct { func NewAddCommentOp(author bug.Person, message string) AddCommentOperation { return AddCommentOperation{ - OpBase: bug.OpBase{OperationType: bug.ADD_COMMENT}, + OpBase: bug.OpBase{OperationType: bug.AddCommentOp}, Message: message, Author: author, Time: time.Now().Unix(), diff --git a/bug/operations/create.go b/bug/operations/create.go index f4ca11ad7cb99d39aba8036ba1d9f81eea38ab88..ad1d99acd1e29c1909294ee43ddf545f8be1e1f5 100644 --- a/bug/operations/create.go +++ b/bug/operations/create.go @@ -2,7 +2,6 @@ package operations import ( "github.com/MichaelMure/git-bug/bug" - "reflect" "time" ) @@ -20,7 +19,7 @@ type CreateOperation struct { func NewCreateOp(author bug.Person, title, message string) CreateOperation { return CreateOperation{ - OpBase: bug.OpBase{OperationType: bug.CREATE}, + OpBase: bug.OpBase{OperationType: bug.CreateOp}, Title: title, Message: message, Author: author, @@ -29,12 +28,6 @@ func NewCreateOp(author bug.Person, title, message string) CreateOperation { } func (op CreateOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { - empty := bug.Snapshot{} - - if !reflect.DeepEqual(snapshot, empty) { - panic("Create operation should never be applied on a non-empty snapshot") - } - snapshot.Title = op.Title snapshot.Comments = []bug.Comment{ { diff --git a/bug/operations/operations.go b/bug/operations/operations.go index f42d6e9a0f03dba944861a68d40d219297e21443..506929528de548a83196d42b0bb3d416529f11f5 100644 --- a/bug/operations/operations.go +++ b/bug/operations/operations.go @@ -7,4 +7,5 @@ func init() { gob.Register(AddCommentOperation{}) gob.Register(CreateOperation{}) gob.Register(SetTitleOperation{}) + gob.Register(SetStatusOperation{}) } diff --git a/bug/operations/set_status.go b/bug/operations/set_status.go new file mode 100644 index 0000000000000000000000000000000000000000..aa673bb14da04ed85d18209644438be99f6d1de5 --- /dev/null +++ b/bug/operations/set_status.go @@ -0,0 +1,24 @@ +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 NewSetStatusOp(status bug.Status) SetStatusOperation { + return SetStatusOperation{ + OpBase: bug.OpBase{OperationType: bug.SetStatusOp}, + Status: status, + } +} + +func (op SetStatusOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { + snapshot.Status = op.Status + return snapshot +} diff --git a/bug/operations/set_title.go b/bug/operations/set_title.go index 6d5cb87faf39ab5efa97fefd7a020f20ce4391fa..c5e0ab0e9b3e2cadd054a301182d4f4a629a80f0 100644 --- a/bug/operations/set_title.go +++ b/bug/operations/set_title.go @@ -11,7 +11,7 @@ type SetTitleOperation struct { func NewSetTitleOp(title string) SetTitleOperation { return SetTitleOperation{ - OpBase: bug.OpBase{OperationType: bug.SET_TITLE}, + OpBase: bug.OpBase{OperationType: bug.SetTitleOp}, Title: title, } } diff --git a/bug/snapshot.go b/bug/snapshot.go index 9b9acf873e16a6ee5041181d5ba9ce361ecb65f6..53a010bba440c992ccf51529077d81e0a4f5efa7 100644 --- a/bug/snapshot.go +++ b/bug/snapshot.go @@ -7,11 +7,23 @@ import ( // Snapshot is a compiled form of the Bug data structure used for storage and merge type Snapshot struct { + id string + Status Status Title string Comments []Comment Labels []Label } +// Return the Bug identifier +func (snap Snapshot) Id() string { + return snap.id +} + +// Return the Bug identifier truncated for human consumption +func (snap Snapshot) HumanId() string { + return fmt.Sprintf("%.8s", snap.id) +} + func (snap Snapshot) Summary() string { return fmt.Sprintf("c:%d l:%d %s", len(snap.Comments)-1, diff --git a/bug/status.go b/bug/status.go new file mode 100644 index 0000000000000000000000000000000000000000..b1b066ffa4a54db44b5d750501a5ec7ee86abc72 --- /dev/null +++ b/bug/status.go @@ -0,0 +1,20 @@ +package bug + +type Status int + +const ( + _ Status = iota + OpenStatus + ClosedStatus +) + +func (s Status) String() string { + switch s { + case OpenStatus: + return "open" + case ClosedStatus: + return "closed" + default: + return "unknown status" + } +} diff --git a/commands/close.go b/commands/close.go new file mode 100644 index 0000000000000000000000000000000000000000..6e668a50822da7f06079d24feb9daf7d89af15bc --- /dev/null +++ b/commands/close.go @@ -0,0 +1,39 @@ +package commands + +import ( + "errors" + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/bug/operations" + "github.com/MichaelMure/git-bug/repository" +) + +func runCloseBug(repo repository.Repo, args []string) error { + if len(args) > 1 { + return errors.New("Only closing one bug at a time is supported") + } + + if len(args) == 0 { + return errors.New("You must provide a bug id") + } + + prefix := args[0] + + b, err := bug.FindBug(repo, prefix) + if err != nil { + return err + } + + op := operations.NewSetStatusOp(bug.ClosedStatus) + + b.Append(op) + + err = b.Commit(repo) + + return err +} + +var closeCmd = &Command{ + Description: "Mark the bug as closed", + Usage: "", + RunMethod: runCloseBug, +} diff --git a/commands/command.go b/commands/command.go index cb231dcef72fb4d69283332fc9987fe8103050f0..111f9603745658b55c8143671f46fc7a47870488 100644 --- a/commands/command.go +++ b/commands/command.go @@ -44,10 +44,12 @@ var CommandMap map[string]*Command // We use init() to avoid a cycle in the data initialization because of the "commands" command func init() { CommandMap = map[string]*Command{ + "close": closeCmd, "commands": commandsCmd, "comment": commentCmd, "ls": lsCmd, "new": newCmd, + "open": openCmd, "pull": pullCmd, "push": pushCmd, "webui": webUICmd, diff --git a/commands/comment.go b/commands/comment.go index f635139b045b1885a3ee440d00dbbcf653c87aa7..9815dac4a12104c825c5610b665c4214dee137c9 100644 --- a/commands/comment.go +++ b/commands/comment.go @@ -22,11 +22,12 @@ func runComment(repo repository.Repo, args []string) error { var err error - if len(args) == 0 { - return errors.New("No bug id provided") - } if len(args) > 1 { - return errors.New("Only accepting one bug id is supported") + return errors.New("Only one bug id is supported") + } + + if len(args) == 0 { + return errors.New("You must provide a bug id") } prefix := args[0] diff --git a/commands/ls.go b/commands/ls.go index 94755b2d515a62752bd76d94fc9d4b6f88ebd14a..ac0bcfbb381b733f578ef167868b7a166b8527e4 100644 --- a/commands/ls.go +++ b/commands/ls.go @@ -22,7 +22,7 @@ func runLsBug(repo repository.Repo, args []string) error { snapshot := bug.Compile() - fmt.Printf("%s %s\t%s\n", bug.HumanId(), snapshot.Title, snapshot.Summary()) + fmt.Printf("%s %s\t%s\t%s\n", bug.HumanId(), snapshot.Status, snapshot.Title, snapshot.Summary()) } return nil diff --git a/commands/open.go b/commands/open.go new file mode 100644 index 0000000000000000000000000000000000000000..91704da3fcb260f4fc1d04e92a493f09518ae8ed --- /dev/null +++ b/commands/open.go @@ -0,0 +1,39 @@ +package commands + +import ( + "errors" + "github.com/MichaelMure/git-bug/bug" + "github.com/MichaelMure/git-bug/bug/operations" + "github.com/MichaelMure/git-bug/repository" +) + +func runOpenBug(repo repository.Repo, args []string) error { + if len(args) > 1 { + return errors.New("Only opening one bug at a time is supported") + } + + if len(args) == 0 { + return errors.New("You must provide a bug id") + } + + prefix := args[0] + + b, err := bug.FindBug(repo, prefix) + if err != nil { + return err + } + + op := operations.NewSetStatusOp(bug.OpenStatus) + + b.Append(op) + + err = b.Commit(repo) + + return err +} + +var openCmd = &Command{ + Description: "Mark the bug as open", + Usage: "", + RunMethod: runOpenBug, +} diff --git a/tests/bug_test.go b/tests/bug_test.go index a98cdc7f5536586685a18997f9712dff2b324663..175df1a803b82af941d0f5ae5ceb30e7fd8826d0 100644 --- a/tests/bug_test.go +++ b/tests/bug_test.go @@ -29,19 +29,19 @@ func TestBugValidity(t *testing.T) { bug1.Append(createOp) if !bug1.IsValid() { - t.Fatal("Bug with just a CREATE should be valid") + t.Fatal("Bug with just a CreateOp should be valid") } bug1.Append(createOp) if bug1.IsValid() { - t.Fatal("Bug with multiple CREATE should be invalid") + t.Fatal("Bug with multiple CreateOp should be invalid") } bug1.Commit(mockRepo) if bug1.IsValid() { - t.Fatal("Bug with multiple CREATE should be invalid") + t.Fatal("Bug with multiple CreateOp should be invalid") } } diff --git a/tests/operation_iterator_test.go b/tests/operation_iterator_test.go index 03747fa4be9fbf89d2f2d9238c6225a512e07c83..9c7c82b6e0f1195f0893627322def0f394a40988 100644 --- a/tests/operation_iterator_test.go +++ b/tests/operation_iterator_test.go @@ -16,6 +16,7 @@ var ( createOp = operations.NewCreateOp(rene, "title", "message") setTitleOp = operations.NewSetTitleOp("title2") addCommentOp = operations.NewAddCommentOp(rene, "message2") + SetStatusOp = operations.NewSetStatusOp(bug.ClosedStatus) mockRepo = repository.NewMockRepoForTest() ) @@ -29,6 +30,7 @@ func TestOpIterator(t *testing.T) { bug1.Append(createOp) bug1.Append(setTitleOp) + bug1.Append(SetStatusOp) bug1.Commit(mockRepo) bug1.Append(setTitleOp)