create the Bug structure

Michael Muré created

Change summary

bug/bug.go                       | 94 ++++++++++++++++++++++++++++-----
bug/comment_test.go              | 12 ----
bug/operation.go                 |  8 --
bug/operation_pack.go            | 20 +++++++
bug/operations/create.go         |  6 +-
bug/operations/operation_test.go | 16 ++--
bug/operations/set_title.go      |  6 +-
bug/person.go                    |  2 
bug/snapshot.go                  |  8 ++
commands/commands.go             | 12 ----
commands/new.go                  | 23 +++----
notes                            |  1 
12 files changed, 136 insertions(+), 72 deletions(-)

Detailed changes

bug/bug.go 🔗

@@ -1,18 +1,84 @@
 package bug
 
-// Snapshot is a compiled form of the Bug data structure used for storage and merge
-type Snapshot struct {
-	Title    string
-	Comments []Comment
-	Labels   []Label
+import (
+	"github.com/kevinburke/go.uuid"
+)
+
+// Bug hold the data of a bug thread, organized in a way close to
+// how it will be persisted inside Git. This is the datastructure
+// used for merge of two different version.
+type Bug struct {
+	// Id used as unique identifier
+	Id uuid.UUID
+
+	// TODO: need a way to order bugs
+	// Probably a Lamport clock
+
+	Packs []OperationPack
+
+	Staging OperationPack
 }
 
-//func (bug Bug) Check() error {
-//	if bug.Operations.Len() == 0 {
-//		return "Empty operation log"
-//	}
-//
-//	if bug.Operations.Elems()
-//
-//	return true
-//}
+// Create a new Bug
+func NewBug() (*Bug, error) {
+
+	// Creating UUID Version 4
+	id, err := uuid.ID4()
+
+	if err != nil {
+		return nil, err
+	}
+
+	return &Bug{
+		Id: id,
+	}, nil
+}
+
+// IsValid check if the Bug data is valid
+func (bug *Bug) IsValid() bool {
+	// non-empty
+	if len(bug.Packs) == 0 {
+		return false
+	}
+
+	// check if each pack is valid
+	for _, pack := range bug.Packs {
+		if !pack.IsValid() {
+			return false
+		}
+	}
+
+	// The very first Op should be a CREATE
+	firstOp := bug.Packs[0].Operations[0]
+	if firstOp.OpType() != CREATE {
+		return false
+	}
+
+	// Check that there is no more CREATE op
+	it := NewOperationIterator(bug)
+	createCount := 0
+	for it.Next() {
+		if it.Value().OpType() == CREATE {
+			createCount++
+		}
+	}
+
+	if createCount != 1 {
+		return false
+	}
+
+	return true
+}
+
+func (bug *Bug) Append(op Operation) {
+	bug.Staging.Append(op)
+}
+
+func (bug *Bug) Commit() {
+	bug.Packs = append(bug.Packs, bug.Staging)
+	bug.Staging = OperationPack{}
+}
+
+func (bug *Bug) HumanId() string {
+	return bug.Id.String()
+}

bug/comment_test.go 🔗

@@ -1,12 +0,0 @@
-package bug
-
-import "testing"
-
-func TestCommentEquality(t *testing.T) {
-	c1 := Comment{}
-	c2 := Comment{}
-
-	if c1 != c2 {
-		t.Fatal()
-	}
-}

bug/operations/operation.go → bug/operation.go 🔗

@@ -1,8 +1,4 @@
-package operations
-
-import (
-	"github.com/MichaelMure/git-bug/bug"
-)
+package bug
 
 type OperationType int
 
@@ -15,5 +11,5 @@ const (
 
 type Operation interface {
 	OpType() OperationType
-	Apply(snapshot bug.Snapshot) bug.Snapshot
+	Apply(snapshot Snapshot) Snapshot
 }

bug/operation_pack.go 🔗

@@ -0,0 +1,20 @@
+package bug
+
+// OperationPack represent an ordered set of operation to apply
+// to a Bug. These operations are stored in a single Git commit.
+//
+// These commits will be linked together in a linear chain of commits
+// inside Git to form the complete ordered chain of operation to
+// apply to get the final state of the Bug
+type OperationPack struct {
+	Operations []Operation
+}
+
+// Append a new operation to the pack
+func (opp *OperationPack) Append(op Operation) {
+	opp.Operations = append(opp.Operations, op)
+}
+
+func (opp *OperationPack) IsValid() bool {
+	return len(opp.Operations) > 0
+}

bug/operations/create.go 🔗

@@ -7,7 +7,7 @@ import (
 
 // CreateOperation define the initial creation of a bug
 
-var _ Operation = CreateOperation{}
+var _ bug.Operation = CreateOperation{}
 
 type CreateOperation struct {
 	Title   string
@@ -23,8 +23,8 @@ func NewCreateOp(author bug.Person, title, message string) CreateOperation {
 	}
 }
 
-func (op CreateOperation) OpType() OperationType {
-	return CREATE
+func (op CreateOperation) OpType() bug.OperationType {
+	return bug.CREATE
 }
 
 func (op CreateOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {

bug/operations/operation_test.go 🔗

@@ -11,8 +11,8 @@ type CreateOperation2 struct {
 	Message string
 }
 
-func (op CreateOperation2) OpType() OperationType {
-	return UNKNOW
+func (op CreateOperation2) OpType() bug.OperationType {
+	return bug.UNKNOW
 }
 
 func (op CreateOperation2) Apply(snapshot bug.Snapshot) bug.Snapshot {
@@ -26,16 +26,16 @@ func TestOperationsEquality(t *testing.T) {
 		Email: "rene@descartes.fr",
 	}
 
-	var A Operation = NewCreateOp(rene, "title", "message")
-	var B Operation = NewCreateOp(rene, "title", "message")
-	var C Operation = NewCreateOp(rene, "title", "different message")
+	var A bug.Operation = NewCreateOp(rene, "title", "message")
+	var B bug.Operation = NewCreateOp(rene, "title", "message")
+	var C bug.Operation = NewCreateOp(rene, "title", "different message")
 
 	if A != B {
-		t.Fatal("Equal value operations should be tested equals")
+		t.Fatal("Equal value ops should be tested equals")
 	}
 
 	if A == C {
-		t.Fatal("Different value operations should be tested different")
+		t.Fatal("Different value ops should be tested different")
 	}
 
 	D := CreateOperation2{Title: "title", Message: "message"}
@@ -49,7 +49,7 @@ func TestOperationsEquality(t *testing.T) {
 		Email: "isaac@newton.uk",
 	}
 
-	var E Operation = NewCreateOp(isaac, "title", "message")
+	var E bug.Operation = NewCreateOp(isaac, "title", "message")
 
 	if A == E {
 		t.Fatal("Operation equality should handle the author")

bug/operations/set_title.go 🔗

@@ -2,7 +2,7 @@ package operations
 
 import "github.com/MichaelMure/git-bug/bug"
 
-var _ Operation = SetTitleOperation{}
+var _ bug.Operation = SetTitleOperation{}
 
 type SetTitleOperation struct {
 	Title string
@@ -14,8 +14,8 @@ func NewSetTitleOp(title string) SetTitleOperation {
 	}
 }
 
-func (op SetTitleOperation) OpType() OperationType {
-	return SET_TITLE
+func (op SetTitleOperation) OpType() bug.OperationType {
+	return bug.SET_TITLE
 }
 
 func (op SetTitleOperation) Apply(snapshot bug.Snapshot) bug.Snapshot {

bug/person.go 🔗

@@ -2,9 +2,9 @@ package bug
 
 import (
 	"encoding/json"
+	"errors"
 	"github.com/MichaelMure/git-bug/repository"
 	"github.com/MichaelMure/git-bug/util"
-	"github.com/pkg/errors"
 )
 
 type Person struct {

bug/snapshot.go 🔗

@@ -0,0 +1,8 @@
+package bug
+
+// Snapshot is a compiled form of the Bug data structure used for storage and merge
+type Snapshot struct {
+	Title    string
+	Comments []Comment
+	Labels   []Label
+}

commands/commands.go 🔗

@@ -27,16 +27,4 @@ var CommandMap = map[string]*Command{
 	"new":  newCmd,
 	"pull": pullCmd,
 	"push": pushCmd,
-
-	/*"abandon": abandonCmd,
-	"accept":  acceptCmd,
-	"comment": commentCmd,
-	"list":    listCmd,
-	"pull":    pullCmd,
-	"push":    pushCmd,
-	"rebase":  rebaseCmd,
-	"reject":  rejectCmd,
-	"request": requestCmd,
-	"show":    showCmd,
-	"submit":  submitCmd,*/
 }

commands/new.go 🔗

@@ -1,12 +1,13 @@
 package commands
 
 import (
+	"errors"
 	"flag"
 	"fmt"
 	"github.com/MichaelMure/git-bug/bug"
+	"github.com/MichaelMure/git-bug/bug/operations"
 	"github.com/MichaelMure/git-bug/commands/input"
 	"github.com/MichaelMure/git-bug/repository"
-	"github.com/pkg/errors"
 )
 
 var newFlagSet = flag.NewFlagSet("new", flag.ExitOnError)
@@ -16,7 +17,7 @@ var (
 	newMessage     = newFlagSet.String("m", "", "Provide a message to describe the issue")
 )
 
-func newBug(repo repository.Repo, args []string) error {
+func RunNewBug(repo repository.Repo, args []string) error {
 	newFlagSet.Parse(args)
 	args = newFlagSet.Args()
 
@@ -50,19 +51,15 @@ func newBug(repo repository.Repo, args []string) error {
 		return err
 	}
 
-	comment := bug.Comment{
-		Author:  author,
-		Message: *newMessage,
-	}
-
-	bug := bug.Snapshot{
-		Title:    title,
-		Comments: []bug.Comment{comment},
+	newbug, err := bug.NewBug()
+	if err != nil {
+		return err
 	}
 
-	fmt.Println(bug)
+	createOp := operations.NewCreateOp(author, title, *newMessage)
 
-	author.Store(repo)
+	newbug.Append(createOp)
+	newbug.Commit()
 
 	return nil
 
@@ -73,5 +70,5 @@ var newCmd = &Command{
 		fmt.Printf("Usage: %s new <title> [<option>...]\n\nOptions:\n", arg0)
 		newFlagSet.PrintDefaults()
 	},
-	RunMethod: newBug,
+	RunMethod: RunNewBug,
 }

notes 🔗

@@ -14,6 +14,7 @@ git push origin "refs/bug/*"
 git fetch origin "refs/bug/*:refs/bug/*"
 
 
+git show-ref refs/bug