aboutsummaryrefslogtreecommitdiffstats
path: root/commands/bug/select
diff options
context:
space:
mode:
Diffstat (limited to 'commands/bug/select')
-rw-r--r--commands/bug/select/select.go129
-rw-r--r--commands/bug/select/select_test.go79
2 files changed, 208 insertions, 0 deletions
diff --git a/commands/bug/select/select.go b/commands/bug/select/select.go
new file mode 100644
index 00000000..908ad58c
--- /dev/null
+++ b/commands/bug/select/select.go
@@ -0,0 +1,129 @@
+package _select
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+
+ "github.com/pkg/errors"
+
+ "github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/entities/bug"
+ "github.com/MichaelMure/git-bug/entity"
+)
+
+const selectFile = "select"
+
+var ErrNoValidId = errors.New("you must provide a bug id or use the \"select\" command first")
+
+// ResolveBug first try to resolve a bug using the first argument of the command
+// line. If it fails, it fallback to the select mechanism.
+//
+// Returns:
+// - the bug if any
+// - the new list of command line arguments with the bug prefix removed if it
+// has been used
+// - an error if the process failed
+func ResolveBug(repo *cache.RepoCache, args []string) (*cache.BugCache, []string, error) {
+ // At first, try to use the first argument as a bug prefix
+ if len(args) > 0 {
+ b, err := repo.ResolveBugPrefix(args[0])
+
+ if err == nil {
+ return b, args[1:], nil
+ }
+
+ if err != bug.ErrBugNotExist {
+ return nil, nil, err
+ }
+ }
+
+ // first arg is not a valid bug prefix, we can safely use the preselected bug if any
+
+ b, err := selected(repo)
+
+ // selected bug is invalid
+ if err == bug.ErrBugNotExist {
+ // we clear the selected bug
+ err = Clear(repo)
+ if err != nil {
+ return nil, nil, err
+ }
+ return nil, nil, ErrNoValidId
+ }
+
+ // another error when reading the bug
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // bug is successfully retrieved
+ if b != nil {
+ return b, args, nil
+ }
+
+ // no selected bug and no valid first argument
+ return nil, nil, ErrNoValidId
+}
+
+// Select will select a bug for future use
+func Select(repo *cache.RepoCache, id entity.Id) error {
+ f, err := repo.LocalStorage().OpenFile(selectFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
+ if err != nil {
+ return err
+ }
+
+ _, err = f.Write([]byte(id.String()))
+ if err != nil {
+ return err
+ }
+
+ return f.Close()
+}
+
+// Clear will clear the selected bug, if any
+func Clear(repo *cache.RepoCache) error {
+ return repo.LocalStorage().Remove(selectFile)
+}
+
+func selected(repo *cache.RepoCache) (*cache.BugCache, error) {
+ f, err := repo.LocalStorage().Open(selectFile)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil, nil
+ } else {
+ return nil, err
+ }
+ }
+
+ buf, err := ioutil.ReadAll(io.LimitReader(f, 100))
+ if err != nil {
+ return nil, err
+ }
+ if len(buf) == 100 {
+ return nil, fmt.Errorf("the select file should be < 100 bytes")
+ }
+
+ id := entity.Id(buf)
+ if err := id.Validate(); err != nil {
+ err = repo.LocalStorage().Remove(selectFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "error while removing invalid select file")
+ }
+
+ return nil, fmt.Errorf("select file in invalid, removing it")
+ }
+
+ b, err := repo.ResolveBug(id)
+ if err != nil {
+ return nil, err
+ }
+
+ err = f.Close()
+ if err != nil {
+ return nil, err
+ }
+
+ return b, nil
+}
diff --git a/commands/bug/select/select_test.go b/commands/bug/select/select_test.go
new file mode 100644
index 00000000..702700f4
--- /dev/null
+++ b/commands/bug/select/select_test.go
@@ -0,0 +1,79 @@
+package _select
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/repository"
+)
+
+func TestSelect(t *testing.T) {
+ repo := repository.CreateGoGitTestRepo(t, false)
+
+ repoCache, err := cache.NewRepoCache(repo)
+ require.NoError(t, err)
+
+ _, _, err = ResolveBug(repoCache, []string{})
+ require.Equal(t, ErrNoValidId, err)
+
+ err = Select(repoCache, "invalid")
+ require.NoError(t, err)
+
+ // Resolve without a pattern should fail when no bug is selected
+ _, _, err = ResolveBug(repoCache, []string{})
+ require.Error(t, err)
+
+ // generate a bunch of bugs
+
+ rene, err := repoCache.NewIdentity("René Descartes", "rene@descartes.fr")
+ require.NoError(t, err)
+
+ for i := 0; i < 10; i++ {
+ _, _, err := repoCache.NewBugRaw(rene, time.Now().Unix(), "title", "message", nil, nil)
+ require.NoError(t, err)
+ }
+
+ // and two more for testing
+ b1, _, err := repoCache.NewBugRaw(rene, time.Now().Unix(), "title", "message", nil, nil)
+ require.NoError(t, err)
+ b2, _, err := repoCache.NewBugRaw(rene, time.Now().Unix(), "title", "message", nil, nil)
+ require.NoError(t, err)
+
+ err = Select(repoCache, b1.Id())
+ require.NoError(t, err)
+
+ // normal select without args
+ b3, _, err := ResolveBug(repoCache, []string{})
+ require.NoError(t, err)
+ require.Equal(t, b1.Id(), b3.Id())
+
+ // override selection with same id
+ b4, _, err := ResolveBug(repoCache, []string{b1.Id().String()})
+ require.NoError(t, err)
+ require.Equal(t, b1.Id(), b4.Id())
+
+ // override selection with a prefix
+ b5, _, err := ResolveBug(repoCache, []string{b1.Id().Human()})
+ require.NoError(t, err)
+ require.Equal(t, b1.Id(), b5.Id())
+
+ // args that shouldn't override
+ b6, _, err := ResolveBug(repoCache, []string{"arg"})
+ require.NoError(t, err)
+ require.Equal(t, b1.Id(), b6.Id())
+
+ // override with a different id
+ b7, _, err := ResolveBug(repoCache, []string{b2.Id().String()})
+ require.NoError(t, err)
+ require.Equal(t, b2.Id(), b7.Id())
+
+ err = Clear(repoCache)
+ require.NoError(t, err)
+
+ // Resolve without a pattern should error again after clearing the selected bug
+ _, _, err = ResolveBug(repoCache, []string{})
+ require.Error(t, err)
+}