diff options
-rw-r--r-- | bug/bug.go | 2 | ||||
-rw-r--r-- | bug/bug_actions.go (renamed from bug/remote_actions.go) | 40 | ||||
-rw-r--r-- | bug/operations/add_comment.go | 5 | ||||
-rw-r--r-- | bug/operations/create.go | 8 | ||||
-rw-r--r-- | bug/operations/label_change.go | 64 | ||||
-rw-r--r-- | bug/operations/set_status.go | 10 | ||||
-rw-r--r-- | bug/operations/set_title.go | 5 | ||||
-rw-r--r-- | commands/close.go | 8 | ||||
-rw-r--r-- | commands/comment.go | 8 | ||||
-rw-r--r-- | commands/label.go | 70 | ||||
-rw-r--r-- | commands/new.go | 16 | ||||
-rw-r--r-- | commands/open.go | 8 | ||||
-rw-r--r-- | commands/pull.go | 22 | ||||
-rw-r--r-- | repository/git.go | 52 | ||||
-rw-r--r-- | repository/mock_repo.go | 17 | ||||
-rw-r--r-- | repository/repo.go | 4 |
16 files changed, 220 insertions, 119 deletions
@@ -41,7 +41,7 @@ func NewBug() *Bug { // Find an existing Bug matching a prefix func FindLocalBug(repo repository.Repo, prefix string) (*Bug, error) { - ids, err := repo.ListRefs(bugsRefPattern) + ids, err := repo.ListIds(bugsRefPattern) if err != nil { return nil, err diff --git a/bug/remote_actions.go b/bug/bug_actions.go index 2070ba21..85123e1c 100644 --- a/bug/remote_actions.go +++ b/bug/bug_actions.go @@ -3,13 +3,14 @@ package bug import ( "fmt" "github.com/MichaelMure/git-bug/repository" + "io" "strings" ) -const MsgNew = "new" -const MsgInvalid = "invalid data" -const MsgUpdated = "updated" -const MsgNothing = "nothing to do" +const MsgMergeNew = "new" +const MsgMergeInvalid = "invalid data" +const MsgMergeUpdated = "updated" +const MsgMergeNothing = "nothing to do" func Fetch(repo repository.Repo, remote string) error { remoteRefSpec := fmt.Sprintf(bugsRemoteRefPattern, remote) @@ -22,6 +23,27 @@ func Push(repo repository.Repo, remote string) error { return repo.PushRefs(remote, bugsRefPattern+"*") } +func Pull(repo repository.Repo, out io.Writer, remote string) error { + fmt.Fprintf(out, "Fetching remote ...\n") + + if err := Fetch(repo, remote); err != nil { + return err + } + + fmt.Fprintf(out, "\nMerging data ...\n") + + for merge := range MergeAll(repo, remote) { + if merge.Err != nil { + return merge.Err + } + + if merge.Status != MsgMergeNothing { + fmt.Fprintf(out, "%s: %s\n", merge.HumanId, merge.Status) + } + } + return nil +} + type MergeResult struct { Err error @@ -73,7 +95,7 @@ func MergeAll(repo repository.Repo, remote string) <-chan MergeResult { // Check for error in remote data if !remoteBug.IsValid() { - out <- newMergeStatus(id, MsgInvalid) + out <- newMergeStatus(id, MsgMergeInvalid) continue } @@ -89,7 +111,7 @@ func MergeAll(repo repository.Repo, remote string) <-chan MergeResult { return } - out <- newMergeStatus(id, MsgNew) + out <- newMergeStatus(id, MsgMergeNew) continue } @@ -108,12 +130,14 @@ func MergeAll(repo repository.Repo, remote string) <-chan MergeResult { } if updated { - out <- newMergeStatus(id, MsgUpdated) + out <- newMergeStatus(id, MsgMergeUpdated) } else { - out <- newMergeStatus(id, MsgNothing) + out <- newMergeStatus(id, MsgMergeNothing) } } }() return out } + + diff --git a/bug/operations/add_comment.go b/bug/operations/add_comment.go index 9ee8dc64..66725915 100644 --- a/bug/operations/add_comment.go +++ b/bug/operations/add_comment.go @@ -31,3 +31,8 @@ func (op AddCommentOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { return snapshot } + +func Comment(b *bug.Bug, author bug.Person, message string) { + addCommentOp := NewAddCommentOp(author, message) + b.Append(addCommentOp) +} diff --git a/bug/operations/create.go b/bug/operations/create.go index 72eba843..0fd1225e 100644 --- a/bug/operations/create.go +++ b/bug/operations/create.go @@ -33,3 +33,11 @@ func (op CreateOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { } return snapshot } + +func Create(author bug.Person, title, message string) (*bug.Bug, error) { + newBug := bug.NewBug() + createOp := NewCreateOp(author, title, message) + newBug.Append(createOp) + + return newBug, nil +} diff --git a/bug/operations/label_change.go b/bug/operations/label_change.go index ca07f6f5..b9bf86c8 100644 --- a/bug/operations/label_change.go +++ b/bug/operations/label_change.go @@ -1,7 +1,9 @@ package operations import ( + "fmt" "github.com/MichaelMure/git-bug/bug" + "io" "sort" ) @@ -54,3 +56,65 @@ AddLoop: return snapshot } + +func ChangeLabels(out io.Writer, b *bug.Bug, author bug.Person, add, remove []string) error { + var added, removed []bug.Label + + 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/bug/operations/set_status.go b/bug/operations/set_status.go index 7c718cd6..b62409dc 100644 --- a/bug/operations/set_status.go +++ b/bug/operations/set_status.go @@ -25,3 +25,13 @@ func (op SetStatusOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { return snapshot } + +func Open(b *bug.Bug, author bug.Person) { + op := NewSetStatusOp(author, bug.OpenStatus) + b.Append(op) +} + +func Close(b *bug.Bug, author bug.Person) { + op := NewSetStatusOp(author, bug.ClosedStatus) + b.Append(op) +} diff --git a/bug/operations/set_title.go b/bug/operations/set_title.go index ef934db1..295db282 100644 --- a/bug/operations/set_title.go +++ b/bug/operations/set_title.go @@ -25,3 +25,8 @@ func (op SetTitleOperation) Apply(snapshot bug.Snapshot) bug.Snapshot { return snapshot } + +func SetTitle(b *bug.Bug, author bug.Person, title string) { + setTitleOp := NewSetTitleOp(author, title) + b.Append(setTitleOp) +} diff --git a/commands/close.go b/commands/close.go index 58446d71..f57519ea 100644 --- a/commands/close.go +++ b/commands/close.go @@ -28,13 +28,9 @@ func runCloseBug(cmd *cobra.Command, args []string) error { return err } - op := operations.NewSetStatusOp(author, bug.ClosedStatus) + operations.Close(b, author) - b.Append(op) - - err = b.Commit(repo) - - return err + return b.Commit(repo) } var closeCmd = &cobra.Command{ diff --git a/commands/comment.go b/commands/comment.go index 252fb7e4..ebbeaa77 100644 --- a/commands/comment.go +++ b/commands/comment.go @@ -49,13 +49,9 @@ func runComment(cmd *cobra.Command, args []string) error { return err } - addCommentOp := operations.NewAddCommentOp(author, commentMessage) + operations.Comment(b, author, commentMessage) - b.Append(addCommentOp) - - err = b.Commit(repo) - - return err + return b.Commit(repo) } var commentCmd = &cobra.Command{ diff --git a/commands/label.go b/commands/label.go index e1679972..ee6ed25f 100644 --- a/commands/label.go +++ b/commands/label.go @@ -2,10 +2,10 @@ package commands import ( "errors" - "fmt" "github.com/MichaelMure/git-bug/bug" "github.com/MichaelMure/git-bug/bug/operations" "github.com/spf13/cobra" + "os" ) var labelRemove bool @@ -21,6 +21,14 @@ func runLabel(cmd *cobra.Command, args []string) error { prefix := args[0] + var add, remove []string + + if labelRemove { + remove = args[1:] + } else { + add = args[1:] + } + b, err := bug.FindLocalBug(repo, prefix) if err != nil { return err @@ -31,65 +39,13 @@ func runLabel(cmd *cobra.Command, args []string) error { return err } - var added, removed []bug.Label - - snap := b.Compile() - - for _, arg := range args[1:] { - label := bug.Label(arg) - - if labelRemove { - // check for duplicate - if labelExist(removed, label) { - fmt.Printf("label \"%s\" is a duplicate\n", arg) - continue - } - - // check that the label actually exist - if !labelExist(snap.Labels, label) { - fmt.Printf("label \"%s\" doesn't exist on this bug\n", arg) - continue - } - - removed = append(removed, label) - } else { - // check for duplicate - if labelExist(added, label) { - fmt.Printf("label \"%s\" is a duplicate\n", arg) - continue - } - - // check that the label doesn't already exist - if labelExist(snap.Labels, label) { - fmt.Printf("label \"%s\" is already set on this bug\n", arg) - continue - } - - added = append(added, label) - } - } - - if len(added) == 0 && len(removed) == 0 { - return errors.New("no label added or removed") - } - - labelOp := operations.NewLabelChangeOperation(author, added, removed) - - b.Append(labelOp) + err = operations.ChangeLabels(os.Stdout, b, author, add, remove) - err = b.Commit(repo) - - return err -} - -func labelExist(labels []bug.Label, label bug.Label) bool { - for _, l := range labels { - if l == label { - return true - } + if err != nil { + return err } - return false + return b.Commit(repo) } var labelCmd = &cobra.Command{ diff --git a/commands/new.go b/commands/new.go index 9844e121..4168453e 100644 --- a/commands/new.go +++ b/commands/new.go @@ -44,18 +44,20 @@ func runNewBug(cmd *cobra.Command, args []string) error { return err } - newBug := bug.NewBug() - - createOp := operations.NewCreateOp(author, title, newMessage) - - newBug.Append(createOp) + newBug, err := operations.Create(author, title, newMessage) + if err != nil { + return err + } err = newBug.Commit(repo) - fmt.Printf("%s created\n", newBug.HumanId()) + if err != nil { + return err + } - return err + fmt.Printf("%s created\n", newBug.HumanId()) + return nil } var newCmd = &cobra.Command{ diff --git a/commands/open.go b/commands/open.go index 7fa59b49..c99578cf 100644 --- a/commands/open.go +++ b/commands/open.go @@ -28,13 +28,9 @@ func runOpenBug(cmd *cobra.Command, args []string) error { return err } - op := operations.NewSetStatusOp(author, bug.OpenStatus) + operations.Open(b, author) - b.Append(op) - - err = b.Commit(repo) - - return err + return b.Commit(repo) } var openCmd = &cobra.Command{ diff --git a/commands/pull.go b/commands/pull.go index ac6a3732..52b3ecd8 100644 --- a/commands/pull.go +++ b/commands/pull.go @@ -2,9 +2,9 @@ package commands import ( "errors" - "fmt" "github.com/MichaelMure/git-bug/bug" "github.com/spf13/cobra" + "os" ) func runPull(cmd *cobra.Command, args []string) error { @@ -17,25 +17,7 @@ func runPull(cmd *cobra.Command, args []string) error { remote = args[0] } - fmt.Printf("Fetching remote ...\n\n") - - if err := bug.Fetch(repo, remote); err != nil { - return err - } - - fmt.Printf("\nMerging data ...\n\n") - - for merge := range bug.MergeAll(repo, remote) { - if merge.Err != nil { - return merge.Err - } - - if merge.Status != bug.MsgNothing { - fmt.Printf("%s: %s\n", merge.HumanId, merge.Status) - } - } - - return nil + return bug.Pull(repo, os.Stdout, remote) } // showCmd defines the "push" subcommand. diff --git a/repository/git.go b/repository/git.go index c6bc5009..17b2096f 100644 --- a/repository/git.go +++ b/repository/git.go @@ -3,7 +3,6 @@ package repository import ( "bytes" - "crypto/sha1" "fmt" "github.com/MichaelMure/git-bug/util" "io" @@ -19,7 +18,7 @@ type GitRepo struct { // Run the given git command with the given I/O reader/writers, returning an error if it fails. func (repo *GitRepo) runGitCommandWithIO(stdin io.Reader, stdout, stderr io.Writer, args ...string) error { - fmt.Println("Running git", strings.Join(args, " ")) + //fmt.Println("Running git", strings.Join(args, " ")) cmd := exec.Command("git", args...) cmd.Dir = repo.Path @@ -74,17 +73,29 @@ func NewGitRepo(path string) (*GitRepo, error) { return nil, err } +func InitGitRepo(path string) (*GitRepo, error) { + repo := &GitRepo{Path: path} + _, err := repo.runGitCommand("init", path) + if err != nil { + return nil, err + } + return repo, nil +} + +func InitBareGitRepo(path string) (*GitRepo, error) { + repo := &GitRepo{Path: path} + _, err := repo.runGitCommand("init", "--bare", path) + if err != nil { + return nil, err + } + return repo, nil +} + // GetPath returns the path to the repo. func (repo *GitRepo) GetPath() string { return repo.Path } -// GetRepoStateHash returns a hash which embodies the entire current state of a repository. -func (repo *GitRepo) GetRepoStateHash() (string, error) { - stateSummary, err := repo.runGitCommand("show-ref") - return fmt.Sprintf("%x", sha1.Sum([]byte(stateSummary))), err -} - // GetUserName returns the name the the user has used to configure git func (repo *GitRepo) GetUserName() (string, error) { return repo.runGitCommand("config", "user.name") @@ -189,6 +200,24 @@ func (repo *GitRepo) UpdateRef(ref string, hash util.Hash) error { // ListRefs will return a list of Git ref matching the given refspec func (repo *GitRepo) ListRefs(refspec string) ([]string, error) { + stdout, err := repo.runGitCommand("for-each-ref", "--format=%(refname)", refspec) + + if err != nil { + return nil, err + } + + splitted := strings.Split(stdout, "\n") + + if len(splitted) == 1 && splitted[0] == "" { + return []string{}, nil + } + + return splitted, nil +} + +// ListIds will return a list of Git ref matching the given refspec, +// stripped to only the last part of the ref +func (repo *GitRepo) ListIds(refspec string) ([]string, error) { // the format option will strip the ref name to keep only the last part (ie, the bug id) stdout, err := repo.runGitCommand("for-each-ref", "--format=%(refname:lstrip=-1)", refspec) @@ -274,3 +303,10 @@ func (repo *GitRepo) GetTreeHash(commit util.Hash) (util.Hash, error) { return util.Hash(stdout), nil } + +// Add a new remote to the repository +func (repo *GitRepo) AddRemote(name string, url string) error { + _, err := repo.runGitCommand("remote", "add", name, url) + + return err +} diff --git a/repository/mock_repo.go b/repository/mock_repo.go index 4bd25738..f8653c64 100644 --- a/repository/mock_repo.go +++ b/repository/mock_repo.go @@ -3,6 +3,8 @@ package repository import ( "crypto/sha1" "fmt" + "strings" + "github.com/MichaelMure/git-bug/util" ) @@ -134,6 +136,21 @@ func (r *mockRepoForTest) ListRefs(refspec string) ([]string, error) { return keys, nil } +// ListIds will return a list of Git ref matching the given refspec, +// stripped to only the last part of the ref +func (r *mockRepoForTest) ListIds(refspec string) ([]string, error) { + keys := make([]string, len(r.refs)) + + i := 0 + for k := range r.refs { + splitted := strings.Split(k, "/") + keys[i] = splitted[len(splitted)-1] + i++ + } + + return keys, nil +} + func (r *mockRepoForTest) ListCommits(ref string) ([]util.Hash, error) { var hashes []util.Hash diff --git a/repository/repo.go b/repository/repo.go index 6ab7be91..38d8a6cb 100644 --- a/repository/repo.go +++ b/repository/repo.go @@ -48,6 +48,10 @@ type Repo interface { // ListRefs will return a list of Git ref matching the given refspec ListRefs(refspec string) ([]string, error) + // ListIds will return a list of Git ref matching the given refspec, + // stripped to only the last part of the ref + ListIds(refspec string) ([]string, error) + // RefExist will check if a reference exist in Git RefExist(ref string) (bool, error) |