mirror of
https://github.com/MichaelMure/git-bug.git
synced 2024-12-15 02:01:43 +03:00
more refactoring to have reusable bug action across different UI
This commit is contained in:
parent
49c90eab26
commit
6a12373965
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -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{
|
||||
|
@ -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
|
||||
err = operations.ChangeLabels(os.Stdout, b, author, add, remove)
|
||||
|
||||
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 err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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 = b.Commit(repo)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func labelExist(labels []bug.Label, label bug.Label) bool {
|
||||
for _, l := range labels {
|
||||
if l == label {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return b.Commit(repo)
|
||||
}
|
||||
|
||||
var labelCmd = &cobra.Command{
|
||||
|
@ -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)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("%s created\n", newBug.HumanId())
|
||||
|
||||
return err
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var newCmd = &cobra.Command{
|
||||
|
@ -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{
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user