aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cache/repo_cache_identity.go2
-rw-r--r--commands/add_test.go32
-rw-r--r--commands/bridge.go42
-rw-r--r--commands/bridge/bridge.go43
-rw-r--r--commands/bridge/bridge_auth.go (renamed from commands/bridge_auth.go)20
-rw-r--r--commands/bridge/bridge_auth_addtoken.go (renamed from commands/bridge_auth_addtoken.go)26
-rw-r--r--commands/bridge/bridge_auth_rm.go41
-rw-r--r--commands/bridge/bridge_auth_show.go60
-rw-r--r--commands/bridge/bridge_new.go (renamed from commands/bridge_configure.go)40
-rw-r--r--commands/bridge/bridge_pull.go (renamed from commands/bridge_pull.go)34
-rw-r--r--commands/bridge/bridge_push.go (renamed from commands/bridge_push.go)28
-rw-r--r--commands/bridge/bridge_rm.go36
-rw-r--r--commands/bridge_auth_rm.go39
-rw-r--r--commands/bridge_auth_show.go58
-rw-r--r--commands/bridge_rm.go34
-rw-r--r--commands/bug/bug.go (renamed from commands/ls.go)178
-rw-r--r--commands/bug/bug_comment.go52
-rw-r--r--commands/bug/bug_comment_add.go (renamed from commands/comment_add.go)36
-rw-r--r--commands/bug/bug_comment_add_test.go18
-rw-r--r--commands/bug/bug_comment_edit.go (renamed from commands/comment_edit.go)29
-rw-r--r--commands/bug/bug_comment_edit_test.go23
-rw-r--r--commands/bug/bug_comment_test.go (renamed from commands/comment_test.go)28
-rw-r--r--commands/bug/bug_deselect.go37
-rw-r--r--commands/bug/bug_label.go43
-rw-r--r--commands/bug/bug_label_new.go47
-rw-r--r--commands/bug/bug_label_rm.go47
-rw-r--r--commands/bug/bug_new.go (renamed from commands/add.go)31
-rw-r--r--commands/bug/bug_new_test.go21
-rw-r--r--commands/bug/bug_rm.go46
-rw-r--r--commands/bug/bug_rm_test.go19
-rw-r--r--commands/bug/bug_select.go62
-rw-r--r--commands/bug/bug_show.go (renamed from commands/show.go)157
-rw-r--r--commands/bug/bug_status.go41
-rw-r--r--commands/bug/bug_status_close.go39
-rw-r--r--commands/bug/bug_status_open.go39
-rw-r--r--commands/bug/bug_test.go (renamed from commands/ls_test.go)24
-rw-r--r--commands/bug/bug_title.go40
-rw-r--r--commands/bug/bug_title_edit.go76
-rw-r--r--commands/bug/select/select.go (renamed from commands/select/select.go)0
-rw-r--r--commands/bug/select/select_test.go (renamed from commands/select/select_test.go)0
-rw-r--r--commands/bug/testdata/comment/add-0-golden.txt (renamed from commands/testdata/comment/add-0-golden.txt)0
-rw-r--r--commands/bug/testdata/comment/add-1-golden.txt (renamed from commands/testdata/comment/add-1-golden.txt)0
-rw-r--r--commands/bug/testdata/comment/edit-0-golden.txt (renamed from commands/testdata/comment/edit-0-golden.txt)0
-rw-r--r--commands/bug/testdata/comment/edit-1-golden.txt (renamed from commands/testdata/comment/edit-1-golden.txt)0
-rw-r--r--commands/bug/testdata/comment/message-only-0-golden.txt (renamed from commands/testdata/comment/message-only-0-golden.txt)0
-rw-r--r--commands/bug/testenv/testenv.go63
-rw-r--r--commands/cmdjson/json_common.go (renamed from commands/json_common.go)25
-rw-r--r--commands/cmdtest/golden.go5
-rw-r--r--commands/commands.go16
-rw-r--r--commands/comment.go50
-rw-r--r--commands/comment_add_test.go33
-rw-r--r--commands/comment_edit_test.go21
-rw-r--r--commands/completion/helper_completion.go (renamed from commands/helper_completion.go)131
-rw-r--r--commands/deselect.go36
-rw-r--r--commands/env_testing.go40
-rw-r--r--commands/execenv/env.go (renamed from commands/env.go)99
-rw-r--r--commands/execenv/env_testing.go48
-rw-r--r--commands/golden_test.go5
-rw-r--r--commands/input/input.go2
-rw-r--r--commands/label.go35
-rw-r--r--commands/label_add.go45
-rw-r--r--commands/label_ls.go33
-rw-r--r--commands/label_rm.go45
-rw-r--r--commands/ls-id.go42
-rw-r--r--commands/ls-labels.go29
-rw-r--r--commands/pull.go28
-rw-r--r--commands/push.go19
-rw-r--r--commands/rm.go43
-rw-r--r--commands/rm_test.go17
-rw-r--r--commands/root.go54
-rw-r--r--commands/select.go60
-rw-r--r--commands/status.go38
-rw-r--r--commands/status_close.go35
-rw-r--r--commands/status_open.go35
-rw-r--r--commands/termui.go13
-rw-r--r--commands/title.go37
-rw-r--r--commands/title_edit.go74
-rw-r--r--commands/user.go110
-rw-r--r--commands/user/user.go89
-rw-r--r--commands/user/user_adopt.go43
-rw-r--r--commands/user/user_new.go (renamed from commands/user_create.go)37
-rw-r--r--commands/user/user_new_test.go14
-rw-r--r--commands/user/user_show.go108
-rw-r--r--commands/user_adopt.go40
-rw-r--r--commands/user_create_test.go38
-rw-r--r--commands/user_ls.go81
-rw-r--r--commands/version.go20
-rw-r--r--commands/webui.go33
-rw-r--r--doc/cli-convention.md13
-rw-r--r--doc/man/git-bug-bridge-auth-rm.16
-rw-r--r--doc/man/git-bug-bridge-auth-show.14
-rw-r--r--doc/man/git-bug-bridge-auth.14
-rw-r--r--doc/man/git-bug-bridge-new.1 (renamed from doc/man/git-bug-bridge-configure.1)12
-rw-r--r--doc/man/git-bug-bridge-pull.14
-rw-r--r--doc/man/git-bug-bridge-push.14
-rw-r--r--doc/man/git-bug-bridge-rm.14
-rw-r--r--doc/man/git-bug-bridge.16
-rw-r--r--doc/man/git-bug-bug-comment-edit.1 (renamed from doc/man/git-bug-comment-edit.1)8
-rw-r--r--doc/man/git-bug-bug-comment-new.1 (renamed from doc/man/git-bug-comment-add.1)10
-rw-r--r--doc/man/git-bug-bug-comment.1 (renamed from doc/man/git-bug-comment.1)8
-rw-r--r--doc/man/git-bug-bug-deselect.1 (renamed from doc/man/git-bug-deselect.1)8
-rw-r--r--doc/man/git-bug-bug-label-new.1 (renamed from doc/man/git-bug-label-add.1)10
-rw-r--r--doc/man/git-bug-bug-label-rm.1 (renamed from doc/man/git-bug-label-rm.1)8
-rw-r--r--doc/man/git-bug-bug-label.127
-rw-r--r--doc/man/git-bug-bug-new.1 (renamed from doc/man/git-bug-add.1)10
-rw-r--r--doc/man/git-bug-bug-rm.1 (renamed from doc/man/git-bug-rm.1)6
-rw-r--r--doc/man/git-bug-bug-select.1 (renamed from doc/man/git-bug-select.1)6
-rw-r--r--doc/man/git-bug-bug-show.1 (renamed from doc/man/git-bug-show.1)8
-rw-r--r--doc/man/git-bug-bug-status-close.1 (renamed from doc/man/git-bug-status-close.1)8
-rw-r--r--doc/man/git-bug-bug-status-open.1 (renamed from doc/man/git-bug-status-open.1)8
-rw-r--r--doc/man/git-bug-bug-status.1 (renamed from doc/man/git-bug-status.1)8
-rw-r--r--doc/man/git-bug-bug-title-edit.1 (renamed from doc/man/git-bug-title-edit.1)8
-rw-r--r--doc/man/git-bug-bug-title.1 (renamed from doc/man/git-bug-title.1)8
-rw-r--r--doc/man/git-bug-bug.1 (renamed from doc/man/git-bug-ls.1)16
-rw-r--r--doc/man/git-bug-label-ls.130
-rw-r--r--doc/man/git-bug-label.111
-rw-r--r--doc/man/git-bug-pull.14
-rw-r--r--doc/man/git-bug-push.14
-rw-r--r--doc/man/git-bug-termui.14
-rw-r--r--doc/man/git-bug-user-adopt.16
-rw-r--r--doc/man/git-bug-user-ls.131
-rw-r--r--doc/man/git-bug-user-new.1 (renamed from doc/man/git-bug-user-create.1)8
-rw-r--r--doc/man/git-bug-user-user.131
-rw-r--r--doc/man/git-bug-user.112
-rw-r--r--doc/man/git-bug-version.14
-rw-r--r--doc/man/git-bug-webui.12
-rw-r--r--doc/man/git-bug.14
-rw-r--r--doc/md/git-bug.md28
-rw-r--r--doc/md/git-bug_bridge.md14
-rw-r--r--doc/md/git-bug_bridge_auth.md8
-rw-r--r--doc/md/git-bug_bridge_auth_add-token.md2
-rw-r--r--doc/md/git-bug_bridge_auth_rm.md6
-rw-r--r--doc/md/git-bug_bridge_auth_show.md4
-rw-r--r--doc/md/git-bug_bridge_new.md (renamed from doc/md/git-bug_bridge_configure.md)16
-rw-r--r--doc/md/git-bug_bridge_pull.md4
-rw-r--r--doc/md/git-bug_bridge_push.md4
-rw-r--r--doc/md/git-bug_bridge_rm.md4
-rw-r--r--doc/md/git-bug_bug.md (renamed from doc/md/git-bug_ls.md)27
-rw-r--r--doc/md/git-bug_bug_comment.md20
-rw-r--r--doc/md/git-bug_bug_comment_edit.md (renamed from doc/md/git-bug_comment_edit.md)8
-rw-r--r--doc/md/git-bug_bug_comment_new.md (renamed from doc/md/git-bug_comment_add.md)10
-rw-r--r--doc/md/git-bug_bug_deselect.md (renamed from doc/md/git-bug_deselect.md)8
-rw-r--r--doc/md/git-bug_bug_label.md20
-rw-r--r--doc/md/git-bug_bug_label_new.md18
-rw-r--r--doc/md/git-bug_bug_label_rm.md18
-rw-r--r--doc/md/git-bug_bug_new.md (renamed from doc/md/git-bug_add.md)10
-rw-r--r--doc/md/git-bug_bug_rm.md (renamed from doc/md/git-bug_rm.md)8
-rw-r--r--doc/md/git-bug_bug_select.md (renamed from doc/md/git-bug_select.md)8
-rw-r--r--doc/md/git-bug_bug_show.md (renamed from doc/md/git-bug_show.md)8
-rw-r--r--doc/md/git-bug_bug_status.md20
-rw-r--r--doc/md/git-bug_bug_status_close.md18
-rw-r--r--doc/md/git-bug_bug_status_open.md18
-rw-r--r--doc/md/git-bug_bug_title.md19
-rw-r--r--doc/md/git-bug_bug_title_edit.md (renamed from doc/md/git-bug_title_edit.md)8
-rw-r--r--doc/md/git-bug_commands.md2
-rw-r--r--doc/md/git-bug_comment.md20
-rw-r--r--doc/md/git-bug_label.md15
-rw-r--r--doc/md/git-bug_label_add.md18
-rw-r--r--doc/md/git-bug_label_ls.md24
-rw-r--r--doc/md/git-bug_label_rm.md18
-rw-r--r--doc/md/git-bug_pull.md4
-rw-r--r--doc/md/git-bug_push.md4
-rw-r--r--doc/md/git-bug_status.md20
-rw-r--r--doc/md/git-bug_status_close.md18
-rw-r--r--doc/md/git-bug_status_open.md18
-rw-r--r--doc/md/git-bug_termui.md4
-rw-r--r--doc/md/git-bug_title.md19
-rw-r--r--doc/md/git-bug_user.md16
-rw-r--r--doc/md/git-bug_user_adopt.md6
-rw-r--r--doc/md/git-bug_user_ls.md19
-rw-r--r--doc/md/git-bug_user_new.md (renamed from doc/md/git-bug_user_create.md)10
-rw-r--r--doc/md/git-bug_user_user.md19
-rw-r--r--doc/md/git-bug_version.md4
-rw-r--r--doc/md/git-bug_webui.md4
-rw-r--r--entities/identity/identity.go2
-rw-r--r--go.mod5
-rw-r--r--go.sum7
-rw-r--r--misc/completion/bash/git-bug2
-rw-r--r--misc/completion/powershell/git-bug4
-rw-r--r--repository/config.go8
180 files changed, 2321 insertions, 2215 deletions
diff --git a/cache/repo_cache_identity.go b/cache/repo_cache_identity.go
index eb30687c..4f612280 100644
--- a/cache/repo_cache_identity.go
+++ b/cache/repo_cache_identity.go
@@ -147,7 +147,7 @@ func (c *RepoCache) ResolveIdentityPrefix(prefix string) (*IdentityCache, error)
}
// ResolveIdentityImmutableMetadata retrieve an Identity that has the exact given metadata on
-// one of it's version. If multiple version have the same key, the first defined take precedence.
+// one of its version. If multiple version have the same key, the first defined take precedence.
func (c *RepoCache) ResolveIdentityImmutableMetadata(key string, value string) (*IdentityCache, error) {
return c.ResolveIdentityMatcher(func(excerpt *IdentityExcerpt) bool {
return excerpt.ImmutableMetadata[key] == value
diff --git a/commands/add_test.go b/commands/add_test.go
deleted file mode 100644
index 077995a6..00000000
--- a/commands/add_test.go
+++ /dev/null
@@ -1,32 +0,0 @@
-package commands
-
-import (
- "strings"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func newTestEnvAndBug(t *testing.T) (*testEnv, string) {
- t.Helper()
-
- testEnv, _ := newTestEnvAndUser(t)
- opts := addOptions{
- title: "this is a bug title",
- message: "this is a bug message",
- messageFile: "",
- nonInteractive: true,
- }
-
- require.NoError(t, runAdd(testEnv.env, opts))
- require.Regexp(t, "^[0-9A-Fa-f]{7} created\n$", testEnv.out)
- bugID := strings.Split(testEnv.out.String(), " ")[0]
- testEnv.out.Reset()
-
- return testEnv, bugID
-}
-
-func TestAdd(t *testing.T) {
- _, bugID := newTestEnvAndBug(t)
- require.Regexp(t, "^[0-9A-Fa-f]{7}$", bugID)
-}
diff --git a/commands/bridge.go b/commands/bridge.go
deleted file mode 100644
index 8ce35aa3..00000000
--- a/commands/bridge.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-
- "github.com/MichaelMure/git-bug/bridge"
-)
-
-func newBridgeCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "bridge",
- Short: "Configure and use bridges to other bug trackers.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runBridge(env)
- }),
- Args: cobra.NoArgs,
- }
-
- cmd.AddCommand(newBridgeAuthCommand())
- cmd.AddCommand(newBridgeConfigureCommand())
- cmd.AddCommand(newBridgePullCommand())
- cmd.AddCommand(newBridgePushCommand())
- cmd.AddCommand(newBridgeRm())
-
- return cmd
-}
-
-func runBridge(env *Env) error {
- configured, err := bridge.ConfiguredBridges(env.backend)
- if err != nil {
- return err
- }
-
- for _, c := range configured {
- env.out.Println(c)
- }
-
- return nil
-}
diff --git a/commands/bridge/bridge.go b/commands/bridge/bridge.go
new file mode 100644
index 00000000..980a38e2
--- /dev/null
+++ b/commands/bridge/bridge.go
@@ -0,0 +1,43 @@
+package bridgecmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/bridge"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func NewBridgeCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "bridge",
+ Short: "List bridges to other bug trackers",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBridge(env)
+ }),
+ Args: cobra.NoArgs,
+ }
+
+ cmd.AddCommand(newBridgeAuthCommand())
+ cmd.AddCommand(newBridgeNewCommand())
+ cmd.AddCommand(newBridgePullCommand())
+ cmd.AddCommand(newBridgePushCommand())
+ cmd.AddCommand(newBridgeRm())
+
+ return cmd
+}
+
+func runBridge(env *execenv.Env) error {
+ configured, err := bridge.ConfiguredBridges(env.Backend)
+ if err != nil {
+ return err
+ }
+
+ for _, c := range configured {
+ env.Out.Println(c)
+ }
+
+ return nil
+}
diff --git a/commands/bridge_auth.go b/commands/bridge/bridge_auth.go
index 50306b8d..52e063e6 100644
--- a/commands/bridge_auth.go
+++ b/commands/bridge/bridge_auth.go
@@ -1,25 +1,25 @@
-package commands
+package bridgecmd
import (
"sort"
"strings"
- "github.com/spf13/cobra"
-
text "github.com/MichaelMure/go-term-text"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/bridge/core/auth"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/util/colors"
)
func newBridgeAuthCommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
cmd := &cobra.Command{
Use: "auth",
- Short: "List all known bridge authentication credentials.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
+ Short: "List all known bridge authentication credentials",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
return runBridgeAuth(env)
}),
Args: cobra.NoArgs,
@@ -32,8 +32,8 @@ func newBridgeAuthCommand() *cobra.Command {
return cmd
}
-func runBridgeAuth(env *Env) error {
- creds, err := auth.List(env.backend)
+func runBridgeAuth(env *execenv.Env) error {
+ creds, err := auth.List(env.Backend)
if err != nil {
return err
}
@@ -54,7 +54,7 @@ func runBridgeAuth(env *Env) error {
sort.Strings(meta)
metaFmt := strings.Join(meta, ",")
- env.out.Printf("%s %s %s %s %s\n",
+ env.Out.Printf("%s %s %s %s %s\n",
colors.Cyan(cred.ID().Human()),
colors.Yellow(targetFmt),
colors.Magenta(cred.Kind()),
diff --git a/commands/bridge_auth_addtoken.go b/commands/bridge/bridge_auth_addtoken.go
index dfdc66b6..bcab7fc3 100644
--- a/commands/bridge_auth_addtoken.go
+++ b/commands/bridge/bridge_auth_addtoken.go
@@ -1,4 +1,4 @@
-package commands
+package bridgecmd
import (
"bufio"
@@ -14,6 +14,8 @@ import (
"github.com/MichaelMure/git-bug/bridge/core"
"github.com/MichaelMure/git-bug/bridge/core/auth"
"github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
)
type bridgeAuthAddTokenOptions struct {
@@ -23,14 +25,14 @@ type bridgeAuthAddTokenOptions struct {
}
func newBridgeAuthAddTokenCommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
options := bridgeAuthAddTokenOptions{}
cmd := &cobra.Command{
Use: "add-token [TOKEN]",
Short: "Store a new token",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
return runBridgeAuthAddToken(env, options, args)
}),
Args: cobra.MaximumNArgs(1),
@@ -41,17 +43,17 @@ func newBridgeAuthAddTokenCommand() *cobra.Command {
flags.StringVarP(&options.target, "target", "t", "",
fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ",")))
- cmd.RegisterFlagCompletionFunc("target", completeFrom(bridge.Targets()))
+ cmd.RegisterFlagCompletionFunc("target", completion.From(bridge.Targets()))
flags.StringVarP(&options.login,
"login", "l", "", "The login in the remote bug-tracker")
flags.StringVarP(&options.user,
"user", "u", "", "The user to add the token to. Default is the current user")
- cmd.RegisterFlagCompletionFunc("user", completeUser(env))
+ cmd.RegisterFlagCompletionFunc("user", completion.User(env))
return cmd
}
-func runBridgeAuthAddToken(env *Env, opts bridgeAuthAddTokenOptions, args []string) error {
+func runBridgeAuthAddToken(env *execenv.Env, opts bridgeAuthAddTokenOptions, args []string) error {
// Note: as bridgeAuthAddTokenLogin is not checked against the remote bug-tracker,
// it's possible to register a credential with an incorrect login (including bad case).
// The consequence is that it will not get picked later by the bridge. I find that
@@ -76,7 +78,7 @@ func runBridgeAuthAddToken(env *Env, opts bridgeAuthAddTokenOptions, args []stri
} else {
// Read from Stdin
if isatty.IsTerminal(os.Stdin.Fd()) {
- env.err.Println("Enter the token:")
+ env.Err.Println("Enter the token:")
}
reader := bufio.NewReader(os.Stdin)
raw, err := reader.ReadString('\n')
@@ -90,9 +92,9 @@ func runBridgeAuthAddToken(env *Env, opts bridgeAuthAddTokenOptions, args []stri
var err error
if opts.user == "" {
- user, err = env.backend.GetUserIdentity()
+ user, err = env.Backend.GetUserIdentity()
} else {
- user, err = env.backend.ResolveIdentityPrefix(opts.user)
+ user, err = env.Backend.ResolveIdentityPrefix(opts.user)
}
if err != nil {
return err
@@ -121,11 +123,11 @@ func runBridgeAuthAddToken(env *Env, opts bridgeAuthAddTokenOptions, args []stri
return errors.Wrap(err, "invalid token")
}
- err = auth.Store(env.repo, token)
+ err = auth.Store(env.Repo, token)
if err != nil {
return err
}
- env.out.Printf("token %s added\n", token.ID())
+ env.Out.Printf("token %s added\n", token.ID())
return nil
}
diff --git a/commands/bridge/bridge_auth_rm.go b/commands/bridge/bridge_auth_rm.go
new file mode 100644
index 00000000..d58ca63e
--- /dev/null
+++ b/commands/bridge/bridge_auth_rm.go
@@ -0,0 +1,41 @@
+package bridgecmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/bridge/core/auth"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBridgeAuthRm() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "rm BRIDGE_ID",
+ Short: "Remove a credential",
+ PreRunE: execenv.LoadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runBridgeAuthRm(env, args)
+ },
+ Args: cobra.ExactArgs(1),
+ ValidArgsFunction: completion.BridgeAuth(env),
+ }
+
+ return cmd
+}
+
+func runBridgeAuthRm(env *execenv.Env, args []string) error {
+ cred, err := auth.LoadWithPrefix(env.Repo, args[0])
+ if err != nil {
+ return err
+ }
+
+ err = auth.Remove(env.Repo, cred.ID())
+ if err != nil {
+ return err
+ }
+
+ env.Out.Printf("credential %s removed\n", cred.ID())
+ return nil
+}
diff --git a/commands/bridge/bridge_auth_show.go b/commands/bridge/bridge_auth_show.go
new file mode 100644
index 00000000..d373273d
--- /dev/null
+++ b/commands/bridge/bridge_auth_show.go
@@ -0,0 +1,60 @@
+package bridgecmd
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/bridge/core/auth"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBridgeAuthShow() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "show",
+ Short: "Display an authentication credential",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBridgeAuthShow(env, args)
+ }),
+ Args: cobra.ExactArgs(1),
+ ValidArgsFunction: completion.BridgeAuth(env),
+ }
+
+ return cmd
+}
+
+func runBridgeAuthShow(env *execenv.Env, args []string) error {
+ cred, err := auth.LoadWithPrefix(env.Repo, args[0])
+ if err != nil {
+ return err
+ }
+
+ env.Out.Printf("Id: %s\n", cred.ID())
+ env.Out.Printf("Target: %s\n", cred.Target())
+ env.Out.Printf("Kind: %s\n", cred.Kind())
+ env.Out.Printf("Creation: %s\n", cred.CreateTime().Format(time.RFC822))
+
+ switch cred := cred.(type) {
+ case *auth.Token:
+ env.Out.Printf("Value: %s\n", cred.Value)
+ }
+
+ env.Out.Println("Metadata:")
+
+ meta := make([]string, 0, len(cred.Metadata()))
+ for key, value := range cred.Metadata() {
+ meta = append(meta, fmt.Sprintf(" %s --> %s\n", key, value))
+ }
+ sort.Strings(meta)
+
+ env.Out.Print(strings.Join(meta, ""))
+
+ return nil
+}
diff --git a/commands/bridge_configure.go b/commands/bridge/bridge_new.go
index d5b40dfd..4cfc903d 100644
--- a/commands/bridge_configure.go
+++ b/commands/bridge/bridge_new.go
@@ -1,4 +1,4 @@
-package commands
+package bridgecmd
import (
"bufio"
@@ -12,10 +12,12 @@ import (
"github.com/MichaelMure/git-bug/bridge"
"github.com/MichaelMure/git-bug/bridge/core"
"github.com/MichaelMure/git-bug/bridge/core/auth"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/repository"
)
-type bridgeConfigureOptions struct {
+type bridgeNewOptions struct {
name string
target string
params core.BridgeParams
@@ -24,13 +26,13 @@ type bridgeConfigureOptions struct {
nonInteractive bool
}
-func newBridgeConfigureCommand() *cobra.Command {
- env := newEnv()
- options := bridgeConfigureOptions{}
+func newBridgeNewCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := bridgeNewOptions{}
cmd := &cobra.Command{
- Use: "configure",
- Short: "Configure a new bridge.",
+ Use: "new",
+ Short: "Configure a new bridge",
Long: ` Configure a new bridge by passing flags or/and using interactive terminal prompts. You can avoid all the terminal prompts by passing all the necessary flags to configure your bridge.`,
Example: `# Interactive example
[1]: github
@@ -66,7 +68,7 @@ Enter token: 87cf5c03b64029f18ea5f9ca5679daa08ccbd700
Successfully configured bridge: default
# For GitHub
-git bug bridge configure \
+git bug bridge new \
--name=default \
--target=github \
--owner=$(OWNER) \
@@ -74,20 +76,20 @@ git bug bridge configure \
--token=$(TOKEN)
# For Launchpad
-git bug bridge configure \
+git bug bridge new \
--name=default \
--target=launchpad-preview \
--url=https://bugs.launchpad.net/ubuntu/
# For Gitlab
-git bug bridge configure \
+git bug bridge new \
--name=default \
--target=github \
--url=https://github.com/michaelmure/git-bug \
--token=$(TOKEN)`,
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runBridgeConfigure(env, options)
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBridgeNew(env, options)
}),
}
@@ -97,7 +99,7 @@ git bug bridge configure \
flags.StringVarP(&options.name, "name", "n", "", "A distinctive name to identify the bridge")
flags.StringVarP(&options.target, "target", "t", "",
fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ",")))
- cmd.RegisterFlagCompletionFunc("target", completeFrom(bridge.Targets()))
+ cmd.RegisterFlagCompletionFunc("target", completion.From(bridge.Targets()))
flags.StringVarP(&options.params.URL, "url", "u", "", "The URL of the remote repository")
flags.StringVarP(&options.params.BaseURL, "base-url", "b", "", "The base URL of your remote issue tracker")
flags.StringVarP(&options.params.Login, "login", "l", "", "The login on your remote issue tracker")
@@ -111,7 +113,7 @@ git bug bridge configure \
return cmd
}
-func runBridgeConfigure(env *Env, opts bridgeConfigureOptions) error {
+func runBridgeNew(env *execenv.Env, opts bridgeNewOptions) error {
var err error
if (opts.tokenStdin || opts.token != "" || opts.params.CredPrefix != "") &&
@@ -121,7 +123,7 @@ func runBridgeConfigure(env *Env, opts bridgeConfigureOptions) error {
// early fail
if opts.params.CredPrefix != "" {
- if _, err := auth.LoadWithPrefix(env.repo, opts.params.CredPrefix); err != nil {
+ if _, err := auth.LoadWithPrefix(env.Repo, opts.params.CredPrefix); err != nil {
return err
}
}
@@ -146,13 +148,13 @@ func runBridgeConfigure(env *Env, opts bridgeConfigureOptions) error {
}
if !opts.nonInteractive && opts.name == "" {
- opts.name, err = promptName(env.repo)
+ opts.name, err = promptName(env.Repo)
if err != nil {
return err
}
}
- b, err := bridge.NewBridge(env.backend, opts.target, opts.name)
+ b, err := bridge.NewBridge(env.Backend, opts.target, opts.name)
if err != nil {
return err
}
@@ -162,7 +164,7 @@ func runBridgeConfigure(env *Env, opts bridgeConfigureOptions) error {
return err
}
- env.out.Printf("Successfully configured bridge: %s\n", opts.name)
+ env.Out.Printf("Successfully configured bridge: %s\n", opts.name)
return nil
}
diff --git a/commands/bridge_pull.go b/commands/bridge/bridge_pull.go
index 9370e088..d1fc279a 100644
--- a/commands/bridge_pull.go
+++ b/commands/bridge/bridge_pull.go
@@ -1,4 +1,4 @@
-package commands
+package bridgecmd
import (
"context"
@@ -13,6 +13,8 @@ import (
"github.com/MichaelMure/git-bug/bridge"
"github.com/MichaelMure/git-bug/bridge/core"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/util/interrupt"
)
@@ -22,18 +24,18 @@ type bridgePullOptions struct {
}
func newBridgePullCommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
options := bridgePullOptions{}
cmd := &cobra.Command{
Use: "pull [NAME]",
- Short: "Pull updates.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
+ Short: "Pull updates from a remote bug tracker",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
return runBridgePull(env, options, args)
}),
Args: cobra.MaximumNArgs(1),
- ValidArgsFunction: completeBridge(env),
+ ValidArgsFunction: completion.Bridge(env),
}
flags := cmd.Flags()
@@ -45,7 +47,7 @@ func newBridgePullCommand() *cobra.Command {
return cmd
}
-func runBridgePull(env *Env, opts bridgePullOptions, args []string) error {
+func runBridgePull(env *execenv.Env, opts bridgePullOptions, args []string) error {
if opts.noResume && opts.importSince != "" {
return fmt.Errorf("only one of --no-resume and --since flags should be used")
}
@@ -54,9 +56,9 @@ func runBridgePull(env *Env, opts bridgePullOptions, args []string) error {
var err error
if len(args) == 0 {
- b, err = bridge.DefaultBridge(env.backend)
+ b, err = bridge.DefaultBridge(env.Backend)
} else {
- b, err = bridge.LoadBridge(env.backend, args[0])
+ b, err = bridge.LoadBridge(env.Backend, args[0])
}
if err != nil {
@@ -75,14 +77,14 @@ func runBridgePull(env *Env, opts bridgePullOptions, args []string) error {
interrupt.RegisterCleaner(func() error {
mu.Lock()
if interruptCount > 0 {
- env.err.Println("Received another interrupt before graceful stop, terminating...")
+ env.Err.Println("Received another interrupt before graceful stop, terminating...")
os.Exit(0)
}
interruptCount++
mu.Unlock()
- env.err.Println("Received interrupt signal, stopping the import...\n(Hit ctrl-c again to kill the process.)")
+ env.Err.Println("Received interrupt signal, stopping the import...\n(Hit ctrl-c again to kill the process.)")
// send signal to stop the importer
cancel()
@@ -119,23 +121,23 @@ func runBridgePull(env *Env, opts bridgePullOptions, args []string) error {
case core.ImportEventBug:
importedIssues++
- env.out.Println(result.String())
+ env.Out.Println(result.String())
case core.ImportEventIdentity:
importedIdentities++
- env.out.Println(result.String())
+ env.Out.Println(result.String())
case core.ImportEventError:
if result.Err != context.Canceled {
- env.out.Println(result.String())
+ env.Out.Println(result.String())
}
default:
- env.out.Println(result.String())
+ env.Out.Println(result.String())
}
}
- env.out.Printf("imported %d issues and %d identities with %s bridge\n", importedIssues, importedIdentities, b.Name)
+ env.Out.Printf("imported %d issues and %d identities with %s bridge\n", importedIssues, importedIdentities, b.Name)
// send done signal
close(done)
diff --git a/commands/bridge_push.go b/commands/bridge/bridge_push.go
index ef1f2d3e..51baed4d 100644
--- a/commands/bridge_push.go
+++ b/commands/bridge/bridge_push.go
@@ -1,4 +1,4 @@
-package commands
+package bridgecmd
import (
"context"
@@ -10,34 +10,36 @@ import (
"github.com/MichaelMure/git-bug/bridge"
"github.com/MichaelMure/git-bug/bridge/core"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/util/interrupt"
)
func newBridgePushCommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
cmd := &cobra.Command{
Use: "push [NAME]",
- Short: "Push updates.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
+ Short: "Push updates to remote bug tracker",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
return runBridgePush(env, args)
}),
Args: cobra.MaximumNArgs(1),
- ValidArgsFunction: completeBridge(env),
+ ValidArgsFunction: completion.Bridge(env),
}
return cmd
}
-func runBridgePush(env *Env, args []string) error {
+func runBridgePush(env *execenv.Env, args []string) error {
var b *core.Bridge
var err error
if len(args) == 0 {
- b, err = bridge.DefaultBridge(env.backend)
+ b, err = bridge.DefaultBridge(env.Backend)
} else {
- b, err = bridge.LoadBridge(env.backend, args[0])
+ b, err = bridge.LoadBridge(env.Backend, args[0])
}
if err != nil {
@@ -55,14 +57,14 @@ func runBridgePush(env *Env, args []string) error {
interrupt.RegisterCleaner(func() error {
mu.Lock()
if interruptCount > 0 {
- env.err.Println("Received another interrupt before graceful stop, terminating...")
+ env.Err.Println("Received another interrupt before graceful stop, terminating...")
os.Exit(0)
}
interruptCount++
mu.Unlock()
- env.err.Println("Received interrupt signal, stopping the import...\n(Hit ctrl-c again to kill the process.)")
+ env.Err.Println("Received interrupt signal, stopping the import...\n(Hit ctrl-c again to kill the process.)")
// send signal to stop the importer
cancel()
@@ -80,7 +82,7 @@ func runBridgePush(env *Env, args []string) error {
exportedIssues := 0
for result := range events {
if result.Event != core.ExportEventNothing {
- env.out.Println(result.String())
+ env.Out.Println(result.String())
}
switch result.Event {
@@ -89,7 +91,7 @@ func runBridgePush(env *Env, args []string) error {
}
}
- env.out.Printf("exported %d issues with %s bridge\n", exportedIssues, b.Name)
+ env.Out.Printf("exported %d issues with %s bridge\n", exportedIssues, b.Name)
// send done signal
close(done)
diff --git a/commands/bridge/bridge_rm.go b/commands/bridge/bridge_rm.go
new file mode 100644
index 00000000..5d8d23c5
--- /dev/null
+++ b/commands/bridge/bridge_rm.go
@@ -0,0 +1,36 @@
+package bridgecmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/bridge"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBridgeRm() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "rm NAME",
+ Short: "Delete a configured bridge",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBridgeRm(env, args)
+ }),
+ Args: cobra.ExactArgs(1),
+ ValidArgsFunction: completion.Bridge(env),
+ }
+
+ return cmd
+}
+
+func runBridgeRm(env *execenv.Env, args []string) error {
+ err := bridge.RemoveBridge(env.Backend, args[0])
+ if err != nil {
+ return err
+ }
+
+ env.Out.Printf("Successfully removed bridge configuration %v\n", args[0])
+ return nil
+}
diff --git a/commands/bridge_auth_rm.go b/commands/bridge_auth_rm.go
deleted file mode 100644
index a28057de..00000000
--- a/commands/bridge_auth_rm.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-
- "github.com/MichaelMure/git-bug/bridge/core/auth"
-)
-
-func newBridgeAuthRm() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "rm ID",
- Short: "Remove a credential.",
- PreRunE: loadRepo(env),
- RunE: func(cmd *cobra.Command, args []string) error {
- return runBridgeAuthRm(env, args)
- },
- Args: cobra.ExactArgs(1),
- ValidArgsFunction: completeBridgeAuth(env),
- }
-
- return cmd
-}
-
-func runBridgeAuthRm(env *Env, args []string) error {
- cred, err := auth.LoadWithPrefix(env.repo, args[0])
- if err != nil {
- return err
- }
-
- err = auth.Remove(env.repo, cred.ID())
- if err != nil {
- return err
- }
-
- env.out.Printf("credential %s removed\n", cred.ID())
- return nil
-}
diff --git a/commands/bridge_auth_show.go b/commands/bridge_auth_show.go
deleted file mode 100644
index 7233bb51..00000000
--- a/commands/bridge_auth_show.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package commands
-
-import (
- "fmt"
- "sort"
- "strings"
- "time"
-
- "github.com/spf13/cobra"
-
- "github.com/MichaelMure/git-bug/bridge/core/auth"
-)
-
-func newBridgeAuthShow() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "show",
- Short: "Display an authentication credential.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runBridgeAuthShow(env, args)
- }),
- Args: cobra.ExactArgs(1),
- ValidArgsFunction: completeBridgeAuth(env),
- }
-
- return cmd
-}
-
-func runBridgeAuthShow(env *Env, args []string) error {
- cred, err := auth.LoadWithPrefix(env.repo, args[0])
- if err != nil {
- return err
- }
-
- env.out.Printf("Id: %s\n", cred.ID())
- env.out.Printf("Target: %s\n", cred.Target())
- env.out.Printf("Kind: %s\n", cred.Kind())
- env.out.Printf("Creation: %s\n", cred.CreateTime().Format(time.RFC822))
-
- switch cred := cred.(type) {
- case *auth.Token:
- env.out.Printf("Value: %s\n", cred.Value)
- }
-
- env.out.Println("Metadata:")
-
- meta := make([]string, 0, len(cred.Metadata()))
- for key, value := range cred.Metadata() {
- meta = append(meta, fmt.Sprintf(" %s --> %s\n", key, value))
- }
- sort.Strings(meta)
-
- env.out.Print(strings.Join(meta, ""))
-
- return nil
-}
diff --git a/commands/bridge_rm.go b/commands/bridge_rm.go
deleted file mode 100644
index 0306944e..00000000
--- a/commands/bridge_rm.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-
- "github.com/MichaelMure/git-bug/bridge"
-)
-
-func newBridgeRm() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "rm NAME",
- Short: "Delete a configured bridge.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runBridgeRm(env, args)
- }),
- Args: cobra.ExactArgs(1),
- ValidArgsFunction: completeBridge(env),
- }
-
- return cmd
-}
-
-func runBridgeRm(env *Env, args []string) error {
- err := bridge.RemoveBridge(env.backend, args[0])
- if err != nil {
- return err
- }
-
- env.out.Printf("Successfully removed bridge configuration %v\n", args[0])
- return nil
-}
diff --git a/commands/ls.go b/commands/bug/bug.go
index 7ed897fa..04bf8980 100644
--- a/commands/ls.go
+++ b/commands/bug/bug.go
@@ -1,4 +1,4 @@
-package commands
+package bugcmd
import (
"encoding/json"
@@ -11,13 +11,16 @@ import (
"github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/commands/cmdjson"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/entities/bug"
"github.com/MichaelMure/git-bug/entities/common"
"github.com/MichaelMure/git-bug/query"
"github.com/MichaelMure/git-bug/util/colors"
)
-type lsOptions struct {
+type bugOptions struct {
statusQuery []string
authorQuery []string
metadataQuery []string
@@ -31,33 +34,33 @@ type lsOptions struct {
outputFormat string
}
-func newLsCommand() *cobra.Command {
- env := newEnv()
- options := lsOptions{}
+func NewBugCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := bugOptions{}
cmd := &cobra.Command{
- Use: "ls [QUERY]",
- Short: "List bugs.",
+ Use: "bug [QUERY]",
+ Short: "List bugs",
Long: `Display a summary of each bugs.
You can pass an additional query to filter and order the list. This query can be expressed either with a simple query language, flags, a natural language full text search, or a combination of the aforementioned.`,
Example: `List open bugs sorted by last edition with a query:
-git bug ls status:open sort:edit-desc
+git bug status:open sort:edit-desc
List closed bugs sorted by creation with flags:
-git bug ls --status closed --by creation
+git bug --status closed --by creation
Do a full text search of all bugs:
-git bug ls "foo bar" baz
+git bug "foo bar" baz
Use queries, flags, and full text search:
-git bug ls status:open --by creation "foo bar" baz
+git bug status:open --by creation "foo bar" baz
`,
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runLs(env, options, args)
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBug(env, options, args)
}),
- ValidArgsFunction: completeLs(env),
+ ValidArgsFunction: completion.Ls(env),
}
flags := cmd.Flags()
@@ -65,41 +68,60 @@ git bug ls status:open --by creation "foo bar" baz
flags.StringSliceVarP(&options.statusQuery, "status", "s", nil,
"Filter by status. Valid values are [open,closed]")
- cmd.RegisterFlagCompletionFunc("status", completeFrom([]string{"open", "closed"}))
+ cmd.RegisterFlagCompletionFunc("status", completion.From([]string{"open", "closed"}))
flags.StringSliceVarP(&options.authorQuery, "author", "a", nil,
"Filter by author")
flags.StringSliceVarP(&options.metadataQuery, "metadata", "m", nil,
"Filter by metadata. Example: github-url=URL")
- cmd.RegisterFlagCompletionFunc("author", completeUserForQuery(env))
+ cmd.RegisterFlagCompletionFunc("author", completion.UserForQuery(env))
flags.StringSliceVarP(&options.participantQuery, "participant", "p", nil,
"Filter by participant")
- cmd.RegisterFlagCompletionFunc("participant", completeUserForQuery(env))
+ cmd.RegisterFlagCompletionFunc("participant", completion.UserForQuery(env))
flags.StringSliceVarP(&options.actorQuery, "actor", "A", nil,
"Filter by actor")
- cmd.RegisterFlagCompletionFunc("actor", completeUserForQuery(env))
+ cmd.RegisterFlagCompletionFunc("actor", completion.UserForQuery(env))
flags.StringSliceVarP(&options.labelQuery, "label", "l", nil,
"Filter by label")
- cmd.RegisterFlagCompletionFunc("label", completeLabel(env))
+ cmd.RegisterFlagCompletionFunc("label", completion.Label(env))
flags.StringSliceVarP(&options.titleQuery, "title", "t", nil,
"Filter by title")
flags.StringSliceVarP(&options.noQuery, "no", "n", nil,
"Filter by absence of something. Valid values are [label]")
- cmd.RegisterFlagCompletionFunc("no", completeLabel(env))
+ cmd.RegisterFlagCompletionFunc("no", completion.Label(env))
flags.StringVarP(&options.sortBy, "by", "b", "creation",
"Sort the results by a characteristic. Valid values are [id,creation,edit]")
- cmd.RegisterFlagCompletionFunc("by", completeFrom([]string{"id", "creation", "edit"}))
+ cmd.RegisterFlagCompletionFunc("by", completion.From([]string{"id", "creation", "edit"}))
flags.StringVarP(&options.sortDirection, "direction", "d", "asc",
"Select the sorting direction. Valid values are [asc,desc]")
- cmd.RegisterFlagCompletionFunc("direction", completeFrom([]string{"asc", "desc"}))
+ cmd.RegisterFlagCompletionFunc("direction", completion.From([]string{"asc", "desc"}))
flags.StringVarP(&options.outputFormat, "format", "f", "default",
"Select the output formatting style. Valid values are [default,plain,compact,id,json,org-mode]")
cmd.RegisterFlagCompletionFunc("format",
- completeFrom([]string{"default", "plain", "compact", "id", "json", "org-mode"}))
+ completion.From([]string{"default", "plain", "compact", "id", "json", "org-mode"}))
+
+ const selectGroup = "select"
+ cmd.AddGroup(&cobra.Group{ID: selectGroup, Title: "Implicit selection"})
+
+ addCmdWithGroup := func(child *cobra.Command, groupID string) {
+ cmd.AddCommand(child)
+ child.GroupID = groupID
+ }
+
+ addCmdWithGroup(newBugDeselectCommand(), selectGroup)
+ addCmdWithGroup(newBugSelectCommand(), selectGroup)
+
+ cmd.AddCommand(newBugCommentCommand())
+ cmd.AddCommand(newBugLabelCommand())
+ cmd.AddCommand(newBugNewCommand())
+ cmd.AddCommand(newBugRmCommand())
+ cmd.AddCommand(newBugShowCommand())
+ cmd.AddCommand(newBugStatusCommand())
+ cmd.AddCommand(newBugTitleCommand())
return cmd
}
-func runLs(env *Env, opts lsOptions, args []string) error {
+func runBug(env *execenv.Env, opts bugOptions, args []string) error {
var q *query.Query
var err error
@@ -120,14 +142,14 @@ func runLs(env *Env, opts lsOptions, args []string) error {
return err
}
- allIds, err := env.backend.QueryBugs(q)
+ allIds, err := env.Backend.QueryBugs(q)
if err != nil {
return err
}
bugExcerpt := make([]*cache.BugExcerpt, len(allIds))
for i, id := range allIds {
- b, err := env.backend.ResolveBugExcerpt(id)
+ b, err := env.Backend.ResolveBugExcerpt(id)
if err != nil {
return err
}
@@ -136,17 +158,17 @@ func runLs(env *Env, opts lsOptions, args []string) error {
switch opts.outputFormat {
case "org-mode":
- return lsOrgmodeFormatter(env, bugExcerpt)
+ return bugsOrgmodeFormatter(env, bugExcerpt)
case "plain":
- return lsPlainFormatter(env, bugExcerpt)
+ return bugsPlainFormatter(env, bugExcerpt)
case "json":
- return lsJsonFormatter(env, bugExcerpt)
+ return bugsJsonFormatter(env, bugExcerpt)
case "compact":
- return lsCompactFormatter(env, bugExcerpt)
+ return bugsCompactFormatter(env, bugExcerpt)
case "id":
- return lsIDFormatter(env, bugExcerpt)
+ return bugsIDFormatter(env, bugExcerpt)
case "default":
- return lsDefaultFormatter(env, bugExcerpt)
+ return bugsDefaultFormatter(env, bugExcerpt)
default:
return fmt.Errorf("unknown format %s", opts.outputFormat)
}
@@ -166,30 +188,30 @@ func repairQuery(args []string) string {
}
type JSONBugExcerpt struct {
- Id string `json:"id"`
- HumanId string `json:"human_id"`
- CreateTime JSONTime `json:"create_time"`
- EditTime JSONTime `json:"edit_time"`
-
- Status string `json:"status"`
- Labels []bug.Label `json:"labels"`
- Title string `json:"title"`
- Actors []JSONIdentity `json:"actors"`
- Participants []JSONIdentity `json:"participants"`
- Author JSONIdentity `json:"author"`
+ Id string `json:"id"`
+ HumanId string `json:"human_id"`
+ CreateTime cmdjson.Time `json:"create_time"`
+ EditTime cmdjson.Time `json:"edit_time"`
+
+ Status string `json:"status"`
+ Labels []bug.Label `json:"labels"`
+ Title string `json:"title"`
+ Actors []cmdjson.Identity `json:"actors"`
+ Participants []cmdjson.Identity `json:"participants"`
+ Author cmdjson.Identity `json:"author"`
Comments int `json:"comments"`
Metadata map[string]string `json:"metadata"`
}
-func lsJsonFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
+func bugsJsonFormatter(env *execenv.Env, bugExcerpts []*cache.BugExcerpt) error {
jsonBugs := make([]JSONBugExcerpt, len(bugExcerpts))
for i, b := range bugExcerpts {
jsonBug := JSONBugExcerpt{
Id: b.Id.String(),
HumanId: b.Id.Human(),
- CreateTime: NewJSONTime(b.CreateTime(), b.CreateLamportTime),
- EditTime: NewJSONTime(b.EditTime(), b.EditLamportTime),
+ CreateTime: cmdjson.NewTime(b.CreateTime(), b.CreateLamportTime),
+ EditTime: cmdjson.NewTime(b.EditTime(), b.EditLamportTime),
Status: b.Status.String(),
Labels: b.Labels,
Title: b.Title,
@@ -197,40 +219,40 @@ func lsJsonFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
Metadata: b.CreateMetadata,
}
- author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
+ author, err := env.Backend.ResolveIdentityExcerpt(b.AuthorId)
if err != nil {
return err
}
- jsonBug.Author = NewJSONIdentityFromExcerpt(author)
+ jsonBug.Author = cmdjson.NewIdentityFromExcerpt(author)
- jsonBug.Actors = make([]JSONIdentity, len(b.Actors))
+ jsonBug.Actors = make([]cmdjson.Identity, len(b.Actors))
for i, element := range b.Actors {
- actor, err := env.backend.ResolveIdentityExcerpt(element)
+ actor, err := env.Backend.ResolveIdentityExcerpt(element)
if err != nil {
return err
}
- jsonBug.Actors[i] = NewJSONIdentityFromExcerpt(actor)
+ jsonBug.Actors[i] = cmdjson.NewIdentityFromExcerpt(actor)
}
- jsonBug.Participants = make([]JSONIdentity, len(b.Participants))
+ jsonBug.Participants = make([]cmdjson.Identity, len(b.Participants))
for i, element := range b.Participants {
- participant, err := env.backend.ResolveIdentityExcerpt(element)
+ participant, err := env.Backend.ResolveIdentityExcerpt(element)
if err != nil {
return err
}
- jsonBug.Participants[i] = NewJSONIdentityFromExcerpt(participant)
+ jsonBug.Participants[i] = cmdjson.NewIdentityFromExcerpt(participant)
}
jsonBugs[i] = jsonBug
}
jsonObject, _ := json.MarshalIndent(jsonBugs, "", " ")
- env.out.Printf("%s\n", jsonObject)
+ env.Out.Printf("%s\n", jsonObject)
return nil
}
-func lsCompactFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
+func bugsCompactFormatter(env *execenv.Env, bugExcerpts []*cache.BugExcerpt) error {
for _, b := range bugExcerpts {
- author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
+ author, err := env.Backend.ResolveIdentityExcerpt(b.AuthorId)
if err != nil {
return err
}
@@ -243,7 +265,7 @@ func lsCompactFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
labelsTxt.WriteString(lc256.Unescape())
}
- env.out.Printf("%s %s %s %s %s\n",
+ env.Out.Printf("%s %s %s %s %s\n",
colors.Cyan(b.Id.Human()),
colors.Yellow(b.Status),
text.LeftPadMaxLine(strings.TrimSpace(b.Title), 40, 0),
@@ -254,17 +276,17 @@ func lsCompactFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
return nil
}
-func lsIDFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
+func bugsIDFormatter(env *execenv.Env, bugExcerpts []*cache.BugExcerpt) error {
for _, b := range bugExcerpts {
- env.out.Println(b.Id.String())
+ env.Out.Println(b.Id.String())
}
return nil
}
-func lsDefaultFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
+func bugsDefaultFormatter(env *execenv.Env, bugExcerpts []*cache.BugExcerpt) error {
for _, b := range bugExcerpts {
- author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
+ author, err := env.Backend.ResolveIdentityExcerpt(b.AuthorId)
if err != nil {
return err
}
@@ -290,7 +312,7 @@ func lsDefaultFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
comments = " ∞ 💬"
}
- env.out.Printf("%s\t%s\t%s\t%s\t%s\n",
+ env.Out.Printf("%s\t%s\t%s\t%s\t%s\n",
colors.Cyan(b.Id.Human()),
colors.Yellow(b.Status),
titleFmt+labelsFmt,
@@ -301,14 +323,14 @@ func lsDefaultFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
return nil
}
-func lsPlainFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
+func bugsPlainFormatter(env *execenv.Env, bugExcerpts []*cache.BugExcerpt) error {
for _, b := range bugExcerpts {
- env.out.Printf("%s [%s] %s\n", b.Id.Human(), b.Status, strings.TrimSpace(b.Title))
+ env.Out.Printf("%s [%s] %s\n", b.Id.Human(), b.Status, strings.TrimSpace(b.Title))
}
return nil
}
-func lsOrgmodeFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
+func bugsOrgmodeFormatter(env *execenv.Env, bugExcerpts []*cache.BugExcerpt) error {
// see https://orgmode.org/manual/Tags.html
orgTagRe := regexp.MustCompile("[^[:alpha:]_@]")
formatTag := func(l bug.Label) string {
@@ -319,7 +341,7 @@ func lsOrgmodeFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
return time.Format("[2006-01-02 Mon 15:05]")
}
- env.out.Println("#+TODO: OPEN | CLOSED")
+ env.Out.Println("#+TODO: OPEN | CLOSED")
for _, b := range bugExcerpts {
status := strings.ToUpper(b.Status.String())
@@ -331,7 +353,7 @@ func lsOrgmodeFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
title = b.Title
}
- author, err := env.backend.ResolveIdentityExcerpt(b.AuthorId)
+ author, err := env.Backend.ResolveIdentityExcerpt(b.AuthorId)
if err != nil {
return err
}
@@ -346,7 +368,7 @@ func lsOrgmodeFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
}
labels.WriteString(":")
- env.out.Printf("* %-6s %s %s %s: %s %s\n",
+ env.Out.Printf("* %-6s %s %s %s: %s %s\n",
status,
b.Id.Human(),
formatTime(b.CreateTime()),
@@ -355,29 +377,29 @@ func lsOrgmodeFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
labels.String(),
)
- env.out.Printf("** Last Edited: %s\n", formatTime(b.EditTime()))
+ env.Out.Printf("** Last Edited: %s\n", formatTime(b.EditTime()))
- env.out.Printf("** Actors:\n")
+ env.Out.Printf("** Actors:\n")
for _, element := range b.Actors {
- actor, err := env.backend.ResolveIdentityExcerpt(element)
+ actor, err := env.Backend.ResolveIdentityExcerpt(element)
if err != nil {
return err
}
- env.out.Printf(": %s %s\n",
+ env.Out.Printf(": %s %s\n",
actor.Id.Human(),
actor.DisplayName(),
)
}
- env.out.Printf("** Participants:\n")
+ env.Out.Printf("** Participants:\n")
for _, element := range b.Participants {
- participant, err := env.backend.ResolveIdentityExcerpt(element)
+ participant, err := env.Backend.ResolveIdentityExcerpt(element)
if err != nil {
return err
}
- env.out.Printf(": %s %s\n",
+ env.Out.Printf(": %s %s\n",
participant.Id.Human(),
participant.DisplayName(),
)
@@ -388,7 +410,7 @@ func lsOrgmodeFormatter(env *Env, bugExcerpts []*cache.BugExcerpt) error {
}
// Finish the command flags transformation into the query.Query
-func completeQuery(q *query.Query, opts lsOptions) error {
+func completeQuery(q *query.Query, opts bugOptions) error {
for _, str := range opts.statusQuery {
status, err := common.StatusFromString(str)
if err != nil {
diff --git a/commands/bug/bug_comment.go b/commands/bug/bug_comment.go
new file mode 100644
index 00000000..bc665f0d
--- /dev/null
+++ b/commands/bug/bug_comment.go
@@ -0,0 +1,52 @@
+package bugcmd
+
+import (
+ text "github.com/MichaelMure/go-term-text"
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+ "github.com/MichaelMure/git-bug/util/colors"
+)
+
+func newBugCommentCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "comment [BUG_ID]",
+ Short: "List a bug's comments",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugComment(env, args)
+ }),
+ ValidArgsFunction: completion.Bug(env),
+ }
+
+ cmd.AddCommand(newBugCommentNewCommand())
+ cmd.AddCommand(newBugCommentEditCommand())
+
+ return cmd
+}
+
+func runBugComment(env *execenv.Env, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
+ if err != nil {
+ return err
+ }
+
+ snap := b.Snapshot()
+
+ for i, comment := range snap.Comments {
+ if i != 0 {
+ env.Out.Println()
+ }
+
+ env.Out.Printf("Author: %s\n", colors.Magenta(comment.Author.DisplayName()))
+ env.Out.Printf("Id: %s\n", colors.Cyan(comment.CombinedId().Human()))
+ env.Out.Printf("Date: %s\n\n", comment.FormatTime())
+ env.Out.Println(text.LeftPadLines(comment.Message, 4))
+ }
+
+ return nil
+}
diff --git a/commands/comment_add.go b/commands/bug/bug_comment_add.go
index acac7994..b676db3a 100644
--- a/commands/comment_add.go
+++ b/commands/bug/bug_comment_add.go
@@ -1,31 +1,33 @@
-package commands
+package bugcmd
import (
"github.com/spf13/cobra"
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/commands/input"
- _select "github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/util/text"
)
-type commentAddOptions struct {
+type bugCommentNewOptions struct {
messageFile string
message string
nonInteractive bool
}
-func newCommentAddCommand() *cobra.Command {
- env := newEnv()
- options := commentAddOptions{}
+func newBugCommentNewCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := bugCommentNewOptions{}
cmd := &cobra.Command{
- Use: "add [ID]",
- Short: "Add a new comment to a bug.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runCommentAdd(env, options, args)
+ Use: "new [BUG_ID]",
+ Short: "Add a new comment to a bug",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugCommentNew(env, options, args)
}),
- ValidArgsFunction: completeBug(env),
+ ValidArgsFunction: completion.Bug(env),
}
flags := cmd.Flags()
@@ -41,8 +43,8 @@ func newCommentAddCommand() *cobra.Command {
return cmd
}
-func runCommentAdd(env *Env, opts commentAddOptions, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
+func runBugCommentNew(env *execenv.Env, opts bugCommentNewOptions, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
if err != nil {
return err
}
@@ -56,12 +58,12 @@ func runCommentAdd(env *Env, opts commentAddOptions, args []string) error {
if opts.messageFile == "" && opts.message == "" {
if opts.nonInteractive {
- env.err.Println("No message given. Use -m or -F option to specify a message. Aborting.")
+ env.Err.Println("No message given. Use -m or -F option to specify a message. Aborting.")
return nil
}
- opts.message, err = input.BugCommentEditorInput(env.backend, "")
+ opts.message, err = input.BugCommentEditorInput(env.Backend, "")
if err == input.ErrEmptyMessage {
- env.err.Println("Empty message, aborting.")
+ env.Err.Println("Empty message, aborting.")
return nil
}
if err != nil {
diff --git a/commands/bug/bug_comment_add_test.go b/commands/bug/bug_comment_add_test.go
new file mode 100644
index 00000000..55e285f4
--- /dev/null
+++ b/commands/bug/bug_comment_add_test.go
@@ -0,0 +1,18 @@
+package bugcmd
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/commands/bug/testenv"
+)
+
+func TestBugCommentNew(t *testing.T) {
+ const golden = "testdata/comment/add"
+
+ env, bugID, _ := testenv.NewTestEnvAndBugWithComment(t)
+
+ require.NoError(t, runBugComment(env, []string{bugID.String()}))
+ requireCommentsEqual(t, golden, env)
+}
diff --git a/commands/comment_edit.go b/commands/bug/bug_comment_edit.go
index 91c6d809..8be7cb80 100644
--- a/commands/comment_edit.go
+++ b/commands/bug/bug_comment_edit.go
@@ -1,28 +1,29 @@
-package commands
+package bugcmd
import (
"github.com/spf13/cobra"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/commands/input"
)
-type commentEditOptions struct {
+type bugCommentEditOptions struct {
messageFile string
message string
nonInteractive bool
}
-func newCommentEditCommand() *cobra.Command {
- env := newEnv()
- options := commentEditOptions{}
+func newBugCommentEditCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := bugCommentEditOptions{}
cmd := &cobra.Command{
Use: "edit [COMMENT_ID]",
- Short: "Edit an existing comment on a bug.",
+ Short: "Edit an existing comment on a bug",
Args: cobra.ExactArgs(1),
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runCommentEdit(env, options, args)
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugCommentEdit(env, options, args)
}),
}
@@ -39,8 +40,8 @@ func newCommentEditCommand() *cobra.Command {
return cmd
}
-func runCommentEdit(env *Env, opts commentEditOptions, args []string) error {
- b, commentId, err := env.backend.ResolveComment(args[0])
+func runBugCommentEdit(env *execenv.Env, opts bugCommentEditOptions, args []string) error {
+ b, commentId, err := env.Backend.ResolveComment(args[0])
if err != nil {
return err
}
@@ -54,12 +55,12 @@ func runCommentEdit(env *Env, opts commentEditOptions, args []string) error {
if opts.messageFile == "" && opts.message == "" {
if opts.nonInteractive {
- env.err.Println("No message given. Use -m or -F option to specify a message. Aborting.")
+ env.Err.Println("No message given. Use -m or -F option to specify a message. Aborting.")
return nil
}
- opts.message, err = input.BugCommentEditorInput(env.backend, "")
+ opts.message, err = input.BugCommentEditorInput(env.Backend, "")
if err == input.ErrEmptyMessage {
- env.err.Println("Empty message, aborting.")
+ env.Err.Println("Empty message, aborting.")
return nil
}
if err != nil {
diff --git a/commands/bug/bug_comment_edit_test.go b/commands/bug/bug_comment_edit_test.go
new file mode 100644
index 00000000..9e110a3b
--- /dev/null
+++ b/commands/bug/bug_comment_edit_test.go
@@ -0,0 +1,23 @@
+package bugcmd
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/commands/bug/testenv"
+)
+
+func TestBugCommentEdit(t *testing.T) {
+ const golden = "testdata/comment/edit"
+
+ env, bugID, commentID := testenv.NewTestEnvAndBugWithComment(t)
+
+ opts := bugCommentEditOptions{
+ message: "this is an altered bug comment",
+ }
+ require.NoError(t, runBugCommentEdit(env, opts, []string{commentID.Human()}))
+
+ require.NoError(t, runBugComment(env, []string{bugID.Human()}))
+ requireCommentsEqual(t, golden, env)
+}
diff --git a/commands/comment_test.go b/commands/bug/bug_comment_test.go
index 43062ed0..c1dc9952 100644
--- a/commands/comment_test.go
+++ b/commands/bug/bug_comment_test.go
@@ -1,4 +1,4 @@
-package commands
+package bugcmd
import (
"fmt"
@@ -8,14 +8,18 @@ import (
"time"
"github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/commands/bug/testenv"
+ "github.com/MichaelMure/git-bug/commands/cmdtest"
+ "github.com/MichaelMure/git-bug/commands/execenv"
)
-func TestComment(t *testing.T) {
+func TestBugComment(t *testing.T) {
const golden = "testdata/comment/message-only"
- env, bug := newTestEnvAndBug(t)
+ env, bug := testenv.NewTestEnvAndBug(t)
- require.NoError(t, runComment(env.env, []string{bug}))
+ require.NoError(t, runBugComment(env, []string{bug.Human()}))
requireCommentsEqual(t, golden, env)
}
@@ -37,7 +41,7 @@ type commentParser struct {
comments []parsedComment
}
-func parseComments(t *testing.T, env *testEnv) []parsedComment {
+func parseComments(t *testing.T, env *execenv.Env) []parsedComment {
t.Helper()
parser := &commentParser{
@@ -48,7 +52,7 @@ func parseComments(t *testing.T, env *testEnv) []parsedComment {
comment := &parsedComment{}
parser.fn = parser.parseAuthor
- for _, line := range strings.Split(env.out.String(), "\n") {
+ for _, line := range strings.Split(env.Out.String(), "\n") {
parser.fn(comment, line)
}
@@ -116,7 +120,7 @@ func normalizeParsedComments(t *testing.T, comments []parsedComment) []parsedCom
date, err := time.Parse(gitDateFormat, "Fri Aug 19 07:00:00 2022 +1900")
require.NoError(t, err)
- out := []parsedComment{}
+ var out []parsedComment
for i, comment := range comments {
comment.id = fmt.Sprintf("%7x", prefix+i)
@@ -127,18 +131,18 @@ func normalizeParsedComments(t *testing.T, comments []parsedComment) []parsedCom
return out
}
-func requireCommentsEqual(t *testing.T, golden string, env *testEnv) {
+func requireCommentsEqual(t *testing.T, golden string, env *execenv.Env) {
t.Helper()
- const goldenFilePatter = "%s-%d-golden.txt"
+ const goldenFilePattern = "%s-%d-golden.txt"
comments := parseComments(t, env)
comments = normalizeParsedComments(t, comments)
- if *update {
+ if *cmdtest.Update {
t.Log("Got here")
for i, comment := range comments {
- fileName := fmt.Sprintf(goldenFilePatter, golden, i)
+ fileName := fmt.Sprintf(goldenFilePattern, golden, i)
require.NoError(t, ioutil.WriteFile(fileName, []byte(comment.message), 0644))
}
}
@@ -152,7 +156,7 @@ func requireCommentsEqual(t *testing.T, golden string, env *testEnv) {
require.Equal(t, fmt.Sprintf("%7x", prefix+i), comment.id)
require.Equal(t, date.Add(time.Duration(i)*time.Minute), comment.date)
- fileName := fmt.Sprintf(goldenFilePatter, golden, i)
+ fileName := fmt.Sprintf(goldenFilePattern, golden, i)
exp, err := ioutil.ReadFile(fileName)
require.NoError(t, err)
require.Equal(t, strings.ReplaceAll(string(exp), "\r", ""), strings.ReplaceAll(comment.message, "\r", ""))
diff --git a/commands/bug/bug_deselect.go b/commands/bug/bug_deselect.go
new file mode 100644
index 00000000..7e2a86c9
--- /dev/null
+++ b/commands/bug/bug_deselect.go
@@ -0,0 +1,37 @@
+package bugcmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBugDeselectCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "deselect",
+ Short: "Clear the implicitly selected bug",
+ Example: `git bug select 2f15
+git bug comment
+git bug status
+git bug deselect
+`,
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugDeselect(env)
+ }),
+ }
+
+ return cmd
+}
+
+func runBugDeselect(env *execenv.Env) error {
+ err := _select.Clear(env.Backend)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/commands/bug/bug_label.go b/commands/bug/bug_label.go
new file mode 100644
index 00000000..657fa2ca
--- /dev/null
+++ b/commands/bug/bug_label.go
@@ -0,0 +1,43 @@
+package bugcmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBugLabelCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "label [BUG_ID]",
+ Short: "Display labels of a bug",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugLabel(env, args)
+ }),
+ ValidArgsFunction: completion.Bug(env),
+ }
+
+ cmd.AddCommand(newBugLabelNewCommand())
+ cmd.AddCommand(newBugLabelRmCommand())
+
+ return cmd
+}
+
+func runBugLabel(env *execenv.Env, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
+ if err != nil {
+ return err
+ }
+
+ snap := b.Snapshot()
+
+ for _, l := range snap.Labels {
+ env.Out.Println(l)
+ }
+
+ return nil
+}
diff --git a/commands/bug/bug_label_new.go b/commands/bug/bug_label_new.go
new file mode 100644
index 00000000..f94d3dc8
--- /dev/null
+++ b/commands/bug/bug_label_new.go
@@ -0,0 +1,47 @@
+package bugcmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+ "github.com/MichaelMure/git-bug/util/text"
+)
+
+func newBugLabelNewCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "new [BUG_ID] LABEL...",
+ Short: "Add a label to a bug",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugLabelNew(env, args)
+ }),
+ ValidArgsFunction: completion.BugAndLabels(env, true),
+ }
+
+ return cmd
+}
+
+func runBugLabelNew(env *execenv.Env, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
+ if err != nil {
+ return err
+ }
+
+ added := args
+
+ changes, _, err := b.ChangeLabels(text.CleanupOneLineArray(added), nil)
+
+ for _, change := range changes {
+ env.Out.Println(change)
+ }
+
+ if err != nil {
+ return err
+ }
+
+ return b.Commit()
+}
diff --git a/commands/bug/bug_label_rm.go b/commands/bug/bug_label_rm.go
new file mode 100644
index 00000000..13ce4b81
--- /dev/null
+++ b/commands/bug/bug_label_rm.go
@@ -0,0 +1,47 @@
+package bugcmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+ "github.com/MichaelMure/git-bug/util/text"
+)
+
+func newBugLabelRmCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "rm [BUG_ID] LABEL...",
+ Short: "Remove a label from a bug",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugLabelRm(env, args)
+ }),
+ ValidArgsFunction: completion.BugAndLabels(env, false),
+ }
+
+ return cmd
+}
+
+func runBugLabelRm(env *execenv.Env, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
+ if err != nil {
+ return err
+ }
+
+ removed := args
+
+ changes, _, err := b.ChangeLabels(nil, text.CleanupOneLineArray(removed))
+
+ for _, change := range changes {
+ env.Out.Println(change)
+ }
+
+ if err != nil {
+ return err
+ }
+
+ return b.Commit()
+}
diff --git a/commands/add.go b/commands/bug/bug_new.go
index b43eda36..4f73a09c 100644
--- a/commands/add.go
+++ b/commands/bug/bug_new.go
@@ -1,29 +1,30 @@
-package commands
+package bugcmd
import (
"github.com/spf13/cobra"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/commands/input"
"github.com/MichaelMure/git-bug/util/text"
)
-type addOptions struct {
+type bugNewOptions struct {
title string
message string
messageFile string
nonInteractive bool
}
-func newAddCommand() *cobra.Command {
- env := newEnv()
- options := addOptions{}
+func newBugNewCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := bugNewOptions{}
cmd := &cobra.Command{
- Use: "add",
- Short: "Create a new bug.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runAdd(env, options)
+ Use: "new",
+ Short: "Create a new bug",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugNew(env, options)
}),
}
@@ -41,7 +42,7 @@ func newAddCommand() *cobra.Command {
return cmd
}
-func runAdd(env *Env, opts addOptions) error {
+func runBugNew(env *execenv.Env, opts bugNewOptions) error {
var err error
if opts.messageFile != "" && opts.message == "" {
opts.title, opts.message, err = input.BugCreateFileInput(opts.messageFile)
@@ -51,10 +52,10 @@ func runAdd(env *Env, opts addOptions) error {
}
if !opts.nonInteractive && opts.messageFile == "" && (opts.message == "" || opts.title == "") {
- opts.title, opts.message, err = input.BugCreateEditorInput(env.backend, opts.title, opts.message)
+ opts.title, opts.message, err = input.BugCreateEditorInput(env.Backend, opts.title, opts.message)
if err == input.ErrEmptyTitle {
- env.out.Println("Empty title, aborting.")
+ env.Out.Println("Empty title, aborting.")
return nil
}
if err != nil {
@@ -62,7 +63,7 @@ func runAdd(env *Env, opts addOptions) error {
}
}
- b, _, err := env.backend.NewBug(
+ b, _, err := env.Backend.NewBug(
text.CleanupOneLine(opts.title),
text.Cleanup(opts.message),
)
@@ -70,7 +71,7 @@ func runAdd(env *Env, opts addOptions) error {
return err
}
- env.out.Printf("%s created\n", b.Id().Human())
+ env.Out.Printf("%s created\n", b.Id().Human())
return nil
}
diff --git a/commands/bug/bug_new_test.go b/commands/bug/bug_new_test.go
new file mode 100644
index 00000000..210a4b0b
--- /dev/null
+++ b/commands/bug/bug_new_test.go
@@ -0,0 +1,21 @@
+package bugcmd
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/commands/bug/testenv"
+)
+
+func TestBugNew(t *testing.T) {
+ env, _ := testenv.NewTestEnvAndUser(t)
+
+ err := runBugNew(env, bugNewOptions{
+ nonInteractive: true,
+ message: "message",
+ title: "title",
+ })
+ require.NoError(t, err)
+ require.Regexp(t, "^[0-9A-Fa-f]{7} created\n$", env.Out.String())
+}
diff --git a/commands/bug/bug_rm.go b/commands/bug/bug_rm.go
new file mode 100644
index 00000000..1d2a7524
--- /dev/null
+++ b/commands/bug/bug_rm.go
@@ -0,0 +1,46 @@
+package bugcmd
+
+import (
+ "errors"
+
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBugRmCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "rm BUG_ID",
+ Short: "Remove an existing bug",
+ Long: "Remove an existing bug in the local repository. Note removing bugs that were imported from bridges will not remove the bug on the remote, and will only remove the local copy of the bug.",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugRm(env, args)
+ }),
+ ValidArgsFunction: completion.Bug(env),
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ return cmd
+}
+
+func runBugRm(env *execenv.Env, args []string) (err error) {
+ if len(args) == 0 {
+ return errors.New("you must provide a bug prefix to remove")
+ }
+
+ err = env.Backend.RemoveBug(args[0])
+
+ if err != nil {
+ return
+ }
+
+ env.Out.Printf("bug %s removed\n", args[0])
+
+ return
+}
diff --git a/commands/bug/bug_rm_test.go b/commands/bug/bug_rm_test.go
new file mode 100644
index 00000000..e0c2bbc5
--- /dev/null
+++ b/commands/bug/bug_rm_test.go
@@ -0,0 +1,19 @@
+package bugcmd
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/commands/bug/testenv"
+)
+
+func TestBugRm(t *testing.T) {
+ env, bugID := testenv.NewTestEnvAndBug(t)
+
+ exp := "bug " + bugID.Human() + " removed\n"
+
+ require.NoError(t, runBugRm(env, []string{bugID.Human()}))
+ require.Equal(t, exp, env.Out.String())
+ env.Out.Reset()
+}
diff --git a/commands/bug/bug_select.go b/commands/bug/bug_select.go
new file mode 100644
index 00000000..0b1cb15c
--- /dev/null
+++ b/commands/bug/bug_select.go
@@ -0,0 +1,62 @@
+package bugcmd
+
+import (
+ "errors"
+
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBugSelectCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "select BUG_ID",
+ Short: "Select a bug for implicit use in future commands",
+ Example: `git bug select 2f15
+git bug comment
+git bug status
+`,
+ Long: `Select a bug for implicit use in future commands.
+
+This command allows you to omit any bug ID argument, for example:
+ git bug show
+instead of
+ git bug show 2f153ca
+
+The complementary command is "git bug deselect" performing the opposite operation.
+`,
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugSelect(env, args)
+ }),
+ ValidArgsFunction: completion.Bug(env),
+ }
+
+ return cmd
+}
+
+func runBugSelect(env *execenv.Env, args []string) error {
+ if len(args) == 0 {
+ return errors.New("You must provide a bug id")
+ }
+
+ prefix := args[0]
+
+ b, err := env.Backend.ResolveBugPrefix(prefix)
+ if err != nil {
+ return err
+ }
+
+ err = _select.Select(env.Backend, b.Id())
+ if err != nil {
+ return err
+ }
+
+ env.Out.Printf("selected bug %s: %s\n", b.Id().Human(), b.Snapshot().Title)
+
+ return nil
+}
diff --git a/commands/show.go b/commands/bug/bug_show.go
index 1491372e..105b1150 100644
--- a/commands/show.go
+++ b/commands/bug/bug_show.go
@@ -1,4 +1,4 @@
-package commands
+package bugcmd
import (
"encoding/json"
@@ -8,28 +8,31 @@ import (
"github.com/spf13/cobra"
- _select "github.com/MichaelMure/git-bug/commands/select"
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/cmdjson"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/entities/bug"
"github.com/MichaelMure/git-bug/util/colors"
)
-type showOptions struct {
+type bugShowOptions struct {
fields string
format string
}
-func newShowCommand() *cobra.Command {
- env := newEnv()
- options := showOptions{}
+func newBugShowCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := bugShowOptions{}
cmd := &cobra.Command{
- Use: "show [ID]",
- Short: "Display the details of a bug.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runShow(env, options, args)
+ Use: "show [BUG_ID]",
+ Short: "Display the details of a bug",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugShow(env, options, args)
}),
- ValidArgsFunction: completeBug(env),
+ ValidArgsFunction: completion.Bug(env),
}
flags := cmd.Flags()
@@ -39,15 +42,15 @@ func newShowCommand() *cobra.Command {
"id", "labels", "shortId", "status", "title", "actors", "participants"}
flags.StringVarP(&options.fields, "field", "", "",
"Select field to display. Valid values are ["+strings.Join(fields, ",")+"]")
- cmd.RegisterFlagCompletionFunc("by", completeFrom(fields))
+ cmd.RegisterFlagCompletionFunc("by", completion.From(fields))
flags.StringVarP(&options.format, "format", "f", "default",
"Select the output formatting style. Valid values are [default,json,org-mode]")
return cmd
}
-func runShow(env *Env, opts showOptions, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
+func runBugShow(env *execenv.Env, opts bugShowOptions, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
if err != nil {
return err
}
@@ -61,35 +64,35 @@ func runShow(env *Env, opts showOptions, args []string) error {
if opts.fields != "" {
switch opts.fields {
case "author":
- env.out.Printf("%s\n", snap.Author.DisplayName())
+ env.Out.Printf("%s\n", snap.Author.DisplayName())
case "authorEmail":
- env.out.Printf("%s\n", snap.Author.Email())
+ env.Out.Printf("%s\n", snap.Author.Email())
case "createTime":
- env.out.Printf("%s\n", snap.CreateTime.String())
+ env.Out.Printf("%s\n", snap.CreateTime.String())
case "lastEdit":
- env.out.Printf("%s\n", snap.EditTime().String())
+ env.Out.Printf("%s\n", snap.EditTime().String())
case "humanId":
- env.out.Printf("%s\n", snap.Id().Human())
+ env.Out.Printf("%s\n", snap.Id().Human())
case "id":
- env.out.Printf("%s\n", snap.Id())
+ env.Out.Printf("%s\n", snap.Id())
case "labels":
for _, l := range snap.Labels {
- env.out.Printf("%s\n", l.String())
+ env.Out.Printf("%s\n", l.String())
}
case "actors":
for _, a := range snap.Actors {
- env.out.Printf("%s\n", a.DisplayName())
+ env.Out.Printf("%s\n", a.DisplayName())
}
case "participants":
for _, p := range snap.Participants {
- env.out.Printf("%s\n", p.DisplayName())
+ env.Out.Printf("%s\n", p.DisplayName())
}
case "shortId":
- env.out.Printf("%s\n", snap.Id().Human())
+ env.Out.Printf("%s\n", snap.Id().Human())
case "status":
- env.out.Printf("%s\n", snap.Status)
+ env.Out.Printf("%s\n", snap.Status)
case "title":
- env.out.Printf("%s\n", snap.Title)
+ env.Out.Printf("%s\n", snap.Title)
default:
return fmt.Errorf("\nUnsupported field: %s\n", opts.fields)
}
@@ -109,20 +112,20 @@ func runShow(env *Env, opts showOptions, args []string) error {
}
}
-func showDefaultFormatter(env *Env, snapshot *bug.Snapshot) error {
+func showDefaultFormatter(env *execenv.Env, snapshot *bug.Snapshot) error {
// Header
- env.out.Printf("%s [%s] %s\n\n",
+ env.Out.Printf("%s [%s] %s\n\n",
colors.Cyan(snapshot.Id().Human()),
colors.Yellow(snapshot.Status),
snapshot.Title,
)
- env.out.Printf("%s opened this issue %s\n",
+ env.Out.Printf("%s opened this issue %s\n",
colors.Magenta(snapshot.Author.DisplayName()),
snapshot.CreateTime.String(),
)
- env.out.Printf("This was last edited at %s\n\n",
+ env.Out.Printf("This was last edited at %s\n\n",
snapshot.EditTime().String(),
)
@@ -132,7 +135,7 @@ func showDefaultFormatter(env *Env, snapshot *bug.Snapshot) error {
labels[i] = string(snapshot.Labels[i])
}
- env.out.Printf("labels: %s\n",
+ env.Out.Printf("labels: %s\n",
strings.Join(labels, ", "),
)
@@ -142,7 +145,7 @@ func showDefaultFormatter(env *Env, snapshot *bug.Snapshot) error {
actors[i] = snapshot.Actors[i].DisplayName()
}
- env.out.Printf("actors: %s\n",
+ env.Out.Printf("actors: %s\n",
strings.Join(actors, ", "),
)
@@ -152,7 +155,7 @@ func showDefaultFormatter(env *Env, snapshot *bug.Snapshot) error {
participants[i] = snapshot.Participants[i].DisplayName()
}
- env.out.Printf("participants: %s\n\n",
+ env.Out.Printf("participants: %s\n\n",
strings.Join(participants, ", "),
)
@@ -161,7 +164,7 @@ func showDefaultFormatter(env *Env, snapshot *bug.Snapshot) error {
for i, comment := range snapshot.Comments {
var message string
- env.out.Printf("%s%s #%d %s <%s>\n\n",
+ env.Out.Printf("%s%s #%d %s <%s>\n\n",
indent,
comment.CombinedId().Human(),
i,
@@ -175,7 +178,7 @@ func showDefaultFormatter(env *Env, snapshot *bug.Snapshot) error {
message = comment.Message
}
- env.out.Printf("%s%s\n\n\n",
+ env.Out.Printf("%s%s\n\n\n",
indent,
message,
)
@@ -185,85 +188,85 @@ func showDefaultFormatter(env *Env, snapshot *bug.Snapshot) error {
}
type JSONBugSnapshot struct {
- Id string `json:"id"`
- HumanId string `json:"human_id"`
- CreateTime JSONTime `json:"create_time"`
- EditTime JSONTime `json:"edit_time"`
- Status string `json:"status"`
- Labels []bug.Label `json:"labels"`
- Title string `json:"title"`
- Author JSONIdentity `json:"author"`
- Actors []JSONIdentity `json:"actors"`
- Participants []JSONIdentity `json:"participants"`
- Comments []JSONComment `json:"comments"`
+ Id string `json:"id"`
+ HumanId string `json:"human_id"`
+ CreateTime cmdjson.Time `json:"create_time"`
+ EditTime cmdjson.Time `json:"edit_time"`
+ Status string `json:"status"`
+ Labels []bug.Label `json:"labels"`
+ Title string `json:"title"`
+ Author cmdjson.Identity `json:"author"`
+ Actors []cmdjson.Identity `json:"actors"`
+ Participants []cmdjson.Identity `json:"participants"`
+ Comments []JSONBugComment `json:"comments"`
}
-type JSONComment struct {
- Id string `json:"id"`
- HumanId string `json:"human_id"`
- Author JSONIdentity `json:"author"`
- Message string `json:"message"`
+type JSONBugComment struct {
+ Id string `json:"id"`
+ HumanId string `json:"human_id"`
+ Author cmdjson.Identity `json:"author"`
+ Message string `json:"message"`
}
-func NewJSONComment(comment bug.Comment) JSONComment {
- return JSONComment{
+func NewJSONComment(comment bug.Comment) JSONBugComment {
+ return JSONBugComment{
Id: comment.CombinedId().String(),
HumanId: comment.CombinedId().Human(),
- Author: NewJSONIdentity(comment.Author),
+ Author: cmdjson.NewIdentity(comment.Author),
Message: comment.Message,
}
}
-func showJsonFormatter(env *Env, snapshot *bug.Snapshot) error {
+func showJsonFormatter(env *execenv.Env, snapshot *bug.Snapshot) error {
jsonBug := JSONBugSnapshot{
Id: snapshot.Id().String(),
HumanId: snapshot.Id().Human(),
- CreateTime: NewJSONTime(snapshot.CreateTime, 0),
- EditTime: NewJSONTime(snapshot.EditTime(), 0),
+ CreateTime: cmdjson.NewTime(snapshot.CreateTime, 0),
+ EditTime: cmdjson.NewTime(snapshot.EditTime(), 0),
Status: snapshot.Status.String(),
Labels: snapshot.Labels,
Title: snapshot.Title,
- Author: NewJSONIdentity(snapshot.Author),
+ Author: cmdjson.NewIdentity(snapshot.Author),
}
- jsonBug.Actors = make([]JSONIdentity, len(snapshot.Actors))
+ jsonBug.Actors = make([]cmdjson.Identity, len(snapshot.Actors))
for i, element := range snapshot.Actors {
- jsonBug.Actors[i] = NewJSONIdentity(element)
+ jsonBug.Actors[i] = cmdjson.NewIdentity(element)
}
- jsonBug.Participants = make([]JSONIdentity, len(snapshot.Participants))
+ jsonBug.Participants = make([]cmdjson.Identity, len(snapshot.Participants))
for i, element := range snapshot.Participants {
- jsonBug.Participants[i] = NewJSONIdentity(element)
+ jsonBug.Participants[i] = cmdjson.NewIdentity(element)
}
- jsonBug.Comments = make([]JSONComment, len(snapshot.Comments))
+ jsonBug.Comments = make([]JSONBugComment, len(snapshot.Comments))
for i, comment := range snapshot.Comments {
jsonBug.Comments[i] = NewJSONComment(comment)
}
jsonObject, _ := json.MarshalIndent(jsonBug, "", " ")
- env.out.Printf("%s\n", jsonObject)
+ env.Out.Printf("%s\n", jsonObject)
return nil
}
-func showOrgModeFormatter(env *Env, snapshot *bug.Snapshot) error {
+func showOrgModeFormatter(env *execenv.Env, snapshot *bug.Snapshot) error {
// Header
- env.out.Printf("%s [%s] %s\n",
+ env.Out.Printf("%s [%s] %s\n",
snapshot.Id().Human(),
snapshot.Status,
snapshot.Title,
)
- env.out.Printf("* Author: %s\n",
+ env.Out.Printf("* Author: %s\n",
snapshot.Author.DisplayName(),
)
- env.out.Printf("* Creation Time: %s\n",
+ env.Out.Printf("* Creation Time: %s\n",
snapshot.CreateTime.String(),
)
- env.out.Printf("* Last Edit: %s\n",
+ env.Out.Printf("* Last Edit: %s\n",
snapshot.EditTime().String(),
)
@@ -273,9 +276,9 @@ func showOrgModeFormatter(env *Env, snapshot *bug.Snapshot) error {
labels[i] = string(label)
}
- env.out.Printf("* Labels:\n")
+ env.Out.Printf("* Labels:\n")
if len(labels) > 0 {
- env.out.Printf("** %s\n",
+ env.Out.Printf("** %s\n",
strings.Join(labels, "\n** "),
)
}
@@ -289,7 +292,7 @@ func showOrgModeFormatter(env *Env, snapshot *bug.Snapshot) error {
)
}
- env.out.Printf("* Actors:\n** %s\n",
+ env.Out.Printf("* Actors:\n** %s\n",
strings.Join(actors, "\n** "),
)
@@ -302,15 +305,15 @@ func showOrgModeFormatter(env *Env, snapshot *bug.Snapshot) error {
)
}
- env.out.Printf("* Participants:\n** %s\n",
+ env.Out.Printf("* Participants:\n** %s\n",
strings.Join(participants, "\n** "),
)
- env.out.Printf("* Comments:\n")
+ env.Out.Printf("* Comments:\n")
for i, comment := range snapshot.Comments {
var message string
- env.out.Printf("** #%d %s\n",
+ env.Out.Printf("** #%d %s\n",
i, comment.Author.DisplayName())
if comment.Message == "" {
@@ -319,7 +322,7 @@ func showOrgModeFormatter(env *Env, snapshot *bug.Snapshot) error {
message = strings.ReplaceAll(comment.Message, "\n", "\n: ")
}
- env.out.Printf(": %s\n", message)
+ env.Out.Printf(": %s\n", message)
}
return nil
diff --git a/commands/bug/bug_status.go b/commands/bug/bug_status.go
new file mode 100644
index 00000000..b05f862c
--- /dev/null
+++ b/commands/bug/bug_status.go
@@ -0,0 +1,41 @@
+package bugcmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBugStatusCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "status [BUG_ID]",
+ Short: "Display the status of a bug",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugStatus(env, args)
+ }),
+ ValidArgsFunction: completion.Bug(env),
+ }
+
+ cmd.AddCommand(newBugStatusCloseCommand())
+ cmd.AddCommand(newBugStatusOpenCommand())
+
+ return cmd
+}
+
+func runBugStatus(env *execenv.Env, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
+ if err != nil {
+ return err
+ }
+
+ snap := b.Snapshot()
+
+ env.Out.Println(snap.Status)
+
+ return nil
+}
diff --git a/commands/bug/bug_status_close.go b/commands/bug/bug_status_close.go
new file mode 100644
index 00000000..fcd47922
--- /dev/null
+++ b/commands/bug/bug_status_close.go
@@ -0,0 +1,39 @@
+package bugcmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBugStatusCloseCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "close [BUG_ID]",
+ Short: "Mark a bug as closed",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugStatusClose(env, args)
+ }),
+ ValidArgsFunction: completion.Bug(env),
+ }
+
+ return cmd
+}
+
+func runBugStatusClose(env *execenv.Env, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
+ if err != nil {
+ return err
+ }
+
+ _, err = b.Close()
+ if err != nil {
+ return err
+ }
+
+ return b.Commit()
+}
diff --git a/commands/bug/bug_status_open.go b/commands/bug/bug_status_open.go
new file mode 100644
index 00000000..e686add1
--- /dev/null
+++ b/commands/bug/bug_status_open.go
@@ -0,0 +1,39 @@
+package bugcmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBugStatusOpenCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "open [BUG_ID]",
+ Short: "Mark a bug as open",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugStatusOpen(env, args)
+ }),
+ ValidArgsFunction: completion.Bug(env),
+ }
+
+ return cmd
+}
+
+func runBugStatusOpen(env *execenv.Env, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
+ if err != nil {
+ return err
+ }
+
+ _, err = b.Open()
+ if err != nil {
+ return err
+ }
+
+ return b.Commit()
+}
diff --git a/commands/ls_test.go b/commands/bug/bug_test.go
index 22adc1ce..aef0346d 100644
--- a/commands/ls_test.go
+++ b/commands/bug/bug_test.go
@@ -1,4 +1,4 @@
-package commands
+package bugcmd
import (
"encoding/json"
@@ -6,6 +6,8 @@ import (
"testing"
"github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/commands/bug/testenv"
)
func Test_repairQuery(t *testing.T) {
@@ -44,7 +46,7 @@ func Test_repairQuery(t *testing.T) {
}
}
-func TestLs_Format(t *testing.T) {
+func TestBug_Format(t *testing.T) {
const expOrgMode = `^#+TODO: OPEN | CLOSED
[*] OPEN [0-9a-f]{7} \[\d\d\d\d-\d\d-\d\d [[:alpha:]]{3} \d\d:\d\d\] John Doe: this is a bug title ::
[*]{2} Last Edited: \[\d\d\d\d-\d\d-\d\d [[:alpha:]]{3} \d\d:\d\d\]
@@ -66,7 +68,7 @@ $`
}
for _, testcase := range cases {
- opts := lsOptions{
+ opts := bugOptions{
sortDirection: "asc",
sortBy: "creation",
outputFormat: testcase.format,
@@ -75,26 +77,26 @@ $`
name := fmt.Sprintf("with %s format", testcase.format)
t.Run(name, func(t *testing.T) {
- env, _ := newTestEnvAndBug(t)
+ env, _ := testenv.NewTestEnvAndBug(t)
- require.NoError(t, runLs(env.env, opts, []string{}))
- require.Regexp(t, testcase.exp, env.out.String())
+ require.NoError(t, runBug(env, opts, []string{}))
+ require.Regexp(t, testcase.exp, env.Out.String())
})
}
t.Run("with JSON format", func(t *testing.T) {
- opts := lsOptions{
+ opts := bugOptions{
sortDirection: "asc",
sortBy: "creation",
outputFormat: "json",
}
- env, _ := newTestEnvAndBug(t)
+ env, _ := testenv.NewTestEnvAndBug(t)
- require.NoError(t, runLs(env.env, opts, []string{}))
+ require.NoError(t, runBug(env, opts, []string{}))
- bugs := []JSONBugExcerpt{}
- require.NoError(t, json.Unmarshal(env.out.Bytes(), &bugs))
+ var bugs []JSONBugExcerpt
+ require.NoError(t, json.Unmarshal(env.Out.Bytes(), &bugs))
require.Len(t, bugs, 1)
})
diff --git a/commands/bug/bug_title.go b/commands/bug/bug_title.go
new file mode 100644
index 00000000..98809b60
--- /dev/null
+++ b/commands/bug/bug_title.go
@@ -0,0 +1,40 @@
+package bugcmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newBugTitleCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "title [BUG_ID]",
+ Short: "Display the title of a bug",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugTitle(env, args)
+ }),
+ ValidArgsFunction: completion.Bug(env),
+ }
+
+ cmd.AddCommand(newBugTitleEditCommand())
+
+ return cmd
+}
+
+func runBugTitle(env *execenv.Env, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
+ if err != nil {
+ return err
+ }
+
+ snap := b.Snapshot()
+
+ env.Out.Println(snap.Title)
+
+ return nil
+}
diff --git a/commands/bug/bug_title_edit.go b/commands/bug/bug_title_edit.go
new file mode 100644
index 00000000..e71330a1
--- /dev/null
+++ b/commands/bug/bug_title_edit.go
@@ -0,0 +1,76 @@
+package bugcmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+ "github.com/MichaelMure/git-bug/commands/input"
+ "github.com/MichaelMure/git-bug/util/text"
+)
+
+type bugTitleEditOptions struct {
+ title string
+ nonInteractive bool
+}
+
+func newBugTitleEditCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := bugTitleEditOptions{}
+
+ cmd := &cobra.Command{
+ Use: "edit [BUG_ID]",
+ Short: "Edit a title of a bug",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runBugTitleEdit(env, options, args)
+ }),
+ ValidArgsFunction: completion.Bug(env),
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.StringVarP(&options.title, "title", "t", "",
+ "Provide a title to describe the issue",
+ )
+ flags.BoolVar(&options.nonInteractive, "non-interactive", false, "Do not ask for user input")
+
+ return cmd
+}
+
+func runBugTitleEdit(env *execenv.Env, opts bugTitleEditOptions, args []string) error {
+ b, args, err := _select.ResolveBug(env.Backend, args)
+ if err != nil {
+ return err
+ }
+
+ snap := b.Snapshot()
+
+ if opts.title == "" {
+ if opts.nonInteractive {
+ env.Err.Println("No title given. Use -m or -F option to specify a title. Aborting.")
+ return nil
+ }
+ opts.title, err = input.BugTitleEditorInput(env.Repo, snap.Title)
+ if err == input.ErrEmptyTitle {
+ env.Out.Println("Empty title, aborting.")
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ }
+
+ if opts.title == snap.Title {
+ env.Err.Println("No change, aborting.")
+ }
+
+ _, err = b.SetTitle(text.CleanupOneLine(opts.title))
+ if err != nil {
+ return err
+ }
+
+ return b.Commit()
+}
diff --git a/commands/select/select.go b/commands/bug/select/select.go
index 908ad58c..908ad58c 100644
--- a/commands/select/select.go
+++ b/commands/bug/select/select.go
diff --git a/commands/select/select_test.go b/commands/bug/select/select_test.go
index 702700f4..702700f4 100644
--- a/commands/select/select_test.go
+++ b/commands/bug/select/select_test.go
diff --git a/commands/testdata/comment/add-0-golden.txt b/commands/bug/testdata/comment/add-0-golden.txt
index 44ae0c1a..44ae0c1a 100644
--- a/commands/testdata/comment/add-0-golden.txt
+++ b/commands/bug/testdata/comment/add-0-golden.txt
diff --git a/commands/testdata/comment/add-1-golden.txt b/commands/bug/testdata/comment/add-1-golden.txt
index bcf127c0..bcf127c0 100644
--- a/commands/testdata/comment/add-1-golden.txt
+++ b/commands/bug/testdata/comment/add-1-golden.txt
diff --git a/commands/testdata/comment/edit-0-golden.txt b/commands/bug/testdata/comment/edit-0-golden.txt
index 44ae0c1a..44ae0c1a 100644
--- a/commands/testdata/comment/edit-0-golden.txt
+++ b/commands/bug/testdata/comment/edit-0-golden.txt
diff --git a/commands/testdata/comment/edit-1-golden.txt b/commands/bug/testdata/comment/edit-1-golden.txt
index 3d83c02b..3d83c02b 100644
--- a/commands/testdata/comment/edit-1-golden.txt
+++ b/commands/bug/testdata/comment/edit-1-golden.txt
diff --git a/commands/testdata/comment/message-only-0-golden.txt b/commands/bug/testdata/comment/message-only-0-golden.txt
index 44ae0c1a..44ae0c1a 100644
--- a/commands/testdata/comment/message-only-0-golden.txt
+++ b/commands/bug/testdata/comment/message-only-0-golden.txt
diff --git a/commands/bug/testenv/testenv.go b/commands/bug/testenv/testenv.go
new file mode 100644
index 00000000..10f20950
--- /dev/null
+++ b/commands/bug/testenv/testenv.go
@@ -0,0 +1,63 @@
+package testenv
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/commands/execenv"
+ "github.com/MichaelMure/git-bug/entity"
+)
+
+const (
+ testUserName = "John Doe"
+ testUserEmail = "jdoe@example.com"
+)
+
+func NewTestEnvAndUser(t *testing.T) (*execenv.Env, entity.Id) {
+ t.Helper()
+
+ testEnv := execenv.NewTestEnv(t)
+
+ i, err := testEnv.Backend.NewIdentity(testUserName, testUserEmail)
+ require.NoError(t, err)
+
+ err = testEnv.Backend.SetUserIdentity(i)
+ require.NoError(t, err)
+
+ return testEnv, i.Id()
+}
+
+const (
+ testBugTitle = "this is a bug title"
+ testBugMessage = "this is a bug message"
+)
+
+func NewTestEnvAndBug(t *testing.T) (*execenv.Env, entity.Id) {
+ t.Helper()
+
+ testEnv, _ := NewTestEnvAndUser(t)
+
+ b, _, err := testEnv.Backend.NewBug(testBugTitle, testBugMessage)
+ require.NoError(t, err)
+
+ return testEnv, b.Id()
+}
+
+const (
+ testCommentMessage = "this is a bug comment"
+)
+
+func NewTestEnvAndBugWithComment(t *testing.T) (*execenv.Env, entity.Id, entity.CombinedId) {
+ t.Helper()
+
+ env, bugID := NewTestEnvAndBug(t)
+
+ b, err := env.Backend.ResolveBug(bugID)
+ require.NoError(t, err)
+
+ commentId, _, err := b.AddComment(testCommentMessage)
+ require.NoError(t, err)
+
+ return env, bugID, commentId
+}
diff --git a/commands/json_common.go b/commands/cmdjson/json_common.go
index 3ceee1ec..60e6e751 100644
--- a/commands/json_common.go
+++ b/commands/cmdjson/json_common.go
@@ -1,4 +1,4 @@
-package commands
+package cmdjson
import (
"time"
@@ -8,15 +8,15 @@ import (
"github.com/MichaelMure/git-bug/util/lamport"
)
-type JSONIdentity struct {
+type Identity struct {
Id string `json:"id"`
HumanId string `json:"human_id"`
Name string `json:"name"`
Login string `json:"login"`
}
-func NewJSONIdentity(i identity.Interface) JSONIdentity {
- return JSONIdentity{
+func NewIdentity(i identity.Interface) Identity {
+ return Identity{
Id: i.Id().String(),
HumanId: i.Id().Human(),
Name: i.Name(),
@@ -24,8 +24,8 @@ func NewJSONIdentity(i identity.Interface) JSONIdentity {
}
}
-func NewJSONIdentityFromExcerpt(excerpt *cache.IdentityExcerpt) JSONIdentity {
- return JSONIdentity{
+func NewIdentityFromExcerpt(excerpt *cache.IdentityExcerpt) Identity {
+ return Identity{
Id: excerpt.Id.String(),
HumanId: excerpt.Id.Human(),
Name: excerpt.Name,
@@ -33,21 +33,14 @@ func NewJSONIdentityFromExcerpt(excerpt *cache.IdentityExcerpt) JSONIdentity {
}
}
-func NewJSONIdentityFromLegacyExcerpt(excerpt *cache.LegacyAuthorExcerpt) JSONIdentity {
- return JSONIdentity{
- Name: excerpt.Name,
- Login: excerpt.Login,
- }
-}
-
-type JSONTime struct {
+type Time struct {
Timestamp int64 `json:"timestamp"`
Time time.Time `json:"time"`
Lamport lamport.Time `json:"lamport,omitempty"`
}
-func NewJSONTime(t time.Time, l lamport.Time) JSONTime {
- return JSONTime{
+func NewTime(t time.Time, l lamport.Time) Time {
+ return Time{
Timestamp: t.Unix(),
Time: t,
Lamport: l,
diff --git a/commands/cmdtest/golden.go b/commands/cmdtest/golden.go
new file mode 100644
index 00000000..c9a21f73
--- /dev/null
+++ b/commands/cmdtest/golden.go
@@ -0,0 +1,5 @@
+package cmdtest
+
+import "flag"
+
+var Update = flag.Bool("Update", false, "Update golden files")
diff --git a/commands/commands.go b/commands/commands.go
index 49c960ab..7d2fc37d 100644
--- a/commands/commands.go
+++ b/commands/commands.go
@@ -4,6 +4,8 @@ import (
"sort"
"github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/execenv"
)
type commandOptions struct {
@@ -11,7 +13,7 @@ type commandOptions struct {
}
func newCommandsCommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
options := commandOptions{}
cmd := &cobra.Command{
@@ -32,7 +34,7 @@ func newCommandsCommand() *cobra.Command {
return cmd
}
-func runCommands(env *Env, opts commandOptions) error {
+func runCommands(env *execenv.Env, opts commandOptions) error {
first := true
var allCmds []*cobra.Command
@@ -49,24 +51,24 @@ func runCommands(env *Env, opts commandOptions) error {
for _, cmd := range allCmds {
if !first {
- env.out.Println()
+ env.Out.Println()
}
first = false
if opts.desc {
- env.out.Printf("# %s\n", cmd.Short)
+ env.Out.Printf("# %s\n", cmd.Short)
}
- env.out.Print(cmd.UseLine())
+ env.Out.Print(cmd.UseLine())
if opts.desc {
- env.out.Println()
+ env.Out.Println()
}
}
if !opts.desc {
- env.out.Println()
+ env.Out.Println()
}
return nil
diff --git a/commands/comment.go b/commands/comment.go
deleted file mode 100644
index 7cab447c..00000000
--- a/commands/comment.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package commands
-
-import (
- text "github.com/MichaelMure/go-term-text"
- "github.com/spf13/cobra"
-
- _select "github.com/MichaelMure/git-bug/commands/select"
- "github.com/MichaelMure/git-bug/util/colors"
-)
-
-func newCommentCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "comment [ID]",
- Short: "Display or add comments to a bug.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runComment(env, args)
- }),
- ValidArgsFunction: completeBug(env),
- }
-
- cmd.AddCommand(newCommentAddCommand())
- cmd.AddCommand(newCommentEditCommand())
-
- return cmd
-}
-
-func runComment(env *Env, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
- if err != nil {
- return err
- }
-
- snap := b.Snapshot()
-
- for i, comment := range snap.Comments {
- if i != 0 {
- env.out.Println()
- }
-
- env.out.Printf("Author: %s\n", colors.Magenta(comment.Author.DisplayName()))
- env.out.Printf("Id: %s\n", colors.Cyan(comment.CombinedId().Human()))
- env.out.Printf("Date: %s\n\n", comment.FormatTime())
- env.out.Println(text.LeftPadLines(comment.Message, 4))
- }
-
- return nil
-}
diff --git a/commands/comment_add_test.go b/commands/comment_add_test.go
deleted file mode 100644
index 34ff3743..00000000
--- a/commands/comment_add_test.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package commands
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func newTestEnvAndBugWithComment(t *testing.T) (*testEnv, string, string) {
- t.Helper()
-
- env, bugID := newTestEnvAndBug(t)
-
- opts := commentAddOptions{
- message: "this is a bug comment",
- }
- require.NoError(t, runCommentAdd(env.env, opts, []string{bugID}))
- require.NoError(t, runComment(env.env, []string{bugID}))
- comments := parseComments(t, env)
- require.Len(t, comments, 2)
-
- env.out.Reset()
-
- return env, bugID, comments[1].id
-}
-
-func TestCommentAdd(t *testing.T) {
- const golden = "testdata/comment/add"
-
- env, bugID, _ := newTestEnvAndBugWithComment(t)
- require.NoError(t, runComment(env.env, []string{bugID}))
- requireCommentsEqual(t, golden, env)
-}
diff --git a/commands/comment_edit_test.go b/commands/comment_edit_test.go
deleted file mode 100644
index 50c1850b..00000000
--- a/commands/comment_edit_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package commands
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestCommentEdit(t *testing.T) {
- const golden = "testdata/comment/edit"
-
- env, bugID, commentID := newTestEnvAndBugWithComment(t)
-
- opts := commentEditOptions{
- message: "this is an altered bug comment",
- }
- require.NoError(t, runCommentEdit(env.env, opts, []string{commentID}))
-
- require.NoError(t, runComment(env.env, []string{bugID}))
- requireCommentsEqual(t, golden, env)
-}
diff --git a/commands/helper_completion.go b/commands/completion/helper_completion.go
index 847a0288..27fbd615 100644
--- a/commands/helper_completion.go
+++ b/commands/completion/helper_completion.go
@@ -1,4 +1,4 @@
-package commands
+package completion
import (
"fmt"
@@ -10,28 +10,29 @@ import (
"github.com/MichaelMure/git-bug/bridge"
"github.com/MichaelMure/git-bug/bridge/core/auth"
"github.com/MichaelMure/git-bug/cache"
- _select "github.com/MichaelMure/git-bug/commands/select"
+ "github.com/MichaelMure/git-bug/commands/bug/select"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/entities/bug"
)
-type validArgsFunction func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective)
+type ValidArgsFunction func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective)
-func completionHandlerError(err error) (completions []string, directives cobra.ShellCompDirective) {
+func handleError(err error) (completions []string, directives cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveError
}
-func completeBridge(env *Env) validArgsFunction {
+func Bridge(env *execenv.Env) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
- if err := loadBackend(env)(cmd, args); err != nil {
- return completionHandlerError(err)
+ if err := execenv.LoadBackend(env)(cmd, args); err != nil {
+ return handleError(err)
}
defer func() {
- _ = env.backend.Close()
+ _ = env.Backend.Close()
}()
- bridges, err := bridge.ConfiguredBridges(env.backend)
+ bridges, err := bridge.ConfiguredBridges(env.Backend)
if err != nil {
- return completionHandlerError(err)
+ return handleError(err)
}
completions = make([]string, len(bridges))
@@ -43,18 +44,18 @@ func completeBridge(env *Env) validArgsFunction {
}
}
-func completeBridgeAuth(env *Env) validArgsFunction {
+func BridgeAuth(env *execenv.Env) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
- if err := loadBackend(env)(cmd, args); err != nil {
- return completionHandlerError(err)
+ if err := execenv.LoadBackend(env)(cmd, args); err != nil {
+ return handleError(err)
}
defer func() {
- _ = env.backend.Close()
+ _ = env.Backend.Close()
}()
- creds, err := auth.List(env.backend)
+ creds, err := auth.List(env.Backend)
if err != nil {
- return completionHandlerError(err)
+ return handleError(err)
}
completions = make([]string, len(creds))
@@ -73,27 +74,27 @@ func completeBridgeAuth(env *Env) validArgsFunction {
}
}
-func completeBug(env *Env) validArgsFunction {
+func Bug(env *execenv.Env) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
- if err := loadBackend(env)(cmd, args); err != nil {
- return completionHandlerError(err)
+ if err := execenv.LoadBackend(env)(cmd, args); err != nil {
+ return handleError(err)
}
defer func() {
- _ = env.backend.Close()
+ _ = env.Backend.Close()
}()
- return completeBugWithBackend(env.backend, toComplete)
+ return bugWithBackend(env.Backend, toComplete)
}
}
-func completeBugWithBackend(backend *cache.RepoCache, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
+func bugWithBackend(backend *cache.RepoCache, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
allIds := backend.AllBugsIds()
bugExcerpt := make([]*cache.BugExcerpt, len(allIds))
for i, id := range allIds {
var err error
bugExcerpt[i], err = backend.ResolveBugExcerpt(id)
if err != nil {
- return completionHandlerError(err)
+ return handleError(err)
}
}
@@ -106,22 +107,22 @@ func completeBugWithBackend(backend *cache.RepoCache, toComplete string) (comple
return completions, cobra.ShellCompDirectiveNoFileComp
}
-func completeBugAndLabels(env *Env, addOrRemove bool) validArgsFunction {
+func BugAndLabels(env *execenv.Env, addOrRemove bool) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
- if err := loadBackend(env)(cmd, args); err != nil {
- return completionHandlerError(err)
+ if err := execenv.LoadBackend(env)(cmd, args); err != nil {
+ return handleError(err)
}
defer func() {
- _ = env.backend.Close()
+ _ = env.Backend.Close()
}()
- b, args, err := _select.ResolveBug(env.backend, args)
+ b, args, err := _select.ResolveBug(env.Backend, args)
if err == _select.ErrNoValidId {
// we need a bug first to complete labels
- return completeBugWithBackend(env.backend, toComplete)
+ return bugWithBackend(env.Backend, toComplete)
}
if err != nil {
- return completionHandlerError(err)
+ return handleError(err)
}
snap := b.Snapshot()
@@ -137,7 +138,7 @@ func completeBugAndLabels(env *Env, addOrRemove bool) validArgsFunction {
seenLabels[label] = true
}
- allLabels := env.backend.ValidLabels()
+ allLabels := env.Backend.ValidLabels()
labels = make([]bug.Label, 0, len(allLabels))
for _, label := range allLabels {
if !seenLabels[label] {
@@ -162,24 +163,24 @@ func completeBugAndLabels(env *Env, addOrRemove bool) validArgsFunction {
}
}
-func completeFrom(choices []string) validArgsFunction {
+func From(choices []string) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return choices, cobra.ShellCompDirectiveNoFileComp
}
}
-func completeGitRemote(env *Env) validArgsFunction {
+func GitRemote(env *execenv.Env) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
- if err := loadBackend(env)(cmd, args); err != nil {
- return completionHandlerError(err)
+ if err := execenv.LoadBackend(env)(cmd, args); err != nil {
+ return handleError(err)
}
defer func() {
- _ = env.backend.Close()
+ _ = env.Backend.Close()
}()
- remoteMap, err := env.backend.GetRemotes()
+ remoteMap, err := env.Backend.GetRemotes()
if err != nil {
- return completionHandlerError(err)
+ return handleError(err)
}
completions = make([]string, 0, len(remoteMap))
for remote, url := range remoteMap {
@@ -190,16 +191,16 @@ func completeGitRemote(env *Env) validArgsFunction {
}
}
-func completeLabel(env *Env) validArgsFunction {
+func Label(env *execenv.Env) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
- if err := loadBackend(env)(cmd, args); err != nil {
- return completionHandlerError(err)
+ if err := execenv.LoadBackend(env)(cmd, args); err != nil {
+ return handleError(err)
}
defer func() {
- _ = env.backend.Close()
+ _ = env.Backend.Close()
}()
- labels := env.backend.ValidLabels()
+ labels := env.Backend.ValidLabels()
completions = make([]string, len(labels))
for i, label := range labels {
if strings.Contains(label.String(), " ") {
@@ -212,7 +213,7 @@ func completeLabel(env *Env) validArgsFunction {
}
}
-func completeLs(env *Env) validArgsFunction {
+func Ls(env *execenv.Env) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
if strings.HasPrefix(toComplete, "status:") {
completions = append(completions, "status:open\tOpen bugs")
@@ -230,11 +231,11 @@ func completeLs(env *Env) validArgsFunction {
}
if needBackend {
- if err := loadBackend(env)(cmd, args); err != nil {
- return completionHandlerError(err)
+ if err := execenv.LoadBackend(env)(cmd, args); err != nil {
+ return handleError(err)
}
defer func() {
- _ = env.backend.Close()
+ _ = env.Backend.Close()
}()
}
@@ -242,12 +243,12 @@ func completeLs(env *Env) validArgsFunction {
if !strings.HasPrefix(toComplete, key) {
continue
}
- ids := env.backend.AllIdentityIds()
+ ids := env.Backend.AllIdentityIds()
completions = make([]string, len(ids))
for i, id := range ids {
- user, err := env.backend.ResolveIdentityExcerpt(id)
+ user, err := env.Backend.ResolveIdentityExcerpt(id)
if err != nil {
- return completionHandlerError(err)
+ return handleError(err)
}
var handle string
if user.Login != "" {
@@ -265,7 +266,7 @@ func completeLs(env *Env) validArgsFunction {
if !strings.HasPrefix(toComplete, key) {
continue
}
- labels := env.backend.ValidLabels()
+ labels := env.Backend.ValidLabels()
completions = make([]string, len(labels))
for i, label := range labels {
if strings.Contains(label.String(), " ") {
@@ -290,21 +291,21 @@ func completeLs(env *Env) validArgsFunction {
}
}
-func completeUser(env *Env) validArgsFunction {
+func User(env *execenv.Env) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
- if err := loadBackend(env)(cmd, args); err != nil {
- return completionHandlerError(err)
+ if err := execenv.LoadBackend(env)(cmd, args); err != nil {
+ return handleError(err)
}
defer func() {
- _ = env.backend.Close()
+ _ = env.Backend.Close()
}()
- ids := env.backend.AllIdentityIds()
+ ids := env.Backend.AllIdentityIds()
completions = make([]string, len(ids))
for i, id := range ids {
- user, err := env.backend.ResolveIdentityExcerpt(id)
+ user, err := env.Backend.ResolveIdentityExcerpt(id)
if err != nil {
- return completionHandlerError(err)
+ return handleError(err)
}
completions[i] = user.Id.Human() + "\t" + user.DisplayName()
}
@@ -312,21 +313,21 @@ func completeUser(env *Env) validArgsFunction {
}
}
-func completeUserForQuery(env *Env) validArgsFunction {
+func UserForQuery(env *execenv.Env) ValidArgsFunction {
return func(cmd *cobra.Command, args []string, toComplete string) (completions []string, directives cobra.ShellCompDirective) {
- if err := loadBackend(env)(cmd, args); err != nil {
- return completionHandlerError(err)
+ if err := execenv.LoadBackend(env)(cmd, args); err != nil {
+ return handleError(err)
}
defer func() {
- _ = env.backend.Close()
+ _ = env.Backend.Close()
}()
- ids := env.backend.AllIdentityIds()
+ ids := env.Backend.AllIdentityIds()
completions = make([]string, len(ids))
for i, id := range ids {
- user, err := env.backend.ResolveIdentityExcerpt(id)
+ user, err := env.Backend.ResolveIdentityExcerpt(id)
if err != nil {
- return completionHandlerError(err)
+ return handleError(err)
}
var handle string
if user.Login != "" {
diff --git a/commands/deselect.go b/commands/deselect.go
deleted file mode 100644
index d8c44dd7..00000000
--- a/commands/deselect.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-
- "github.com/MichaelMure/git-bug/commands/select"
-)
-
-func newDeselectCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "deselect",
- Short: "Clear the implicitly selected bug.",
- Example: `git bug select 2f15
-git bug comment
-git bug status
-git bug deselect
-`,
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runDeselect(env)
- }),
- }
-
- return cmd
-}
-
-func runDeselect(env *Env) error {
- err := _select.Clear(env.backend)
- if err != nil {
- return err
- }
-
- return nil
-}
diff --git a/commands/env_testing.go b/commands/env_testing.go
deleted file mode 100644
index 1493a190..00000000
--- a/commands/env_testing.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package commands
-
-import (
- "bytes"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/MichaelMure/git-bug/cache"
- "github.com/MichaelMure/git-bug/repository"
-)
-
-type testEnv struct {
- env *Env
- out *bytes.Buffer
-}
-
-func newTestEnv(t *testing.T) *testEnv {
- t.Helper()
-
- repo := repository.CreateGoGitTestRepo(t, false)
-
- buf := new(bytes.Buffer)
-
- backend, err := cache.NewRepoCache(repo)
- require.NoError(t, err)
- t.Cleanup(func() {
- backend.Close()
- })
-
- return &testEnv{
- env: &Env{
- repo: repo,
- backend: backend,
- out: out{Writer: buf},
- err: out{Writer: buf},
- },
- out: buf,
- }
-}
diff --git a/commands/env.go b/commands/execenv/env.go
index 11b91c4b..a63f835a 100644
--- a/commands/env.go
+++ b/commands/execenv/env.go
@@ -1,4 +1,4 @@
-package commands
+package execenv
import (
"fmt"
@@ -14,24 +14,43 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
+const RootCommandName = "git-bug"
+
const gitBugNamespace = "git-bug"
// Env is the environment of a command
type Env struct {
- repo repository.ClockedRepo
- backend *cache.RepoCache
- out out
- err out
+ Repo repository.ClockedRepo
+ Backend *cache.RepoCache
+ Out Out
+ Err Out
}
-func newEnv() *Env {
+func NewEnv() *Env {
return &Env{
- repo: nil,
- out: out{Writer: os.Stdout},
- err: out{Writer: os.Stderr},
+ Repo: nil,
+ Out: out{Writer: os.Stdout},
+ Err: out{Writer: os.Stderr},
}
}
+type Out interface {
+ io.Writer
+ Printf(format string, a ...interface{})
+ Print(a ...interface{})
+ Println(a ...interface{})
+
+ // String returns what have been written in the output before, as a string.
+ // This only works in test scenario.
+ String() string
+ // Bytes returns what have been written in the output before, as []byte.
+ // This only works in test scenario.
+ Bytes() []byte
+ // Reset clear what has been recorded as written in the output before.
+ // This only works in test scenario.
+ Reset()
+}
+
type out struct {
io.Writer
}
@@ -48,17 +67,29 @@ func (o out) Println(a ...interface{}) {
_, _ = fmt.Fprintln(o, a...)
}
-// loadRepo is a pre-run function that load the repository for use in a command
-func loadRepo(env *Env) func(*cobra.Command, []string) error {
+func (o out) String() string {
+ panic("only work with a test env")
+}
+
+func (o out) Bytes() []byte {
+ panic("only work with a test env")
+}
+
+func (o out) Reset() {
+ panic("only work with a test env")
+}
+
+// LoadRepo is a pre-run function that load the repository for use in a command
+func LoadRepo(env *Env) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
cwd, err := os.Getwd()
if err != nil {
return fmt.Errorf("unable to get the current working directory: %q", err)
}
- env.repo, err = repository.OpenGoGitRepo(cwd, gitBugNamespace, []repository.ClockLoader{bug.ClockLoader})
+ env.Repo, err = repository.OpenGoGitRepo(cwd, gitBugNamespace, []repository.ClockLoader{bug.ClockLoader})
if err == repository.ErrNotARepo {
- return fmt.Errorf("%s must be run from within a git repo", rootCommandName)
+ return fmt.Errorf("%s must be run from within a git Repo", RootCommandName)
}
if err != nil {
@@ -69,17 +100,17 @@ func loadRepo(env *Env) func(*cobra.Command, []string) error {
}
}
-// loadRepoEnsureUser is the same as loadRepo, but also ensure that the user has configured
+// LoadRepoEnsureUser is the same as LoadRepo, but also ensure that the user has configured
// an identity. Use this pre-run function when an error after using the configured user won't
// do.
-func loadRepoEnsureUser(env *Env) func(*cobra.Command, []string) error {
+func LoadRepoEnsureUser(env *Env) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
- err := loadRepo(env)(cmd, args)
+ err := LoadRepo(env)(cmd, args)
if err != nil {
return err
}
- _, err = identity.GetUserIdentity(env.repo)
+ _, err = identity.GetUserIdentity(env.Repo)
if err != nil {
return err
}
@@ -88,25 +119,25 @@ func loadRepoEnsureUser(env *Env) func(*cobra.Command, []string) error {
}
}
-// loadBackend is a pre-run function that load the repository and the backend for use in a command
-// When using this function you also need to use closeBackend as a post-run
-func loadBackend(env *Env) func(*cobra.Command, []string) error {
+// LoadBackend is a pre-run function that load the repository and the Backend for use in a command
+// When using this function you also need to use CloseBackend as a post-run
+func LoadBackend(env *Env) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
- err := loadRepo(env)(cmd, args)
+ err := LoadRepo(env)(cmd, args)
if err != nil {
return err
}
- env.backend, err = cache.NewRepoCache(env.repo)
+ env.Backend, err = cache.NewRepoCache(env.Repo)
if err != nil {
return err
}
cleaner := func(env *Env) interrupt.CleanerFunc {
return func() error {
- if env.backend != nil {
- err := env.backend.Close()
- env.backend = nil
+ if env.Backend != nil {
+ err := env.Backend.Close()
+ env.Backend = nil
return err
}
return nil
@@ -119,17 +150,17 @@ func loadBackend(env *Env) func(*cobra.Command, []string) error {
}
}
-// loadBackendEnsureUser is the same as loadBackend, but also ensure that the user has configured
+// LoadBackendEnsureUser is the same as LoadBackend, but also ensure that the user has configured
// an identity. Use this pre-run function when an error after using the configured user won't
// do.
-func loadBackendEnsureUser(env *Env) func(*cobra.Command, []string) error {
+func LoadBackendEnsureUser(env *Env) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
- err := loadBackend(env)(cmd, args)
+ err := LoadBackend(env)(cmd, args)
if err != nil {
return err
}
- _, err = identity.GetUserIdentity(env.repo)
+ _, err = identity.GetUserIdentity(env.Repo)
if err != nil {
return err
}
@@ -138,18 +169,18 @@ func loadBackendEnsureUser(env *Env) func(*cobra.Command, []string) error {
}
}
-// closeBackend is a wrapper for a RunE function that will close the backend properly
+// CloseBackend is a wrapper for a RunE function that will close the Backend properly
// if it has been opened.
// This wrapper style is necessary because a Cobra PostE function does not run if RunE return an error.
-func closeBackend(env *Env, runE func(cmd *cobra.Command, args []string) error) func(*cobra.Command, []string) error {
+func CloseBackend(env *Env, runE func(cmd *cobra.Command, args []string) error) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
errRun := runE(cmd, args)
- if env.backend == nil {
+ if env.Backend == nil {
return nil
}
- err := env.backend.Close()
- env.backend = nil
+ err := env.Backend.Close()
+ env.Backend = nil
// prioritize the RunE error
if errRun != nil {
diff --git a/commands/execenv/env_testing.go b/commands/execenv/env_testing.go
new file mode 100644
index 00000000..7d9fbd60
--- /dev/null
+++ b/commands/execenv/env_testing.go
@@ -0,0 +1,48 @@
+package execenv
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+
+ "github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/repository"
+ "github.com/stretchr/testify/require"
+)
+
+type TestOut struct {
+ *bytes.Buffer
+}
+
+func (te *TestOut) Printf(format string, a ...interface{}) {
+ _, _ = fmt.Fprintf(te.Buffer, format, a...)
+}
+
+func (te *TestOut) Print(a ...interface{}) {
+ _, _ = fmt.Fprint(te.Buffer, a...)
+}
+
+func (te *TestOut) Println(a ...interface{}) {
+ _, _ = fmt.Fprintln(te.Buffer, a...)
+}
+
+func NewTestEnv(t *testing.T) *Env {
+ t.Helper()
+
+ repo := repository.CreateGoGitTestRepo(t, false)
+
+ buf := new(bytes.Buffer)
+
+ backend, err := cache.NewRepoCache(repo)
+ require.NoError(t, err)
+ t.Cleanup(func() {
+ backend.Close()
+ })
+
+ return &Env{
+ Repo: repo,
+ Backend: backend,
+ Out: &TestOut{buf},
+ Err: &TestOut{buf},
+ }
+}
diff --git a/commands/golden_test.go b/commands/golden_test.go
deleted file mode 100644
index 9fcee0d6..00000000
--- a/commands/golden_test.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package commands
-
-import "flag"
-
-var update = flag.Bool("update", false, "update golden files")
diff --git a/commands/input/input.go b/commands/input/input.go
index e9c1be1b..ee343cd8 100644
--- a/commands/input/input.go
+++ b/commands/input/input.go
@@ -25,7 +25,7 @@ const messageFilename = "BUG_MESSAGE_EDITMSG"
// ErrEmptyMessage is returned when the required message has not been entered
var ErrEmptyMessage = errors.New("empty message")
-// ErrEmptyMessage is returned when the required title has not been entered
+// ErrEmptyTitle is returned when the required title has not been entered
var ErrEmptyTitle = errors.New("empty title")
const bugTitleCommentTemplate = `%s%s
diff --git a/commands/label.go b/commands/label.go
index ff4d0151..70090d26 100644
--- a/commands/label.go
+++ b/commands/label.go
@@ -3,39 +3,32 @@ package commands
import (
"github.com/spf13/cobra"
- _select "github.com/MichaelMure/git-bug/commands/select"
+ "github.com/MichaelMure/git-bug/commands/execenv"
)
func newLabelCommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
cmd := &cobra.Command{
- Use: "label [ID]",
- Short: "Display, add or remove labels to/from a bug.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runLabel(env, args)
+ Use: "label",
+ Short: "List valid labels",
+ Long: `List valid labels.
+
+Note: in the future, a proper label policy could be implemented where valid labels are defined in a configuration file. Until that, the default behavior is to return the list of labels already used.`,
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runLabel(env)
}),
- ValidArgsFunction: completeBug(env),
}
- cmd.AddCommand(newLabelAddCommand())
- cmd.AddCommand(newLabelLsCommand())
- cmd.AddCommand(newLabelRmCommand())
-
return cmd
}
-func runLabel(env *Env, args []string) error {
- b, _, err := _select.ResolveBug(env.backend, args)
- if err != nil {
- return err
- }
-
- snap := b.Snapshot()
+func runLabel(env *execenv.Env) error {
+ labels := env.Backend.ValidLabels()
- for _, l := range snap.Labels {
- env.out.Println(l)
+ for _, l := range labels {
+ env.Out.Println(l)
}
return nil
diff --git a/commands/label_add.go b/commands/label_add.go
deleted file mode 100644
index 65439a4a..00000000
--- a/commands/label_add.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-
- _select "github.com/MichaelMure/git-bug/commands/select"
- "github.com/MichaelMure/git-bug/util/text"
-)
-
-func newLabelAddCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "add [ID] LABEL...",
- Short: "Add a label to a bug.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runLabelAdd(env, args)
- }),
- ValidArgsFunction: completeBugAndLabels(env, true),
- }
-
- return cmd
-}
-
-func runLabelAdd(env *Env, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
- if err != nil {
- return err
- }
-
- added := args
-
- changes, _, err := b.ChangeLabels(text.CleanupOneLineArray(added), nil)
-
- for _, change := range changes {
- env.out.Println(change)
- }
-
- if err != nil {
- return err
- }
-
- return b.Commit()
-}
diff --git a/commands/label_ls.go b/commands/label_ls.go
deleted file mode 100644
index 242eb00c..00000000
--- a/commands/label_ls.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-)
-
-func newLabelLsCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "ls",
- Short: "List valid labels.",
- Long: `List valid labels.
-
-Note: in the future, a proper label policy could be implemented where valid labels are defined in a configuration file. Until that, the default behavior is to return the list of labels already used.`,
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runLabelLs(env)
- }),
- }
-
- return cmd
-}
-
-func runLabelLs(env *Env) error {
- labels := env.backend.ValidLabels()
-
- for _, l := range labels {
- env.out.Println(l)
- }
-
- return nil
-}
diff --git a/commands/label_rm.go b/commands/label_rm.go
deleted file mode 100644
index 3f4e1958..00000000
--- a/commands/label_rm.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-
- _select "github.com/MichaelMure/git-bug/commands/select"
- "github.com/MichaelMure/git-bug/util/text"
-)
-
-func newLabelRmCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "rm [ID] LABEL...",
- Short: "Remove a label from a bug.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runLabelRm(env, args)
- }),
- ValidArgsFunction: completeBugAndLabels(env, false),
- }
-
- return cmd
-}
-
-func runLabelRm(env *Env, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
- if err != nil {
- return err
- }
-
- removed := args
-
- changes, _, err := b.ChangeLabels(nil, text.CleanupOneLineArray(removed))
-
- for _, change := range changes {
- env.out.Println(change)
- }
-
- if err != nil {
- return err
- }
-
- return b.Commit()
-}
diff --git a/commands/ls-id.go b/commands/ls-id.go
deleted file mode 100644
index 31107e87..00000000
--- a/commands/ls-id.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-)
-
-func newLsIdCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "ls-id [PREFIX]",
- Short: "List bug identifiers.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runLsId(env, args)
- }),
- Deprecated: `and will be removed in v1.0.
-
-Please use the "ls" command which allows filtering and sorting of the resulting
-list of ids. The following example would print a new-line separated list containing
-the ids of all open bugs:
-git-bug ls --format id --status open
-`,
- }
-
- return cmd
-}
-
-func runLsId(env *Env, args []string) error {
- var prefix = ""
- if len(args) != 0 {
- prefix = args[0]
- }
-
- for _, id := range env.backend.AllBugsIds() {
- if prefix == "" || id.HasPrefix(prefix) {
- env.out.Println(id)
- }
- }
-
- return nil
-}
diff --git a/commands/ls-labels.go b/commands/ls-labels.go
deleted file mode 100644
index 00fc3fe6..00000000
--- a/commands/ls-labels.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-)
-
-func newLsLabelCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "ls-label",
- Short: "List valid labels.",
- Long: `List valid labels.
-
-Note: in the future, a proper label policy could be implemented where valid labels are defined in a configuration file. Until that, the default behavior is to return the list of labels already used.`,
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runLabelLs(env)
- }),
- Deprecated: ` and will be removed in v1.0.
-
-The functionality provided by this command is now provided by
-the following (equivalent) command:
-git-bug label ls
-`,
- }
-
- return cmd
-}
diff --git a/commands/pull.go b/commands/pull.go
index 29c9f034..2e2639e1 100644
--- a/commands/pull.go
+++ b/commands/pull.go
@@ -5,26 +5,28 @@ import (
"github.com/spf13/cobra"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/entity"
)
func newPullCommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
cmd := &cobra.Command{
Use: "pull [REMOTE]",
- Short: "Pull bugs update from a git remote.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
+ Short: "Pull updates from a git remote",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
return runPull(env, args)
}),
- ValidArgsFunction: completeGitRemote(env),
+ ValidArgsFunction: completion.GitRemote(env),
}
return cmd
}
-func runPull(env *Env, args []string) error {
+func runPull(env *execenv.Env, args []string) error {
if len(args) > 1 {
return errors.New("Only pulling from one remote at a time is supported")
}
@@ -34,24 +36,24 @@ func runPull(env *Env, args []string) error {
remote = args[0]
}
- env.out.Println("Fetching remote ...")
+ env.Out.Println("Fetching remote ...")
- stdout, err := env.backend.Fetch(remote)
+ stdout, err := env.Backend.Fetch(remote)
if err != nil {
return err
}
- env.out.Println(stdout)
+ env.Out.Println(stdout)
- env.out.Println("Merging data ...")
+ env.Out.Println("Merging data ...")
- for result := range env.backend.MergeAll(remote) {
+ for result := range env.Backend.MergeAll(remote) {
if result.Err != nil {
- env.err.Println(result.Err)
+ env.Err.Println(result.Err)
}
if result.Status != entity.MergeStatusNothing {
- env.out.Printf("%s: %s\n", result.Id.Human(), result)
+ env.Out.Printf("%s: %s\n", result.Id.Human(), result)
}
}
diff --git a/commands/push.go b/commands/push.go
index adba6bef..d45e301a 100644
--- a/commands/push.go
+++ b/commands/push.go
@@ -4,25 +4,28 @@ import (
"errors"
"github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
)
func newPushCommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
cmd := &cobra.Command{
Use: "push [REMOTE]",
- Short: "Push bugs update to a git remote.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
+ Short: "Push updates to a git remote",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
return runPush(env, args)
}),
- ValidArgsFunction: completeGitRemote(env),
+ ValidArgsFunction: completion.GitRemote(env),
}
return cmd
}
-func runPush(env *Env, args []string) error {
+func runPush(env *execenv.Env, args []string) error {
if len(args) > 1 {
return errors.New("Only pushing to one remote at a time is supported")
}
@@ -32,12 +35,12 @@ func runPush(env *Env, args []string) error {
remote = args[0]
}
- stdout, err := env.backend.Push(remote)
+ stdout, err := env.Backend.Push(remote)
if err != nil {
return err
}
- env.out.Println(stdout)
+ env.Out.Println(stdout)
return nil
}
diff --git a/commands/rm.go b/commands/rm.go
deleted file mode 100644
index 2e1d924d..00000000
--- a/commands/rm.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package commands
-
-import (
- "errors"
-
- "github.com/spf13/cobra"
-)
-
-func newRmCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "rm ID",
- Short: "Remove an existing bug.",
- Long: "Remove an existing bug in the local repository. Note removing bugs that were imported from bridges will not remove the bug on the remote, and will only remove the local copy of the bug.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runRm(env, args)
- }),
- ValidArgsFunction: completeBug(env),
- }
-
- flags := cmd.Flags()
- flags.SortFlags = false
-
- return cmd
-}
-
-func runRm(env *Env, args []string) (err error) {
- if len(args) == 0 {
- return errors.New("you must provide a bug prefix to remove")
- }
-
- err = env.backend.RemoveBug(args[0])
-
- if err != nil {
- return
- }
-
- env.out.Printf("bug %s removed\n", args[0])
-
- return
-}
diff --git a/commands/rm_test.go b/commands/rm_test.go
deleted file mode 100644
index 0156bbd4..00000000
--- a/commands/rm_test.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package commands
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-func TestRm(t *testing.T) {
- testEnv, bugID := newTestEnvAndBug(t)
-
- exp := "bug " + bugID + " removed\n"
-
- require.NoError(t, runRm(testEnv.env, []string{bugID}))
- require.Equal(t, exp, testEnv.out.String())
- testEnv.out.Reset()
-}
diff --git a/commands/root.go b/commands/root.go
index e012bd83..b28b77b8 100644
--- a/commands/root.go
+++ b/commands/root.go
@@ -6,9 +6,13 @@ import (
"os"
"github.com/spf13/cobra"
-)
-const rootCommandName = "git-bug"
+ "github.com/MichaelMure/git-bug/commands/bridge"
+ usercmd "github.com/MichaelMure/git-bug/commands/user"
+
+ "github.com/MichaelMure/git-bug/commands/bug"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
// These variables are initialized externally during the build. See the Makefile.
var GitCommit string
@@ -17,8 +21,8 @@ var GitExactTag string
func NewRootCommand() *cobra.Command {
cmd := &cobra.Command{
- Use: rootCommandName,
- Short: "A bug tracker embedded in Git.",
+ Use: execenv.RootCommandName,
+ Short: "A bug tracker embedded in Git",
Long: `git-bug is a bug tracker embedded in git.
git-bug use git objects to store the bug tracking separated from the files
@@ -52,26 +56,32 @@ the same git remote you are already using to collaborate with other people.
DisableAutoGenTag: true,
}
- cmd.AddCommand(newAddCommand())
- cmd.AddCommand(newBridgeCommand())
+ const entityGroup = "entity"
+ const uiGroup = "ui"
+ const remoteGroup = "remote"
+
+ cmd.AddGroup(&cobra.Group{ID: entityGroup, Title: "Entities"})
+ cmd.AddGroup(&cobra.Group{ID: uiGroup, Title: "User interfaces"})
+ cmd.AddGroup(&cobra.Group{ID: remoteGroup, Title: "Interaction with the outside world"})
+
+ addCmdWithGroup := func(child *cobra.Command, groupID string) {
+ cmd.AddCommand(child)
+ child.GroupID = groupID
+ }
+
+ addCmdWithGroup(bugcmd.NewBugCommand(), entityGroup)
+ addCmdWithGroup(usercmd.NewUserCommand(), entityGroup)
+ addCmdWithGroup(newLabelCommand(), entityGroup)
+
+ addCmdWithGroup(newTermUICommand(), uiGroup)
+ addCmdWithGroup(newWebUICommand(), uiGroup)
+
+ addCmdWithGroup(newPullCommand(), remoteGroup)
+ addCmdWithGroup(newPushCommand(), remoteGroup)
+ addCmdWithGroup(bridgecmd.NewBridgeCommand(), remoteGroup)
+
cmd.AddCommand(newCommandsCommand())
- cmd.AddCommand(newCommentCommand())
- cmd.AddCommand(newDeselectCommand())
- cmd.AddCommand(newLabelCommand())
- cmd.AddCommand(newLsCommand())
- cmd.AddCommand(newLsIdCommand())
- cmd.AddCommand(newLsLabelCommand())
- cmd.AddCommand(newPullCommand())
- cmd.AddCommand(newPushCommand())
- cmd.AddCommand(newRmCommand())
- cmd.AddCommand(newSelectCommand())
- cmd.AddCommand(newShowCommand())
- cmd.AddCommand(newStatusCommand())
- cmd.AddCommand(newTermUICommand())
- cmd.AddCommand(newTitleCommand())
- cmd.AddCommand(newUserCommand())
cmd.AddCommand(newVersionCommand())
- cmd.AddCommand(newWebUICommand())
return cmd
}
diff --git a/commands/select.go b/commands/select.go
deleted file mode 100644
index f9e6ece7..00000000
--- a/commands/select.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package commands
-
-import (
- "errors"
-
- "github.com/spf13/cobra"
-
- _select "github.com/MichaelMure/git-bug/commands/select"
-)
-
-func newSelectCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "select ID",
- Short: "Select a bug for implicit use in future commands.",
- Example: `git bug select 2f15
-git bug comment
-git bug status
-`,
- Long: `Select a bug for implicit use in future commands.
-
-This command allows you to omit any bug ID argument, for example:
- git bug show
-instead of
- git bug show 2f153ca
-
-The complementary command is "git bug deselect" performing the opposite operation.
-`,
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runSelect(env, args)
- }),
- ValidArgsFunction: completeBug(env),
- }
-
- return cmd
-}
-
-func runSelect(env *Env, args []string) error {
- if len(args) == 0 {
- return errors.New("You must provide a bug id")
- }
-
- prefix := args[0]
-
- b, err := env.backend.ResolveBugPrefix(prefix)
- if err != nil {
- return err
- }
-
- err = _select.Select(env.backend, b.Id())
- if err != nil {
- return err
- }
-
- env.out.Printf("selected bug %s: %s\n", b.Id().Human(), b.Snapshot().Title)
-
- return nil
-}
diff --git a/commands/status.go b/commands/status.go
deleted file mode 100644
index c3e860b6..00000000
--- a/commands/status.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package commands
-
-import (
- _select "github.com/MichaelMure/git-bug/commands/select"
- "github.com/spf13/cobra"
-)
-
-func newStatusCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "status [ID]",
- Short: "Display or change a bug status.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runStatus(env, args)
- }),
- ValidArgsFunction: completeBug(env),
- }
-
- cmd.AddCommand(newStatusCloseCommand())
- cmd.AddCommand(newStatusOpenCommand())
-
- return cmd
-}
-
-func runStatus(env *Env, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
- if err != nil {
- return err
- }
-
- snap := b.Snapshot()
-
- env.out.Println(snap.Status)
-
- return nil
-}
diff --git a/commands/status_close.go b/commands/status_close.go
deleted file mode 100644
index 8541aa0b..00000000
--- a/commands/status_close.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package commands
-
-import (
- _select "github.com/MichaelMure/git-bug/commands/select"
- "github.com/spf13/cobra"
-)
-
-func newStatusCloseCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "close [ID]",
- Short: "Mark a bug as closed.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runStatusClose(env, args)
- }),
- }
-
- return cmd
-}
-
-func runStatusClose(env *Env, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
- if err != nil {
- return err
- }
-
- _, err = b.Close()
- if err != nil {
- return err
- }
-
- return b.Commit()
-}
diff --git a/commands/status_open.go b/commands/status_open.go
deleted file mode 100644
index ee6bd27a..00000000
--- a/commands/status_open.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package commands
-
-import (
- _select "github.com/MichaelMure/git-bug/commands/select"
- "github.com/spf13/cobra"
-)
-
-func newStatusOpenCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "open [ID]",
- Short: "Mark a bug as open.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runStatusOpen(env, args)
- }),
- }
-
- return cmd
-}
-
-func runStatusOpen(env *Env, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
- if err != nil {
- return err
- }
-
- _, err = b.Open()
- if err != nil {
- return err
- }
-
- return b.Commit()
-}
diff --git a/commands/termui.go b/commands/termui.go
index 4df6cdaf..1cfdd8f3 100644
--- a/commands/termui.go
+++ b/commands/termui.go
@@ -3,18 +3,19 @@ package commands
import (
"github.com/spf13/cobra"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/termui"
)
func newTermUICommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
cmd := &cobra.Command{
Use: "termui",
Aliases: []string{"tui"},
- Short: "Launch the terminal UI.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
+ Short: "Launch the terminal UI",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
return runTermUI(env)
}),
}
@@ -22,6 +23,6 @@ func newTermUICommand() *cobra.Command {
return cmd
}
-func runTermUI(env *Env) error {
- return termui.Run(env.backend)
+func runTermUI(env *execenv.Env) error {
+ return termui.Run(env.Backend)
}
diff --git a/commands/title.go b/commands/title.go
deleted file mode 100644
index f99c6eff..00000000
--- a/commands/title.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package commands
-
-import (
- _select "github.com/MichaelMure/git-bug/commands/select"
- "github.com/spf13/cobra"
-)
-
-func newTitleCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "title [ID]",
- Short: "Display or change a title of a bug.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runTitle(env, args)
- }),
- ValidArgsFunction: completeBug(env),
- }
-
- cmd.AddCommand(newTitleEditCommand())
-
- return cmd
-}
-
-func runTitle(env *Env, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
- if err != nil {
- return err
- }
-
- snap := b.Snapshot()
-
- env.out.Println(snap.Title)
-
- return nil
-}
diff --git a/commands/title_edit.go b/commands/title_edit.go
deleted file mode 100644
index a1ba0324..00000000
--- a/commands/title_edit.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-
- "github.com/MichaelMure/git-bug/commands/input"
- _select "github.com/MichaelMure/git-bug/commands/select"
- "github.com/MichaelMure/git-bug/util/text"
-)
-
-type titleEditOptions struct {
- title string
- nonInteractive bool
-}
-
-func newTitleEditCommand() *cobra.Command {
- env := newEnv()
- options := titleEditOptions{}
-
- cmd := &cobra.Command{
- Use: "edit [ID]",
- Short: "Edit a title of a bug.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runTitleEdit(env, options, args)
- }),
- ValidArgsFunction: completeBug(env),
- }
-
- flags := cmd.Flags()
- flags.SortFlags = false
-
- flags.StringVarP(&options.title, "title", "t", "",
- "Provide a title to describe the issue",
- )
- flags.BoolVar(&options.nonInteractive, "non-interactive", false, "Do not ask for user input")
-
- return cmd
-}
-
-func runTitleEdit(env *Env, opts titleEditOptions, args []string) error {
- b, args, err := _select.ResolveBug(env.backend, args)
- if err != nil {
- return err
- }
-
- snap := b.Snapshot()
-
- if opts.title == "" {
- if opts.nonInteractive {
- env.err.Println("No title given. Use -m or -F option to specify a title. Aborting.")
- return nil
- }
- opts.title, err = input.BugTitleEditorInput(env.repo, snap.Title)
- if err == input.ErrEmptyTitle {
- env.out.Println("Empty title, aborting.")
- return nil
- }
- if err != nil {
- return err
- }
- }
-
- if opts.title == snap.Title {
- env.err.Println("No change, aborting.")
- }
-
- _, err = b.SetTitle(text.CleanupOneLine(opts.title))
- if err != nil {
- return err
- }
-
- return b.Commit()
-}
diff --git a/commands/user.go b/commands/user.go
deleted file mode 100644
index 0fe3be4d..00000000
--- a/commands/user.go
+++ /dev/null
@@ -1,110 +0,0 @@
-package commands
-
-import (
- "errors"
- "fmt"
- "strings"
-
- "github.com/spf13/cobra"
-
- "github.com/MichaelMure/git-bug/cache"
-)
-
-type userOptions struct {
- fields string
-}
-
-func newUserCommand() *cobra.Command {
- env := newEnv()
- options := userOptions{}
-
- cmd := &cobra.Command{
- Use: "user [USER-ID]",
- Short: "Display or change the user identity.",
- PreRunE: loadBackendEnsureUser(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runUser(env, options, args)
- }),
- ValidArgsFunction: completeUser(env),
- }
-
- cmd.AddCommand(newUserAdoptCommand())
- cmd.AddCommand(newUserCreateCommand())
- cmd.AddCommand(newUserLsCommand())
-
- flags := cmd.Flags()
- flags.SortFlags = false
-
- fields := []string{"email", "humanId", "id", "lastModification", "lastModificationLamports", "login", "metadata", "name"}
- flags.StringVarP(&options.fields, "field", "f", "",
- "Select field to display. Valid values are ["+strings.Join(fields, ",")+"]")
- cmd.RegisterFlagCompletionFunc("field", completeFrom(fields))
-
- return cmd
-}
-
-func runUser(env *Env, opts userOptions, args []string) error {
- if len(args) > 1 {
- return errors.New("only one identity can be displayed at a time")
- }
-
- var id *cache.IdentityCache
- var err error
- if len(args) == 1 {
- id, err = env.backend.ResolveIdentityPrefix(args[0])
- } else {
- id, err = env.backend.GetUserIdentity()
- }
-
- if err != nil {
- return err
- }
-
- if opts.fields != "" {
- switch opts.fields {
- case "email":
- env.out.Printf("%s\n", id.Email())
- case "login":
- env.out.Printf("%s\n", id.Login())
- case "humanId":
- env.out.Printf("%s\n", id.Id().Human())
- case "id":
- env.out.Printf("%s\n", id.Id())
- case "lastModification":
- env.out.Printf("%s\n", id.LastModification().
- Time().Format("Mon Jan 2 15:04:05 2006 +0200"))
- case "lastModificationLamport":
- for name, t := range id.LastModificationLamports() {
- env.out.Printf("%s\n%d\n", name, t)
- }
- case "metadata":
- for key, value := range id.ImmutableMetadata() {
- env.out.Printf("%s\n%s\n", key, value)
- }
- case "name":
- env.out.Printf("%s\n", id.Name())
-
- default:
- return fmt.Errorf("\nUnsupported field: %s\n", opts.fields)
- }
-
- return nil
- }
-
- env.out.Printf("Id: %s\n", id.Id())
- env.out.Printf("Name: %s\n", id.Name())
- env.out.Printf("Email: %s\n", id.Email())
- env.out.Printf("Login: %s\n", id.Login())
- env.out.Printf("Last modification: %s\n", id.LastModification().Time().Format("Mon Jan 2 15:04:05 2006 +0200"))
- env.out.Printf("Last moditication (lamport):\n")
- for name, t := range id.LastModificationLamports() {
- env.out.Printf("\t%s: %d", name, t)
- }
- env.out.Println("Metadata:")
- for key, value := range id.ImmutableMetadata() {
- env.out.Printf(" %s --> %s\n", key, value)
- }
- // env.out.Printf("Protected: %v\n", id.IsProtected())
-
- return nil
-}
diff --git a/commands/user/user.go b/commands/user/user.go
new file mode 100644
index 00000000..191fb828
--- /dev/null
+++ b/commands/user/user.go
@@ -0,0 +1,89 @@
+package usercmd
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/spf13/cobra"
+
+ json2 "github.com/MichaelMure/git-bug/commands/cmdjson"
+
+ "github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+ "github.com/MichaelMure/git-bug/util/colors"
+)
+
+type userOptions struct {
+ format string
+}
+
+func NewUserCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := userOptions{}
+
+ cmd := &cobra.Command{
+ Use: "user",
+ Short: "List identities",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runUser(env, options)
+ }),
+ }
+
+ cmd.AddCommand(newUserNewCommand())
+ cmd.AddCommand(newUserShowCommand())
+ cmd.AddCommand(newUserAdoptCommand())
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.StringVarP(&options.format, "format", "f", "default",
+ "Select the output formatting style. Valid values are [default,json]")
+ cmd.RegisterFlagCompletionFunc("format", completion.From([]string{"default", "json"}))
+
+ return cmd
+}
+
+func runUser(env *execenv.Env, opts userOptions) error {
+ ids := env.Backend.AllIdentityIds()
+ var users []*cache.IdentityExcerpt
+ for _, id := range ids {
+ user, err := env.Backend.ResolveIdentityExcerpt(id)
+ if err != nil {
+ return err
+ }
+ users = append(users, user)
+ }
+
+ switch opts.format {
+ case "json":
+ return userJsonFormatter(env, users)
+ case "default":
+ return userDefaultFormatter(env, users)
+ default:
+ return fmt.Errorf("unknown format %s", opts.format)
+ }
+}
+
+func userDefaultFormatter(env *execenv.Env, users []*cache.IdentityExcerpt) error {
+ for _, user := range users {
+ env.Out.Printf("%s %s\n",
+ colors.Cyan(user.Id.Human()),
+ user.DisplayName(),
+ )
+ }
+
+ return nil
+}
+
+func userJsonFormatter(env *execenv.Env, users []*cache.IdentityExcerpt) error {
+ jsonUsers := make([]json2.Identity, len(users))
+ for i, user := range users {
+ jsonUsers[i] = json2.NewIdentityFromExcerpt(user)
+ }
+
+ jsonObject, _ := json.MarshalIndent(jsonUsers, "", " ")
+ env.Out.Printf("%s\n", jsonObject)
+ return nil
+}
diff --git a/commands/user/user_adopt.go b/commands/user/user_adopt.go
new file mode 100644
index 00000000..f5944053
--- /dev/null
+++ b/commands/user/user_adopt.go
@@ -0,0 +1,43 @@
+package usercmd
+
+import (
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+func newUserAdoptCommand() *cobra.Command {
+ env := execenv.NewEnv()
+
+ cmd := &cobra.Command{
+ Use: "adopt USER_ID",
+ Short: "Adopt an existing identity as your own",
+ Args: cobra.ExactArgs(1),
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runUserAdopt(env, args)
+ }),
+ ValidArgsFunction: completion.User(env),
+ }
+
+ return cmd
+}
+
+func runUserAdopt(env *execenv.Env, args []string) error {
+ prefix := args[0]
+
+ i, err := env.Backend.ResolveIdentityPrefix(prefix)
+ if err != nil {
+ return err
+ }
+
+ err = env.Backend.SetUserIdentity(i)
+ if err != nil {
+ return err
+ }
+
+ env.Out.Printf("Your identity is now: %s\n", i.DisplayName())
+
+ return nil
+}
diff --git a/commands/user_create.go b/commands/user/user_new.go
index 6941cff5..d7224512 100644
--- a/commands/user_create.go
+++ b/commands/user/user_new.go
@@ -1,28 +1,29 @@
-package commands
+package usercmd
import (
"github.com/spf13/cobra"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/commands/input"
)
-type createUserOptions struct {
+type userNewOptions struct {
name string
email string
avatarURL string
nonInteractive bool
}
-func newUserCreateCommand() *cobra.Command {
- env := newEnv()
+func newUserNewCommand() *cobra.Command {
+ env := execenv.NewEnv()
- options := createUserOptions{}
+ options := userNewOptions{}
cmd := &cobra.Command{
- Use: "create",
- Short: "Create a new identity.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runUserCreate(env, options)
+ Use: "new",
+ Short: "Create a new identity",
+ PreRunE: execenv.LoadBackend(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runUserNew(env, options)
}),
}
@@ -35,10 +36,10 @@ func newUserCreateCommand() *cobra.Command {
return cmd
}
-func runUserCreate(env *Env, opts createUserOptions) error {
+func runUserNew(env *execenv.Env, opts userNewOptions) error {
if !opts.nonInteractive && opts.name == "" {
- preName, err := env.backend.GetUserName()
+ preName, err := env.Backend.GetUserName()
if err != nil {
return err
}
@@ -49,7 +50,7 @@ func runUserCreate(env *Env, opts createUserOptions) error {
}
if !opts.nonInteractive && opts.email == "" {
- preEmail, err := env.backend.GetUserEmail()
+ preEmail, err := env.Backend.GetUserEmail()
if err != nil {
return err
}
@@ -68,7 +69,7 @@ func runUserCreate(env *Env, opts createUserOptions) error {
}
}
- id, err := env.backend.NewIdentityRaw(opts.name, opts.email, "", opts.avatarURL, nil, nil)
+ id, err := env.Backend.NewIdentityRaw(opts.name, opts.email, "", opts.avatarURL, nil, nil)
if err != nil {
return err
}
@@ -78,20 +79,20 @@ func runUserCreate(env *Env, opts createUserOptions) error {
return err
}
- set, err := env.backend.IsUserIdentitySet()
+ set, err := env.Backend.IsUserIdentitySet()
if err != nil {
return err
}
if !set {
- err = env.backend.SetUserIdentity(id)
+ err = env.Backend.SetUserIdentity(id)
if err != nil {
return err
}
}
- env.err.Println()
- env.out.Println(id.Id())
+ env.Err.Println()
+ env.Out.Println(id.Id())
return nil
}
diff --git a/commands/user/user_new_test.go b/commands/user/user_new_test.go
new file mode 100644
index 00000000..619e5de6
--- /dev/null
+++ b/commands/user/user_new_test.go
@@ -0,0 +1,14 @@
+package usercmd
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "github.com/MichaelMure/git-bug/commands/bug/testenv"
+)
+
+func TestUserNewCommand(t *testing.T) {
+ _, userID := testenv.NewTestEnvAndUser(t)
+ require.Regexp(t, "[0-9a-f]{64}", userID)
+}
diff --git a/commands/user/user_show.go b/commands/user/user_show.go
new file mode 100644
index 00000000..36c09e8e
--- /dev/null
+++ b/commands/user/user_show.go
@@ -0,0 +1,108 @@
+package usercmd
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ "github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/commands/completion"
+ "github.com/MichaelMure/git-bug/commands/execenv"
+)
+
+type userShowOptions struct {
+ fields string
+}
+
+func newUserShowCommand() *cobra.Command {
+ env := execenv.NewEnv()
+ options := userShowOptions{}
+
+ cmd := &cobra.Command{
+ Use: "user show [USER_ID]",
+ Short: "Display a user identity",
+ PreRunE: execenv.LoadBackendEnsureUser(env),
+ RunE: execenv.CloseBackend(env, func(cmd *cobra.Command, args []string) error {
+ return runUserShow(env, options, args)
+ }),
+ ValidArgsFunction: completion.User(env),
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ fields := []string{"email", "humanId", "id", "lastModification", "lastModificationLamports", "login", "metadata", "name"}
+ flags.StringVarP(&options.fields, "field", "f", "",
+ "Select field to display. Valid values are ["+strings.Join(fields, ",")+"]")
+ cmd.RegisterFlagCompletionFunc("field", completion.From(fields))
+
+ return cmd
+}
+
+func runUserShow(env *execenv.Env, opts userShowOptions, args []string) error {
+ if len(args) > 1 {
+ return errors.New("only one identity can be displayed at a time")
+ }
+
+ var id *cache.IdentityCache
+ var err error
+ if len(args) == 1 {
+ id, err = env.Backend.ResolveIdentityPrefix(args[0])
+ } else {
+ id, err = env.Backend.GetUserIdentity()
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if opts.fields != "" {
+ switch opts.fields {
+ case "email":
+ env.Out.Printf("%s\n", id.Email())
+ case "login":
+ env.Out.Printf("%s\n", id.Login())
+ case "humanId":
+ env.Out.Printf("%s\n", id.Id().Human())
+ case "id":
+ env.Out.Printf("%s\n", id.Id())
+ case "lastModification":
+ env.Out.Printf("%s\n", id.LastModification().
+ Time().Format("Mon Jan 2 15:04:05 2006 +0200"))
+ case "lastModificationLamport":
+ for name, t := range id.LastModificationLamports() {
+ env.Out.Printf("%s\n%d\n", name, t)
+ }
+ case "metadata":
+ for key, value := range id.ImmutableMetadata() {
+ env.Out.Printf("%s\n%s\n", key, value)
+ }
+ case "name":
+ env.Out.Printf("%s\n", id.Name())
+
+ default:
+ return fmt.Errorf("\nUnsupported field: %s\n", opts.fields)
+ }
+
+ return nil
+ }
+
+ env.Out.Printf("Id: %s\n", id.Id())
+ env.Out.Printf("Name: %s\n", id.Name())
+ env.Out.Printf("Email: %s\n", id.Email())
+ env.Out.Printf("Login: %s\n", id.Login())
+ env.Out.Printf("Last modification: %s\n", id.LastModification().Time().Format("Mon Jan 2 15:04:05 2006 +0200"))
+ env.Out.Printf("Last moditication (lamport):\n")
+ for name, t := range id.LastModificationLamports() {
+ env.Out.Printf("\t%s: %d", name, t)
+ }
+ env.Out.Println("Metadata:")
+ for key, value := range id.ImmutableMetadata() {
+ env.Out.Printf(" %s --> %s\n", key, value)
+ }
+ // env.Out.Printf("Protected: %v\n", id.IsProtected())
+
+ return nil
+}
diff --git a/commands/user_adopt.go b/commands/user_adopt.go
deleted file mode 100644
index afef94ea..00000000
--- a/commands/user_adopt.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package commands
-
-import (
- "github.com/spf13/cobra"
-)
-
-func newUserAdoptCommand() *cobra.Command {
- env := newEnv()
-
- cmd := &cobra.Command{
- Use: "adopt USER-ID",
- Short: "Adopt an existing identity as your own.",
- Args: cobra.ExactArgs(1),
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runUserAdopt(env, args)
- }),
- ValidArgsFunction: completeUser(env),
- }
-
- return cmd
-}
-
-func runUserAdopt(env *Env, args []string) error {
- prefix := args[0]
-
- i, err := env.backend.ResolveIdentityPrefix(prefix)
- if err != nil {
- return err
- }
-
- err = env.backend.SetUserIdentity(i)
- if err != nil {
- return err
- }
-
- env.out.Printf("Your identity is now: %s\n", i.DisplayName())
-
- return nil
-}
diff --git a/commands/user_create_test.go b/commands/user_create_test.go
deleted file mode 100644
index 08958344..00000000
--- a/commands/user_create_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package commands
-
-import (
- "strings"
- "testing"
-
- "github.com/stretchr/testify/require"
-)
-
-const (
- testUserName = "John Doe"
- testUserEmail = "jdoe@example.com"
-)
-
-func newTestEnvAndUser(t *testing.T) (*testEnv, string) {
- t.Helper()
-
- testEnv := newTestEnv(t)
-
- opts := createUserOptions{
- name: testUserName,
- email: testUserEmail,
- avatarURL: "",
- nonInteractive: true,
- }
-
- require.NoError(t, runUserCreate(testEnv.env, opts))
-
- userID := strings.TrimSpace(testEnv.out.String())
- testEnv.out.Reset()
-
- return testEnv, userID
-}
-
-func TestUserCreateCommand(t *testing.T) {
- _, userID := newTestEnvAndUser(t)
- require.Regexp(t, "[0-9a-f]{64}", userID)
-}
diff --git a/commands/user_ls.go b/commands/user_ls.go
deleted file mode 100644
index 341f0dc1..00000000
--- a/commands/user_ls.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package commands
-
-import (
- "encoding/json"
- "fmt"
-
- "github.com/spf13/cobra"
-
- "github.com/MichaelMure/git-bug/cache"
- "github.com/MichaelMure/git-bug/util/colors"
-)
-
-type userLsOptions struct {
- format string
-}
-
-func newUserLsCommand() *cobra.Command {
- env := newEnv()
- options := userLsOptions{}
-
- cmd := &cobra.Command{
- Use: "ls",
- Short: "List identities.",
- PreRunE: loadBackend(env),
- RunE: closeBackend(env, func(cmd *cobra.Command, args []string) error {
- return runUserLs(env, options)
- }),
- }
-
- flags := cmd.Flags()
- flags.SortFlags = false
-
- flags.StringVarP(&options.format, "format", "f", "default",
- "Select the output formatting style. Valid values are [default,json]")
- cmd.RegisterFlagCompletionFunc("format", completeFrom([]string{"default", "json"}))
-
- return cmd
-}
-
-func runUserLs(env *Env, opts userLsOptions) error {
- ids := env.backend.AllIdentityIds()
- var users []*cache.IdentityExcerpt
- for _, id := range ids {
- user, err := env.backend.ResolveIdentityExcerpt(id)
- if err != nil {
- return err
- }
- users = append(users, user)
- }
-
- switch opts.format {
- case "json":
- return userLsJsonFormatter(env, users)
- case "default":
- return userLsDefaultFormatter(env, users)
- default:
- return fmt.Errorf("unknown format %s", opts.format)
- }
-}
-
-func userLsDefaultFormatter(env *Env, users []*cache.IdentityExcerpt) error {
- for _, user := range users {
- env.out.Printf("%s %s\n",
- colors.Cyan(user.Id.Human()),
- user.DisplayName(),
- )
- }
-
- return nil
-}
-
-func userLsJsonFormatter(env *Env, users []*cache.IdentityExcerpt) error {
- jsonUsers := make([]JSONIdentity, len(users))
- for i, user := range users {
- jsonUsers[i] = NewJSONIdentityFromExcerpt(user)
- }
-
- jsonObject, _ := json.MarshalIndent(jsonUsers, "", " ")
- env.out.Printf("%s\n", jsonObject)
- return nil
-}
diff --git a/commands/version.go b/commands/version.go
index 71baba40..0e54bb92 100644
--- a/commands/version.go
+++ b/commands/version.go
@@ -4,6 +4,8 @@ import (
"runtime"
"github.com/spf13/cobra"
+
+ "github.com/MichaelMure/git-bug/commands/execenv"
)
type versionOptions struct {
@@ -13,12 +15,12 @@ type versionOptions struct {
}
func newVersionCommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
options := versionOptions{}
cmd := &cobra.Command{
Use: "version",
- Short: "Show git-bug version information.",
+ Short: "Show git-bug version information",
Run: func(cmd *cobra.Command, args []string) {
runVersion(env, options, cmd.Root())
},
@@ -40,23 +42,23 @@ func newVersionCommand() *cobra.Command {
return cmd
}
-func runVersion(env *Env, opts versionOptions, root *cobra.Command) {
+func runVersion(env *execenv.Env, opts versionOptions, root *cobra.Command) {
if opts.all {
- env.out.Printf("%s version: %s\n", rootCommandName, root.Version)
- env.out.Printf("System version: %s/%s\n", runtime.GOARCH, runtime.GOOS)
- env.out.Printf("Golang version: %s\n", runtime.Version())
+ env.Out.Printf("%s version: %s\n", execenv.RootCommandName, root.Version)
+ env.Out.Printf("System version: %s/%s\n", runtime.GOARCH, runtime.GOOS)
+ env.Out.Printf("Golang version: %s\n", runtime.Version())
return
}
if opts.number {
- env.out.Println(root.Version)
+ env.Out.Println(root.Version)
return
}
if opts.commit {
- env.out.Println(GitCommit)
+ env.Out.Println(GitCommit)
return
}
- env.out.Printf("%s version: %s\n", rootCommandName, root.Version)
+ env.Out.Printf("%s version: %s\n", execenv.RootCommandName, root.Version)
}
diff --git a/commands/webui.go b/commands/webui.go
index 758a153b..5fe66aa7 100644
--- a/commands/webui.go
+++ b/commands/webui.go
@@ -23,6 +23,7 @@ import (
"github.com/MichaelMure/git-bug/api/graphql"
httpapi "github.com/MichaelMure/git-bug/api/http"
"github.com/MichaelMure/git-bug/cache"
+ "github.com/MichaelMure/git-bug/commands/execenv"
"github.com/MichaelMure/git-bug/entities/identity"
"github.com/MichaelMure/git-bug/repository"
"github.com/MichaelMure/git-bug/webui"
@@ -41,18 +42,18 @@ type webUIOptions struct {
}
func newWebUICommand() *cobra.Command {
- env := newEnv()
+ env := execenv.NewEnv()
options := webUIOptions{}
cmd := &cobra.Command{
Use: "webui",
- Short: "Launch the web UI.",
+ Short: "Launch the web UI",
Long: `Launch the web UI.
Available git config:
git-bug.webui.open [bool]: control the automatic opening of the web UI in the default browser
`,
- PreRunE: loadRepo(env),
+ PreRunE: execenv.LoadRepo(env),
RunE: func(cmd *cobra.Command, args []string) error {
return runWebUI(env, options)
},
@@ -72,7 +73,7 @@ Available git config:
return cmd
}
-func runWebUI(env *Env, opts webUIOptions) error {
+func runWebUI(env *execenv.Env, opts webUIOptions) error {
if opts.port == 0 {
var err error
opts.port, err = freeport.GetFreePort()
@@ -96,7 +97,7 @@ func runWebUI(env *Env, opts webUIOptions) error {
// fixed identity: the default user of the repo
// TODO: support dynamic authentication with OAuth
if !opts.readOnly {
- author, err := identity.GetUserIdentity(env.repo)
+ author, err := identity.GetUserIdentity(env.Repo)
if err != nil {
return err
}
@@ -104,14 +105,14 @@ func runWebUI(env *Env, opts webUIOptions) error {
}
mrc := cache.NewMultiRepoCache()
- _, err := mrc.RegisterDefaultRepository(env.repo)
+ _, err := mrc.RegisterDefaultRepository(env.Repo)
if err != nil {
return err
}
var errOut io.Writer
if opts.logErrors {
- errOut = env.err
+ errOut = env.Err
}
graphqlHandler := graphql.NewHandler(mrc, errOut)
@@ -136,7 +137,7 @@ func runWebUI(env *Env, opts webUIOptions) error {
go func() {
<-quit
- env.out.Println("WebUI is shutting down...")
+ env.Out.Println("WebUI is shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
@@ -149,18 +150,18 @@ func runWebUI(env *Env, opts webUIOptions) error {
// Teardown
err := graphqlHandler.Close()
if err != nil {
- env.out.Println(err)
+ env.Out.Println(err)
}
close(done)
}()
- env.out.Printf("Web UI: %s\n", webUiAddr)
- env.out.Printf("Graphql API: http://%s/graphql\n", addr)
- env.out.Printf("Graphql Playground: http://%s/playground\n", addr)
- env.out.Println("Press Ctrl+c to quit")
+ env.Out.Printf("Web UI: %s\n", webUiAddr)
+ env.Out.Printf("Graphql API: http://%s/graphql\n", addr)
+ env.Out.Printf("Graphql Playground: http://%s/playground\n", addr)
+ env.Out.Println("Press Ctrl+c to quit")
- configOpen, err := env.repo.AnyConfig().ReadBool(webUIOpenConfigKey)
+ configOpen, err := env.Repo.AnyConfig().ReadBool(webUIOpenConfigKey)
if err == repository.ErrNoConfigEntry {
// default to true
configOpen = true
@@ -173,7 +174,7 @@ func runWebUI(env *Env, opts webUIOptions) error {
if shouldOpen {
err = open.Run(toOpen)
if err != nil {
- env.out.Println(err)
+ env.Out.Println(err)
}
}
@@ -184,6 +185,6 @@ func runWebUI(env *Env, opts webUIOptions) error {
<-done
- env.out.Println("WebUI stopped")
+ env.Out.Println("WebUI stopped")
return nil
}
diff --git a/doc/cli-convention.md b/doc/cli-convention.md
new file mode 100644
index 00000000..47eccf69
--- /dev/null
+++ b/doc/cli-convention.md
@@ -0,0 +1,13 @@
+## Pattern
+
+CLI commands should consistently follow this pattern:
+
+```
+xxx --> list xxx things if list, otherwise show one
+xxx new --> create thing
+xxx rm --> delete thing
+xxx show ID --> show one
+xxx show --> show one with "select" implied ID
+xxx yyy --> action commands for that thing, or subcommand
+xxx select|deselect --> select/deselect implied ID
+```
diff --git a/doc/man/git-bug-bridge-auth-rm.1 b/doc/man/git-bug-bridge-auth-rm.1
index a22da320..4ce7672c 100644
--- a/doc/man/git-bug-bridge-auth-rm.1
+++ b/doc/man/git-bug-bridge-auth-rm.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-bridge-auth-rm - Remove a credential.
+git-bug-bridge-auth-rm - Remove a credential
.SH SYNOPSIS
.PP
-\fBgit-bug bridge auth rm ID [flags]\fP
+\fBgit-bug bridge auth rm BRIDGE_ID [flags]\fP
.SH DESCRIPTION
.PP
-Remove a credential.
+Remove a credential
.SH OPTIONS
diff --git a/doc/man/git-bug-bridge-auth-show.1 b/doc/man/git-bug-bridge-auth-show.1
index 19ac9d37..1c4385ff 100644
--- a/doc/man/git-bug-bridge-auth-show.1
+++ b/doc/man/git-bug-bridge-auth-show.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-bridge-auth-show - Display an authentication credential.
+git-bug-bridge-auth-show - Display an authentication credential
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-bridge-auth-show - Display an authentication credential.
.SH DESCRIPTION
.PP
-Display an authentication credential.
+Display an authentication credential
.SH OPTIONS
diff --git a/doc/man/git-bug-bridge-auth.1 b/doc/man/git-bug-bridge-auth.1
index 1fd94f5b..f6f36623 100644
--- a/doc/man/git-bug-bridge-auth.1
+++ b/doc/man/git-bug-bridge-auth.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-bridge-auth - List all known bridge authentication credentials.
+git-bug-bridge-auth - List all known bridge authentication credentials
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-bridge-auth - List all known bridge authentication credentials.
.SH DESCRIPTION
.PP
-List all known bridge authentication credentials.
+List all known bridge authentication credentials
.SH OPTIONS
diff --git a/doc/man/git-bug-bridge-configure.1 b/doc/man/git-bug-bridge-new.1
index 002d8202..1b0b2f38 100644
--- a/doc/man/git-bug-bridge-configure.1
+++ b/doc/man/git-bug-bridge-new.1
@@ -3,12 +3,12 @@
.SH NAME
.PP
-git-bug-bridge-configure - Configure a new bridge.
+git-bug-bridge-new - Configure a new bridge
.SH SYNOPSIS
.PP
-\fBgit-bug bridge configure [flags]\fP
+\fBgit-bug bridge new [flags]\fP
.SH DESCRIPTION
@@ -69,7 +69,7 @@ Configure a new bridge by passing flags or/and using interactive terminal prompt
.PP
\fB-h\fP, \fB--help\fP[=false]
- help for configure
+ help for new
.SH EXAMPLE
@@ -111,7 +111,7 @@ Enter token: 87cf5c03b64029f18ea5f9ca5679daa08ccbd700
Successfully configured bridge: default
# For GitHub
-git bug bridge configure \\
+git bug bridge new \\
--name=default \\
--target=github \\
--owner=$(OWNER) \\
@@ -119,13 +119,13 @@ git bug bridge configure \\
--token=$(TOKEN)
# For Launchpad
-git bug bridge configure \\
+git bug bridge new \\
--name=default \\
--target=launchpad-preview \\
--url=https://bugs.launchpad.net/ubuntu/
# For Gitlab
-git bug bridge configure \\
+git bug bridge new \\
--name=default \\
--target=github \\
--url=https://github.com/michaelmure/git-bug \\
diff --git a/doc/man/git-bug-bridge-pull.1 b/doc/man/git-bug-bridge-pull.1
index 0ff1f860..4d39b0d7 100644
--- a/doc/man/git-bug-bridge-pull.1
+++ b/doc/man/git-bug-bridge-pull.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-bridge-pull - Pull updates.
+git-bug-bridge-pull - Pull updates from a remote bug tracker
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-bridge-pull - Pull updates.
.SH DESCRIPTION
.PP
-Pull updates.
+Pull updates from a remote bug tracker
.SH OPTIONS
diff --git a/doc/man/git-bug-bridge-push.1 b/doc/man/git-bug-bridge-push.1
index fa882cf0..9541c527 100644
--- a/doc/man/git-bug-bridge-push.1
+++ b/doc/man/git-bug-bridge-push.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-bridge-push - Push updates.
+git-bug-bridge-push - Push updates to remote bug tracker
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-bridge-push - Push updates.
.SH DESCRIPTION
.PP
-Push updates.
+Push updates to remote bug tracker
.SH OPTIONS
diff --git a/doc/man/git-bug-bridge-rm.1 b/doc/man/git-bug-bridge-rm.1
index 2445e6d8..6010eca8 100644
--- a/doc/man/git-bug-bridge-rm.1
+++ b/doc/man/git-bug-bridge-rm.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-bridge-rm - Delete a configured bridge.
+git-bug-bridge-rm - Delete a configured bridge
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-bridge-rm - Delete a configured bridge.
.SH DESCRIPTION
.PP
-Delete a configured bridge.
+Delete a configured bridge
.SH OPTIONS
diff --git a/doc/man/git-bug-bridge.1 b/doc/man/git-bug-bridge.1
index 30e5f3ed..7fbce2c1 100644
--- a/doc/man/git-bug-bridge.1
+++ b/doc/man/git-bug-bridge.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-bridge - Configure and use bridges to other bug trackers.
+git-bug-bridge - List bridges to other bug trackers
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-bridge - Configure and use bridges to other bug trackers.
.SH DESCRIPTION
.PP
-Configure and use bridges to other bug trackers.
+List bridges to other bug trackers
.SH OPTIONS
@@ -24,4 +24,4 @@ Configure and use bridges to other bug trackers.
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP, \fBgit-bug-bridge-auth(1)\fP, \fBgit-bug-bridge-configure(1)\fP, \fBgit-bug-bridge-pull(1)\fP, \fBgit-bug-bridge-push(1)\fP, \fBgit-bug-bridge-rm(1)\fP
+\fBgit-bug(1)\fP, \fBgit-bug-bridge-auth(1)\fP, \fBgit-bug-bridge-new(1)\fP, \fBgit-bug-bridge-pull(1)\fP, \fBgit-bug-bridge-push(1)\fP, \fBgit-bug-bridge-rm(1)\fP
diff --git a/doc/man/git-bug-comment-edit.1 b/doc/man/git-bug-bug-comment-edit.1
index 03e6c1cd..5a3d3506 100644
--- a/doc/man/git-bug-comment-edit.1
+++ b/doc/man/git-bug-bug-comment-edit.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-comment-edit - Edit an existing comment on a bug.
+git-bug-bug-comment-edit - Edit an existing comment on a bug
.SH SYNOPSIS
.PP
-\fBgit-bug comment edit [COMMENT_ID] [flags]\fP
+\fBgit-bug bug comment edit [COMMENT_ID] [flags]\fP
.SH DESCRIPTION
.PP
-Edit an existing comment on a bug.
+Edit an existing comment on a bug
.SH OPTIONS
@@ -36,4 +36,4 @@ Edit an existing comment on a bug.
.SH SEE ALSO
.PP
-\fBgit-bug-comment(1)\fP
+\fBgit-bug-bug-comment(1)\fP
diff --git a/doc/man/git-bug-comment-add.1 b/doc/man/git-bug-bug-comment-new.1
index 41aec9bb..f2afc933 100644
--- a/doc/man/git-bug-comment-add.1
+++ b/doc/man/git-bug-bug-comment-new.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-comment-add - Add a new comment to a bug.
+git-bug-bug-comment-new - Add a new comment to a bug
.SH SYNOPSIS
.PP
-\fBgit-bug comment add [ID] [flags]\fP
+\fBgit-bug bug comment new [BUG_ID] [flags]\fP
.SH DESCRIPTION
.PP
-Add a new comment to a bug.
+Add a new comment to a bug
.SH OPTIONS
@@ -31,9 +31,9 @@ Add a new comment to a bug.
.PP
\fB-h\fP, \fB--help\fP[=false]
- help for add
+ help for new
.SH SEE ALSO
.PP
-\fBgit-bug-comment(1)\fP
+\fBgit-bug-bug-comment(1)\fP
diff --git a/doc/man/git-bug-comment.1 b/doc/man/git-bug-bug-comment.1
index 2939b641..162c4182 100644
--- a/doc/man/git-bug-comment.1
+++ b/doc/man/git-bug-bug-comment.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-comment - Display or add comments to a bug.
+git-bug-bug-comment - List a bug's comments
.SH SYNOPSIS
.PP
-\fBgit-bug comment [ID] [flags]\fP
+\fBgit-bug bug comment [BUG_ID] [flags]\fP
.SH DESCRIPTION
.PP
-Display or add comments to a bug.
+List a bug's comments
.SH OPTIONS
@@ -24,4 +24,4 @@ Display or add comments to a bug.
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP, \fBgit-bug-comment-add(1)\fP, \fBgit-bug-comment-edit(1)\fP
+\fBgit-bug-bug(1)\fP, \fBgit-bug-bug-comment-edit(1)\fP, \fBgit-bug-bug-comment-new(1)\fP
diff --git a/doc/man/git-bug-deselect.1 b/doc/man/git-bug-bug-deselect.1
index 9b630357..fd342245 100644
--- a/doc/man/git-bug-deselect.1
+++ b/doc/man/git-bug-bug-deselect.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-deselect - Clear the implicitly selected bug.
+git-bug-bug-deselect - Clear the implicitly selected bug
.SH SYNOPSIS
.PP
-\fBgit-bug deselect [flags]\fP
+\fBgit-bug bug deselect [flags]\fP
.SH DESCRIPTION
.PP
-Clear the implicitly selected bug.
+Clear the implicitly selected bug
.SH OPTIONS
@@ -39,4 +39,4 @@ git bug deselect
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP
+\fBgit-bug-bug(1)\fP
diff --git a/doc/man/git-bug-label-add.1 b/doc/man/git-bug-bug-label-new.1
index a8ef3375..aa2b0c65 100644
--- a/doc/man/git-bug-label-add.1
+++ b/doc/man/git-bug-bug-label-new.1
@@ -3,25 +3,25 @@
.SH NAME
.PP
-git-bug-label-add - Add a label to a bug.
+git-bug-bug-label-new - Add a label to a bug
.SH SYNOPSIS
.PP
-\fBgit-bug label add [ID] LABEL... [flags]\fP
+\fBgit-bug bug label new [BUG_ID] LABEL... [flags]\fP
.SH DESCRIPTION
.PP
-Add a label to a bug.
+Add a label to a bug
.SH OPTIONS
.PP
\fB-h\fP, \fB--help\fP[=false]
- help for add
+ help for new
.SH SEE ALSO
.PP
-\fBgit-bug-label(1)\fP
+\fBgit-bug-bug-label(1)\fP
diff --git a/doc/man/git-bug-label-rm.1 b/doc/man/git-bug-bug-label-rm.1
index 6b98196b..b204d61f 100644
--- a/doc/man/git-bug-label-rm.1
+++ b/doc/man/git-bug-bug-label-rm.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-label-rm - Remove a label from a bug.
+git-bug-bug-label-rm - Remove a label from a bug
.SH SYNOPSIS
.PP
-\fBgit-bug label rm [ID] LABEL... [flags]\fP
+\fBgit-bug bug label rm [BUG_ID] LABEL... [flags]\fP
.SH DESCRIPTION
.PP
-Remove a label from a bug.
+Remove a label from a bug
.SH OPTIONS
@@ -24,4 +24,4 @@ Remove a label from a bug.
.SH SEE ALSO
.PP
-\fBgit-bug-label(1)\fP
+\fBgit-bug-bug-label(1)\fP
diff --git a/doc/man/git-bug-bug-label.1 b/doc/man/git-bug-bug-label.1
new file mode 100644
index 00000000..a98c2285
--- /dev/null
+++ b/doc/man/git-bug-bug-label.1
@@ -0,0 +1,27 @@
+.nh
+.TH "GIT-BUG" "1" "Apr 2019" "Generated from git-bug's source code" ""
+
+.SH NAME
+.PP
+git-bug-bug-label - Display labels of a bug
+
+
+.SH SYNOPSIS
+.PP
+\fBgit-bug bug label [BUG_ID] [flags]\fP
+
+
+.SH DESCRIPTION
+.PP
+Display labels of a bug
+
+
+.SH OPTIONS
+.PP
+\fB-h\fP, \fB--help\fP[=false]
+ help for label
+
+
+.SH SEE ALSO
+.PP
+\fBgit-bug-bug(1)\fP, \fBgit-bug-bug-label-new(1)\fP, \fBgit-bug-bug-label-rm(1)\fP
diff --git a/doc/man/git-bug-add.1 b/doc/man/git-bug-bug-new.1
index 39c8fce4..91de2dcc 100644
--- a/doc/man/git-bug-add.1
+++ b/doc/man/git-bug-bug-new.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-add - Create a new bug.
+git-bug-bug-new - Create a new bug
.SH SYNOPSIS
.PP
-\fBgit-bug add [flags]\fP
+\fBgit-bug bug new [flags]\fP
.SH DESCRIPTION
.PP
-Create a new bug.
+Create a new bug
.SH OPTIONS
@@ -35,9 +35,9 @@ Create a new bug.
.PP
\fB-h\fP, \fB--help\fP[=false]
- help for add
+ help for new
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP
+\fBgit-bug-bug(1)\fP
diff --git a/doc/man/git-bug-rm.1 b/doc/man/git-bug-bug-rm.1
index 78156f37..ee7ea185 100644
--- a/doc/man/git-bug-rm.1
+++ b/doc/man/git-bug-bug-rm.1
@@ -3,12 +3,12 @@
.SH NAME
.PP
-git-bug-rm - Remove an existing bug.
+git-bug-bug-rm - Remove an existing bug
.SH SYNOPSIS
.PP
-\fBgit-bug rm ID [flags]\fP
+\fBgit-bug bug rm BUG_ID [flags]\fP
.SH DESCRIPTION
@@ -24,4 +24,4 @@ Remove an existing bug in the local repository. Note removing bugs that were imp
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP
+\fBgit-bug-bug(1)\fP
diff --git a/doc/man/git-bug-select.1 b/doc/man/git-bug-bug-select.1
index e94d80b1..d73cd606 100644
--- a/doc/man/git-bug-select.1
+++ b/doc/man/git-bug-bug-select.1
@@ -3,12 +3,12 @@
.SH NAME
.PP
-git-bug-select - Select a bug for implicit use in future commands.
+git-bug-bug-select - Select a bug for implicit use in future commands
.SH SYNOPSIS
.PP
-\fBgit-bug select ID [flags]\fP
+\fBgit-bug bug select BUG_ID [flags]\fP
.SH DESCRIPTION
@@ -47,4 +47,4 @@ git bug status
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP
+\fBgit-bug-bug(1)\fP
diff --git a/doc/man/git-bug-show.1 b/doc/man/git-bug-bug-show.1
index 6abf1b6f..aec83fa3 100644
--- a/doc/man/git-bug-show.1
+++ b/doc/man/git-bug-bug-show.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-show - Display the details of a bug.
+git-bug-bug-show - Display the details of a bug
.SH SYNOPSIS
.PP
-\fBgit-bug show [ID] [flags]\fP
+\fBgit-bug bug show [BUG_ID] [flags]\fP
.SH DESCRIPTION
.PP
-Display the details of a bug.
+Display the details of a bug
.SH OPTIONS
@@ -32,4 +32,4 @@ Display the details of a bug.
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP
+\fBgit-bug-bug(1)\fP
diff --git a/doc/man/git-bug-status-close.1 b/doc/man/git-bug-bug-status-close.1
index 3fcbdc35..edd9f666 100644
--- a/doc/man/git-bug-status-close.1
+++ b/doc/man/git-bug-bug-status-close.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-status-close - Mark a bug as closed.
+git-bug-bug-status-close - Mark a bug as closed
.SH SYNOPSIS
.PP
-\fBgit-bug status close [ID] [flags]\fP
+\fBgit-bug bug status close [BUG_ID] [flags]\fP
.SH DESCRIPTION
.PP
-Mark a bug as closed.
+Mark a bug as closed
.SH OPTIONS
@@ -24,4 +24,4 @@ Mark a bug as closed.
.SH SEE ALSO
.PP
-\fBgit-bug-status(1)\fP
+\fBgit-bug-bug-status(1)\fP
diff --git a/doc/man/git-bug-status-open.1 b/doc/man/git-bug-bug-status-open.1
index e13f11a3..4c001ada 100644
--- a/doc/man/git-bug-status-open.1
+++ b/doc/man/git-bug-bug-status-open.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-status-open - Mark a bug as open.
+git-bug-bug-status-open - Mark a bug as open
.SH SYNOPSIS
.PP
-\fBgit-bug status open [ID] [flags]\fP
+\fBgit-bug bug status open [BUG_ID] [flags]\fP
.SH DESCRIPTION
.PP
-Mark a bug as open.
+Mark a bug as open
.SH OPTIONS
@@ -24,4 +24,4 @@ Mark a bug as open.
.SH SEE ALSO
.PP
-\fBgit-bug-status(1)\fP
+\fBgit-bug-bug-status(1)\fP
diff --git a/doc/man/git-bug-status.1 b/doc/man/git-bug-bug-status.1
index e810b673..7abcd1a5 100644
--- a/doc/man/git-bug-status.1
+++ b/doc/man/git-bug-bug-status.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-status - Display or change a bug status.
+git-bug-bug-status - Display the status of a bug
.SH SYNOPSIS
.PP
-\fBgit-bug status [ID] [flags]\fP
+\fBgit-bug bug status [BUG_ID] [flags]\fP
.SH DESCRIPTION
.PP
-Display or change a bug status.
+Display the status of a bug
.SH OPTIONS
@@ -24,4 +24,4 @@ Display or change a bug status.
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP, \fBgit-bug-status-close(1)\fP, \fBgit-bug-status-open(1)\fP
+\fBgit-bug-bug(1)\fP, \fBgit-bug-bug-status-close(1)\fP, \fBgit-bug-bug-status-open(1)\fP
diff --git a/doc/man/git-bug-title-edit.1 b/doc/man/git-bug-bug-title-edit.1
index 5e0fa139..c5e33c7a 100644
--- a/doc/man/git-bug-title-edit.1
+++ b/doc/man/git-bug-bug-title-edit.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-title-edit - Edit a title of a bug.
+git-bug-bug-title-edit - Edit a title of a bug
.SH SYNOPSIS
.PP
-\fBgit-bug title edit [ID] [flags]\fP
+\fBgit-bug bug title edit [BUG_ID] [flags]\fP
.SH DESCRIPTION
.PP
-Edit a title of a bug.
+Edit a title of a bug
.SH OPTIONS
@@ -32,4 +32,4 @@ Edit a title of a bug.
.SH SEE ALSO
.PP
-\fBgit-bug-title(1)\fP
+\fBgit-bug-bug-title(1)\fP
diff --git a/doc/man/git-bug-title.1 b/doc/man/git-bug-bug-title.1
index 164c0257..94568035 100644
--- a/doc/man/git-bug-title.1
+++ b/doc/man/git-bug-bug-title.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-title - Display or change a title of a bug.
+git-bug-bug-title - Display the title of a bug
.SH SYNOPSIS
.PP
-\fBgit-bug title [ID] [flags]\fP
+\fBgit-bug bug title [BUG_ID] [flags]\fP
.SH DESCRIPTION
.PP
-Display or change a title of a bug.
+Display the title of a bug
.SH OPTIONS
@@ -24,4 +24,4 @@ Display or change a title of a bug.
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP, \fBgit-bug-title-edit(1)\fP
+\fBgit-bug-bug(1)\fP, \fBgit-bug-bug-title-edit(1)\fP
diff --git a/doc/man/git-bug-ls.1 b/doc/man/git-bug-bug.1
index e58177de..6ee62303 100644
--- a/doc/man/git-bug-ls.1
+++ b/doc/man/git-bug-bug.1
@@ -3,12 +3,12 @@
.SH NAME
.PP
-git-bug-ls - List bugs.
+git-bug-bug - List bugs
.SH SYNOPSIS
.PP
-\fBgit-bug ls [QUERY] [flags]\fP
+\fBgit-bug bug [QUERY] [flags]\fP
.SH DESCRIPTION
@@ -66,7 +66,7 @@ You can pass an additional query to filter and order the list. This query can be
.PP
\fB-h\fP, \fB--help\fP[=false]
- help for ls
+ help for bug
.SH EXAMPLE
@@ -75,16 +75,16 @@ You can pass an additional query to filter and order the list. This query can be
.nf
List open bugs sorted by last edition with a query:
-git bug ls status:open sort:edit-desc
+git bug status:open sort:edit-desc
List closed bugs sorted by creation with flags:
-git bug ls --status closed --by creation
+git bug --status closed --by creation
Do a full text search of all bugs:
-git bug ls "foo bar" baz
+git bug "foo bar" baz
Use queries, flags, and full text search:
-git bug ls status:open --by creation "foo bar" baz
+git bug status:open --by creation "foo bar" baz
.fi
@@ -93,4 +93,4 @@ git bug ls status:open --by creation "foo bar" baz
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP
+\fBgit-bug(1)\fP, \fBgit-bug-bug-comment(1)\fP, \fBgit-bug-bug-deselect(1)\fP, \fBgit-bug-bug-label(1)\fP, \fBgit-bug-bug-new(1)\fP, \fBgit-bug-bug-rm(1)\fP, \fBgit-bug-bug-select(1)\fP, \fBgit-bug-bug-show(1)\fP, \fBgit-bug-bug-status(1)\fP, \fBgit-bug-bug-title(1)\fP
diff --git a/doc/man/git-bug-label-ls.1 b/doc/man/git-bug-label-ls.1
deleted file mode 100644
index 67ee7dd1..00000000
--- a/doc/man/git-bug-label-ls.1
+++ /dev/null
@@ -1,30 +0,0 @@
-.nh
-.TH "GIT-BUG" "1" "Apr 2019" "Generated from git-bug's source code" ""
-
-.SH NAME
-.PP
-git-bug-label-ls - List valid labels.
-
-
-.SH SYNOPSIS
-.PP
-\fBgit-bug label ls [flags]\fP
-
-
-.SH DESCRIPTION
-.PP
-List valid labels.
-
-.PP
-Note: in the future, a proper label policy could be implemented where valid labels are defined in a configuration file. Until that, the default behavior is to return the list of labels already used.
-
-
-.SH OPTIONS
-.PP
-\fB-h\fP, \fB--help\fP[=false]
- help for ls
-
-
-.SH SEE ALSO
-.PP
-\fBgit-bug-label(1)\fP
diff --git a/doc/man/git-bug-label.1 b/doc/man/git-bug-label.1
index 69a5c217..9de7d2c0 100644
--- a/doc/man/git-bug-label.1
+++ b/doc/man/git-bug-label.1
@@ -3,17 +3,20 @@
.SH NAME
.PP
-git-bug-label - Display, add or remove labels to/from a bug.
+git-bug-label - List valid labels
.SH SYNOPSIS
.PP
-\fBgit-bug label [ID] [flags]\fP
+\fBgit-bug label [flags]\fP
.SH DESCRIPTION
.PP
-Display, add or remove labels to/from a bug.
+List valid labels.
+
+.PP
+Note: in the future, a proper label policy could be implemented where valid labels are defined in a configuration file. Until that, the default behavior is to return the list of labels already used.
.SH OPTIONS
@@ -24,4 +27,4 @@ Display, add or remove labels to/from a bug.
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP, \fBgit-bug-label-add(1)\fP, \fBgit-bug-label-ls(1)\fP, \fBgit-bug-label-rm(1)\fP
+\fBgit-bug(1)\fP
diff --git a/doc/man/git-bug-pull.1 b/doc/man/git-bug-pull.1
index f2536b30..62485429 100644
--- a/doc/man/git-bug-pull.1
+++ b/doc/man/git-bug-pull.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-pull - Pull bugs update from a git remote.
+git-bug-pull - Pull updates from a git remote
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-pull - Pull bugs update from a git remote.
.SH DESCRIPTION
.PP
-Pull bugs update from a git remote.
+Pull updates from a git remote
.SH OPTIONS
diff --git a/doc/man/git-bug-push.1 b/doc/man/git-bug-push.1
index 2be8d6e2..2f15aacb 100644
--- a/doc/man/git-bug-push.1
+++ b/doc/man/git-bug-push.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-push - Push bugs update to a git remote.
+git-bug-push - Push updates to a git remote
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-push - Push bugs update to a git remote.
.SH DESCRIPTION
.PP
-Push bugs update to a git remote.
+Push updates to a git remote
.SH OPTIONS
diff --git a/doc/man/git-bug-termui.1 b/doc/man/git-bug-termui.1
index ac09d2ed..7409c963 100644
--- a/doc/man/git-bug-termui.1
+++ b/doc/man/git-bug-termui.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-termui - Launch the terminal UI.
+git-bug-termui - Launch the terminal UI
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-termui - Launch the terminal UI.
.SH DESCRIPTION
.PP
-Launch the terminal UI.
+Launch the terminal UI
.SH OPTIONS
diff --git a/doc/man/git-bug-user-adopt.1 b/doc/man/git-bug-user-adopt.1
index ce4e9fe1..f7f2c895 100644
--- a/doc/man/git-bug-user-adopt.1
+++ b/doc/man/git-bug-user-adopt.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-user-adopt - Adopt an existing identity as your own.
+git-bug-user-adopt - Adopt an existing identity as your own
.SH SYNOPSIS
.PP
-\fBgit-bug user adopt USER-ID [flags]\fP
+\fBgit-bug user adopt USER_ID [flags]\fP
.SH DESCRIPTION
.PP
-Adopt an existing identity as your own.
+Adopt an existing identity as your own
.SH OPTIONS
diff --git a/doc/man/git-bug-user-ls.1 b/doc/man/git-bug-user-ls.1
deleted file mode 100644
index aff46335..00000000
--- a/doc/man/git-bug-user-ls.1
+++ /dev/null
@@ -1,31 +0,0 @@
-.nh
-.TH "GIT-BUG" "1" "Apr 2019" "Generated from git-bug's source code" ""
-
-.SH NAME
-.PP
-git-bug-user-ls - List identities.
-
-
-.SH SYNOPSIS
-.PP
-\fBgit-bug user ls [flags]\fP
-
-
-.SH DESCRIPTION
-.PP
-List identities.
-
-
-.SH OPTIONS
-.PP
-\fB-f\fP, \fB--format\fP="default"
- Select the output formatting style. Valid values are [default,json]
-
-.PP
-\fB-h\fP, \fB--help\fP[=false]
- help for ls
-
-
-.SH SEE ALSO
-.PP
-\fBgit-bug-user(1)\fP
diff --git a/doc/man/git-bug-user-create.1 b/doc/man/git-bug-user-new.1
index 66c7db58..cdb6f91f 100644
--- a/doc/man/git-bug-user-create.1
+++ b/doc/man/git-bug-user-new.1
@@ -3,17 +3,17 @@
.SH NAME
.PP
-git-bug-user-create - Create a new identity.
+git-bug-user-new - Create a new identity
.SH SYNOPSIS
.PP
-\fBgit-bug user create [flags]\fP
+\fBgit-bug user new [flags]\fP
.SH DESCRIPTION
.PP
-Create a new identity.
+Create a new identity
.SH OPTIONS
@@ -27,7 +27,7 @@ Create a new identity.
.PP
\fB-h\fP, \fB--help\fP[=false]
- help for create
+ help for new
.PP
\fB-n\fP, \fB--name\fP=""
diff --git a/doc/man/git-bug-user-user.1 b/doc/man/git-bug-user-user.1
new file mode 100644
index 00000000..f4bf83d8
--- /dev/null
+++ b/doc/man/git-bug-user-user.1
@@ -0,0 +1,31 @@
+.nh
+.TH "GIT-BUG" "1" "Apr 2019" "Generated from git-bug's source code" ""
+
+.SH NAME
+.PP
+git-bug-user-user - Display a user identity
+
+
+.SH SYNOPSIS
+.PP
+\fBgit-bug user user show [USER_ID] [flags]\fP
+
+
+.SH DESCRIPTION
+.PP
+Display a user identity
+
+
+.SH OPTIONS
+.PP
+\fB-f\fP, \fB--field\fP=""
+ Select field to display. Valid values are [email,humanId,id,lastModification,lastModificationLamports,login,metadata,name]
+
+.PP
+\fB-h\fP, \fB--help\fP[=false]
+ help for user
+
+
+.SH SEE ALSO
+.PP
+\fBgit-bug-user(1)\fP
diff --git a/doc/man/git-bug-user.1 b/doc/man/git-bug-user.1
index 2a613ae2..276d0e43 100644
--- a/doc/man/git-bug-user.1
+++ b/doc/man/git-bug-user.1
@@ -3,23 +3,23 @@
.SH NAME
.PP
-git-bug-user - Display or change the user identity.
+git-bug-user - List identities
.SH SYNOPSIS
.PP
-\fBgit-bug user [USER-ID] [flags]\fP
+\fBgit-bug user [flags]\fP
.SH DESCRIPTION
.PP
-Display or change the user identity.
+List identities
.SH OPTIONS
.PP
-\fB-f\fP, \fB--field\fP=""
- Select field to display. Valid values are [email,humanId,id,lastModification,lastModificationLamports,login,metadata,name]
+\fB-f\fP, \fB--format\fP="default"
+ Select the output formatting style. Valid values are [default,json]
.PP
\fB-h\fP, \fB--help\fP[=false]
@@ -28,4 +28,4 @@ Display or change the user identity.
.SH SEE ALSO
.PP
-\fBgit-bug(1)\fP, \fBgit-bug-user-adopt(1)\fP, \fBgit-bug-user-create(1)\fP, \fBgit-bug-user-ls(1)\fP
+\fBgit-bug(1)\fP, \fBgit-bug-user-adopt(1)\fP, \fBgit-bug-user-new(1)\fP, \fBgit-bug-user-user(1)\fP
diff --git a/doc/man/git-bug-version.1 b/doc/man/git-bug-version.1
index 311f1d2a..6b688221 100644
--- a/doc/man/git-bug-version.1
+++ b/doc/man/git-bug-version.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-version - Show git-bug version information.
+git-bug-version - Show git-bug version information
.SH SYNOPSIS
@@ -13,7 +13,7 @@ git-bug-version - Show git-bug version information.
.SH DESCRIPTION
.PP
-Show git-bug version information.
+Show git-bug version information
.SH OPTIONS
diff --git a/doc/man/git-bug-webui.1 b/doc/man/git-bug-webui.1
index 0fcfeac2..f6cdcfde 100644
--- a/doc/man/git-bug-webui.1
+++ b/doc/man/git-bug-webui.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug-webui - Launch the web UI.
+git-bug-webui - Launch the web UI
.SH SYNOPSIS
diff --git a/doc/man/git-bug.1 b/doc/man/git-bug.1
index b982c7f4..8b66d312 100644
--- a/doc/man/git-bug.1
+++ b/doc/man/git-bug.1
@@ -3,7 +3,7 @@
.SH NAME
.PP
-git-bug - A bug tracker embedded in Git.
+git-bug - A bug tracker embedded in Git
.SH SYNOPSIS
@@ -29,4 +29,4 @@ the same git remote you are already using to collaborate with other people.
.SH SEE ALSO
.PP
-\fBgit-bug-add(1)\fP, \fBgit-bug-bridge(1)\fP, \fBgit-bug-commands(1)\fP, \fBgit-bug-comment(1)\fP, \fBgit-bug-deselect(1)\fP, \fBgit-bug-label(1)\fP, \fBgit-bug-ls(1)\fP, \fBgit-bug-pull(1)\fP, \fBgit-bug-push(1)\fP, \fBgit-bug-rm(1)\fP, \fBgit-bug-select(1)\fP, \fBgit-bug-show(1)\fP, \fBgit-bug-status(1)\fP, \fBgit-bug-termui(1)\fP, \fBgit-bug-title(1)\fP, \fBgit-bug-user(1)\fP, \fBgit-bug-version(1)\fP, \fBgit-bug-webui(1)\fP
+\fBgit-bug-bridge(1)\fP, \fBgit-bug-bug(1)\fP, \fBgit-bug-commands(1)\fP, \fBgit-bug-label(1)\fP, \fBgit-bug-pull(1)\fP, \fBgit-bug-push(1)\fP, \fBgit-bug-termui(1)\fP, \fBgit-bug-user(1)\fP, \fBgit-bug-version(1)\fP, \fBgit-bug-webui(1)\fP
diff --git a/doc/md/git-bug.md b/doc/md/git-bug.md
index c47f8484..b311aff5 100644
--- a/doc/md/git-bug.md
+++ b/doc/md/git-bug.md
@@ -1,6 +1,6 @@
## git-bug
-A bug tracker embedded in Git.
+A bug tracker embedded in Git
### Synopsis
@@ -24,22 +24,14 @@ git-bug [flags]
### SEE ALSO
-* [git-bug add](git-bug_add.md) - Create a new bug.
-* [git-bug bridge](git-bug_bridge.md) - Configure and use bridges to other bug trackers.
+* [git-bug bridge](git-bug_bridge.md) - List bridges to other bug trackers
+* [git-bug bug](git-bug_bug.md) - List bugs
* [git-bug commands](git-bug_commands.md) - Display available commands.
-* [git-bug comment](git-bug_comment.md) - Display or add comments to a bug.
-* [git-bug deselect](git-bug_deselect.md) - Clear the implicitly selected bug.
-* [git-bug label](git-bug_label.md) - Display, add or remove labels to/from a bug.
-* [git-bug ls](git-bug_ls.md) - List bugs.
-* [git-bug pull](git-bug_pull.md) - Pull bugs update from a git remote.
-* [git-bug push](git-bug_push.md) - Push bugs update to a git remote.
-* [git-bug rm](git-bug_rm.md) - Remove an existing bug.
-* [git-bug select](git-bug_select.md) - Select a bug for implicit use in future commands.
-* [git-bug show](git-bug_show.md) - Display the details of a bug.
-* [git-bug status](git-bug_status.md) - Display or change a bug status.
-* [git-bug termui](git-bug_termui.md) - Launch the terminal UI.
-* [git-bug title](git-bug_title.md) - Display or change a title of a bug.
-* [git-bug user](git-bug_user.md) - Display or change the user identity.
-* [git-bug version](git-bug_version.md) - Show git-bug version information.
-* [git-bug webui](git-bug_webui.md) - Launch the web UI.
+* [git-bug label](git-bug_label.md) - List valid labels
+* [git-bug pull](git-bug_pull.md) - Pull updates from a git remote
+* [git-bug push](git-bug_push.md) - Push updates to a git remote
+* [git-bug termui](git-bug_termui.md) - Launch the terminal UI
+* [git-bug user](git-bug_user.md) - List identities
+* [git-bug version](git-bug_version.md) - Show git-bug version information
+* [git-bug webui](git-bug_webui.md) - Launch the web UI
diff --git a/doc/md/git-bug_bridge.md b/doc/md/git-bug_bridge.md
index e8b6e382..c3e239e2 100644
--- a/doc/md/git-bug_bridge.md
+++ b/doc/md/git-bug_bridge.md
@@ -1,6 +1,6 @@
## git-bug bridge
-Configure and use bridges to other bug trackers.
+List bridges to other bug trackers
```
git-bug bridge [flags]
@@ -14,10 +14,10 @@ git-bug bridge [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
-* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials.
-* [git-bug bridge configure](git-bug_bridge_configure.md) - Configure a new bridge.
-* [git-bug bridge pull](git-bug_bridge_pull.md) - Pull updates.
-* [git-bug bridge push](git-bug_bridge_push.md) - Push updates.
-* [git-bug bridge rm](git-bug_bridge_rm.md) - Delete a configured bridge.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
+* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials
+* [git-bug bridge new](git-bug_bridge_new.md) - Configure a new bridge
+* [git-bug bridge pull](git-bug_bridge_pull.md) - Pull updates from a remote bug tracker
+* [git-bug bridge push](git-bug_bridge_push.md) - Push updates to remote bug tracker
+* [git-bug bridge rm](git-bug_bridge_rm.md) - Delete a configured bridge
diff --git a/doc/md/git-bug_bridge_auth.md b/doc/md/git-bug_bridge_auth.md
index bcaf6028..e7404822 100644
--- a/doc/md/git-bug_bridge_auth.md
+++ b/doc/md/git-bug_bridge_auth.md
@@ -1,6 +1,6 @@
## git-bug bridge auth
-List all known bridge authentication credentials.
+List all known bridge authentication credentials
```
git-bug bridge auth [flags]
@@ -14,8 +14,8 @@ git-bug bridge auth [flags]
### SEE ALSO
-* [git-bug bridge](git-bug_bridge.md) - Configure and use bridges to other bug trackers.
+* [git-bug bridge](git-bug_bridge.md) - List bridges to other bug trackers
* [git-bug bridge auth add-token](git-bug_bridge_auth_add-token.md) - Store a new token
-* [git-bug bridge auth rm](git-bug_bridge_auth_rm.md) - Remove a credential.
-* [git-bug bridge auth show](git-bug_bridge_auth_show.md) - Display an authentication credential.
+* [git-bug bridge auth rm](git-bug_bridge_auth_rm.md) - Remove a credential
+* [git-bug bridge auth show](git-bug_bridge_auth_show.md) - Display an authentication credential
diff --git a/doc/md/git-bug_bridge_auth_add-token.md b/doc/md/git-bug_bridge_auth_add-token.md
index faafaf61..3fb33036 100644
--- a/doc/md/git-bug_bridge_auth_add-token.md
+++ b/doc/md/git-bug_bridge_auth_add-token.md
@@ -17,5 +17,5 @@ git-bug bridge auth add-token [TOKEN] [flags]
### SEE ALSO
-* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials.
+* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials
diff --git a/doc/md/git-bug_bridge_auth_rm.md b/doc/md/git-bug_bridge_auth_rm.md
index d890054e..8ae3ad52 100644
--- a/doc/md/git-bug_bridge_auth_rm.md
+++ b/doc/md/git-bug_bridge_auth_rm.md
@@ -1,9 +1,9 @@
## git-bug bridge auth rm
-Remove a credential.
+Remove a credential
```
-git-bug bridge auth rm ID [flags]
+git-bug bridge auth rm BRIDGE_ID [flags]
```
### Options
@@ -14,5 +14,5 @@ git-bug bridge auth rm ID [flags]
### SEE ALSO
-* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials.
+* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials
diff --git a/doc/md/git-bug_bridge_auth_show.md b/doc/md/git-bug_bridge_auth_show.md
index 18d468db..f73bb876 100644
--- a/doc/md/git-bug_bridge_auth_show.md
+++ b/doc/md/git-bug_bridge_auth_show.md
@@ -1,6 +1,6 @@
## git-bug bridge auth show
-Display an authentication credential.
+Display an authentication credential
```
git-bug bridge auth show [flags]
@@ -14,5 +14,5 @@ git-bug bridge auth show [flags]
### SEE ALSO
-* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials.
+* [git-bug bridge auth](git-bug_bridge_auth.md) - List all known bridge authentication credentials
diff --git a/doc/md/git-bug_bridge_configure.md b/doc/md/git-bug_bridge_new.md
index e3b4c6bd..81bffd49 100644
--- a/doc/md/git-bug_bridge_configure.md
+++ b/doc/md/git-bug_bridge_new.md
@@ -1,13 +1,13 @@
-## git-bug bridge configure
+## git-bug bridge new
-Configure a new bridge.
+Configure a new bridge
### Synopsis
Configure a new bridge by passing flags or/and using interactive terminal prompts. You can avoid all the terminal prompts by passing all the necessary flags to configure your bridge.
```
-git-bug bridge configure [flags]
+git-bug bridge new [flags]
```
### Examples
@@ -47,7 +47,7 @@ Enter token: 87cf5c03b64029f18ea5f9ca5679daa08ccbd700
Successfully configured bridge: default
# For GitHub
-git bug bridge configure \
+git bug bridge new \
--name=default \
--target=github \
--owner=$(OWNER) \
@@ -55,13 +55,13 @@ git bug bridge configure \
--token=$(TOKEN)
# For Launchpad
-git bug bridge configure \
+git bug bridge new \
--name=default \
--target=launchpad-preview \
--url=https://bugs.launchpad.net/ubuntu/
# For Gitlab
-git bug bridge configure \
+git bug bridge new \
--name=default \
--target=github \
--url=https://github.com/michaelmure/git-bug \
@@ -82,10 +82,10 @@ git bug bridge configure \
-o, --owner string The owner of the remote repository
-p, --project string The name of the remote repository
--non-interactive Do not ask for user input
- -h, --help help for configure
+ -h, --help help for new
```
### SEE ALSO
-* [git-bug bridge](git-bug_bridge.md) - Configure and use bridges to other bug trackers.
+* [git-bug bridge](git-bug_bridge.md) - List bridges to other bug trackers
diff --git a/doc/md/git-bug_bridge_pull.md b/doc/md/git-bug_bridge_pull.md
index b1ce2169..0975010a 100644
--- a/doc/md/git-bug_bridge_pull.md
+++ b/doc/md/git-bug_bridge_pull.md
@@ -1,6 +1,6 @@
## git-bug bridge pull
-Pull updates.
+Pull updates from a remote bug tracker
```
git-bug bridge pull [NAME] [flags]
@@ -16,5 +16,5 @@ git-bug bridge pull [NAME] [flags]
### SEE ALSO
-* [git-bug bridge](git-bug_bridge.md) - Configure and use bridges to other bug trackers.
+* [git-bug bridge](git-bug_bridge.md) - List bridges to other bug trackers
diff --git a/doc/md/git-bug_bridge_push.md b/doc/md/git-bug_bridge_push.md
index a532a26d..c7e1a86d 100644
--- a/doc/md/git-bug_bridge_push.md
+++ b/doc/md/git-bug_bridge_push.md
@@ -1,6 +1,6 @@
## git-bug bridge push
-Push updates.
+Push updates to remote bug tracker
```
git-bug bridge push [NAME] [flags]
@@ -14,5 +14,5 @@ git-bug bridge push [NAME] [flags]
### SEE ALSO
-* [git-bug bridge](git-bug_bridge.md) - Configure and use bridges to other bug trackers.
+* [git-bug bridge](git-bug_bridge.md) - List bridges to other bug trackers
diff --git a/doc/md/git-bug_bridge_rm.md b/doc/md/git-bug_bridge_rm.md
index 6d8ff67c..2b3baf71 100644
--- a/doc/md/git-bug_bridge_rm.md
+++ b/doc/md/git-bug_bridge_rm.md
@@ -1,6 +1,6 @@
## git-bug bridge rm
-Delete a configured bridge.
+Delete a configured bridge
```
git-bug bridge rm NAME [flags]
@@ -14,5 +14,5 @@ git-bug bridge rm NAME [flags]
### SEE ALSO
-* [git-bug bridge](git-bug_bridge.md) - Configure and use bridges to other bug trackers.
+* [git-bug bridge](git-bug_bridge.md) - List bridges to other bug trackers
diff --git a/doc/md/git-bug_ls.md b/doc/md/git-bug_bug.md
index 5aec0fbc..c040cd16 100644
--- a/doc/md/git-bug_ls.md
+++ b/doc/md/git-bug_bug.md
@@ -1,6 +1,6 @@
-## git-bug ls
+## git-bug bug
-List bugs.
+List bugs
### Synopsis
@@ -9,23 +9,23 @@ Display a summary of each bugs.
You can pass an additional query to filter and order the list. This query can be expressed either with a simple query language, flags, a natural language full text search, or a combination of the aforementioned.
```
-git-bug ls [QUERY] [flags]
+git-bug bug [QUERY] [flags]
```
### Examples
```
List open bugs sorted by last edition with a query:
-git bug ls status:open sort:edit-desc
+git bug status:open sort:edit-desc
List closed bugs sorted by creation with flags:
-git bug ls --status closed --by creation
+git bug --status closed --by creation
Do a full text search of all bugs:
-git bug ls "foo bar" baz
+git bug "foo bar" baz
Use queries, flags, and full text search:
-git bug ls status:open --by creation "foo bar" baz
+git bug status:open --by creation "foo bar" baz
```
@@ -43,10 +43,19 @@ git bug ls status:open --by creation "foo bar" baz
-b, --by string Sort the results by a characteristic. Valid values are [id,creation,edit] (default "creation")
-d, --direction string Select the sorting direction. Valid values are [asc,desc] (default "asc")
-f, --format string Select the output formatting style. Valid values are [default,plain,compact,id,json,org-mode] (default "default")
- -h, --help help for ls
+ -h, --help help for bug
```
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
+* [git-bug bug comment](git-bug_bug_comment.md) - List a bug's comments
+* [git-bug bug deselect](git-bug_bug_deselect.md) - Clear the implicitly selected bug
+* [git-bug bug label](git-bug_bug_label.md) - Display labels of a bug
+* [git-bug bug new](git-bug_bug_new.md) - Create a new bug
+* [git-bug bug rm](git-bug_bug_rm.md) - Remove an existing bug
+* [git-bug bug select](git-bug_bug_select.md) - Select a bug for implicit use in future commands
+* [git-bug bug show](git-bug_bug_show.md) - Display the details of a bug
+* [git-bug bug status](git-bug_bug_status.md) - Display the status of a bug
+* [git-bug bug title](git-bug_bug_title.md) - Display the title of a bug
diff --git a/doc/md/git-bug_bug_comment.md b/doc/md/git-bug_bug_comment.md
new file mode 100644
index 00000000..6d56a873
--- /dev/null
+++ b/doc/md/git-bug_bug_comment.md
@@ -0,0 +1,20 @@
+## git-bug bug comment
+
+List a bug's comments
+
+```
+git-bug bug comment [BUG_ID] [flags]
+```
+
+### Options
+
+```
+ -h, --help help for comment
+```
+
+### SEE ALSO
+
+* [git-bug bug](git-bug_bug.md) - List bugs
+* [git-bug bug comment edit](git-bug_bug_comment_edit.md) - Edit an existing comment on a bug
+* [git-bug bug comment new](git-bug_bug_comment_new.md) - Add a new comment to a bug
+
diff --git a/doc/md/git-bug_comment_edit.md b/doc/md/git-bug_bug_comment_edit.md
index 1a53b439..86a0a4e6 100644
--- a/doc/md/git-bug_comment_edit.md
+++ b/doc/md/git-bug_bug_comment_edit.md
@@ -1,9 +1,9 @@
-## git-bug comment edit
+## git-bug bug comment edit
-Edit an existing comment on a bug.
+Edit an existing comment on a bug
```
-git-bug comment edit [COMMENT_ID] [flags]
+git-bug bug comment edit [COMMENT_ID] [flags]
```
### Options
@@ -17,5 +17,5 @@ git-bug comment edit [COMMENT_ID] [flags]
### SEE ALSO
-* [git-bug comment](git-bug_comment.md) - Display or add comments to a bug.
+* [git-bug bug comment](git-bug_bug_comment.md) - List a bug's comments
diff --git a/doc/md/git-bug_comment_add.md b/doc/md/git-bug_bug_comment_new.md
index 5a199aba..b1ba697b 100644
--- a/doc/md/git-bug_comment_add.md
+++ b/doc/md/git-bug_bug_comment_new.md
@@ -1,9 +1,9 @@
-## git-bug comment add
+## git-bug bug comment new
-Add a new comment to a bug.
+Add a new comment to a bug
```
-git-bug comment add [ID] [flags]
+git-bug bug comment new [BUG_ID] [flags]
```
### Options
@@ -12,10 +12,10 @@ git-bug comment add [ID] [flags]
-F, --file string Take the message from the given file. Use - to read the message from the standard input
-m, --message string Provide the new message from the command line
--non-interactive Do not ask for user input
- -h, --help help for add
+ -h, --help help for new
```
### SEE ALSO
-* [git-bug comment](git-bug_comment.md) - Display or add comments to a bug.
+* [git-bug bug comment](git-bug_bug_comment.md) - List a bug's comments
diff --git a/doc/md/git-bug_deselect.md b/doc/md/git-bug_bug_deselect.md
index 51ce5dda..d4136068 100644
--- a/doc/md/git-bug_deselect.md
+++ b/doc/md/git-bug_bug_deselect.md
@@ -1,9 +1,9 @@
-## git-bug deselect
+## git-bug bug deselect
-Clear the implicitly selected bug.
+Clear the implicitly selected bug
```
-git-bug deselect [flags]
+git-bug bug deselect [flags]
```
### Examples
@@ -24,5 +24,5 @@ git bug deselect
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug bug](git-bug_bug.md) - List bugs
diff --git a/doc/md/git-bug_bug_label.md b/doc/md/git-bug_bug_label.md
new file mode 100644
index 00000000..ac5fb985
--- /dev/null
+++ b/doc/md/git-bug_bug_label.md
@@ -0,0 +1,20 @@
+## git-bug bug label
+
+Display labels of a bug
+
+```
+git-bug bug label [BUG_ID] [flags]
+```
+
+### Options
+
+```
+ -h, --help help for label
+```
+
+### SEE ALSO
+
+* [git-bug bug](git-bug_bug.md) - List bugs
+* [git-bug bug label new](git-bug_bug_label_new.md) - Add a label to a bug
+* [git-bug bug label rm](git-bug_bug_label_rm.md) - Remove a label from a bug
+
diff --git a/doc/md/git-bug_bug_label_new.md b/doc/md/git-bug_bug_label_new.md
new file mode 100644
index 00000000..ada978dc
--- /dev/null
+++ b/doc/md/git-bug_bug_label_new.md
@@ -0,0 +1,18 @@
+## git-bug bug label new
+
+Add a label to a bug
+
+```
+git-bug bug label new [BUG_ID] LABEL... [flags]
+```
+
+### Options
+
+```
+ -h, --help help for new
+```
+
+### SEE ALSO
+
+* [git-bug bug label](git-bug_bug_label.md) - Display labels of a bug
+
diff --git a/doc/md/git-bug_bug_label_rm.md b/doc/md/git-bug_bug_label_rm.md
new file mode 100644
index 00000000..7899b1be
--- /dev/null
+++ b/doc/md/git-bug_bug_label_rm.md
@@ -0,0 +1,18 @@
+## git-bug bug label rm
+
+Remove a label from a bug
+
+```
+git-bug bug label rm [BUG_ID] LABEL... [flags]
+```
+
+### Options
+
+```
+ -h, --help help for rm
+```
+
+### SEE ALSO
+
+* [git-bug bug label](git-bug_bug_label.md) - Display labels of a bug
+
diff --git a/doc/md/git-bug_add.md b/doc/md/git-bug_bug_new.md
index 5e748610..4dacc5fd 100644
--- a/doc/md/git-bug_add.md
+++ b/doc/md/git-bug_bug_new.md
@@ -1,9 +1,9 @@
-## git-bug add
+## git-bug bug new
-Create a new bug.
+Create a new bug
```
-git-bug add [flags]
+git-bug bug new [flags]
```
### Options
@@ -13,10 +13,10 @@ git-bug add [flags]
-m, --message string Provide a message to describe the issue
-F, --file string Take the message from the given file. Use - to read the message from the standard input
--non-interactive Do not ask for user input
- -h, --help help for add
+ -h, --help help for new
```
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug bug](git-bug_bug.md) - List bugs
diff --git a/doc/md/git-bug_rm.md b/doc/md/git-bug_bug_rm.md
index 3b77ce1c..2e77c6ec 100644
--- a/doc/md/git-bug_rm.md
+++ b/doc/md/git-bug_bug_rm.md
@@ -1,13 +1,13 @@
-## git-bug rm
+## git-bug bug rm
-Remove an existing bug.
+Remove an existing bug
### Synopsis
Remove an existing bug in the local repository. Note removing bugs that were imported from bridges will not remove the bug on the remote, and will only remove the local copy of the bug.
```
-git-bug rm ID [flags]
+git-bug bug rm BUG_ID [flags]
```
### Options
@@ -18,5 +18,5 @@ git-bug rm ID [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug bug](git-bug_bug.md) - List bugs
diff --git a/doc/md/git-bug_select.md b/doc/md/git-bug_bug_select.md
index b8a71120..d529c544 100644
--- a/doc/md/git-bug_select.md
+++ b/doc/md/git-bug_bug_select.md
@@ -1,6 +1,6 @@
-## git-bug select
+## git-bug bug select
-Select a bug for implicit use in future commands.
+Select a bug for implicit use in future commands
### Synopsis
@@ -15,7 +15,7 @@ The complementary command is "git bug deselect" performing the opposite operatio
```
-git-bug select ID [flags]
+git-bug bug select BUG_ID [flags]
```
### Examples
@@ -35,5 +35,5 @@ git bug status
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug bug](git-bug_bug.md) - List bugs
diff --git a/doc/md/git-bug_show.md b/doc/md/git-bug_bug_show.md
index c284fc71..1c7b762f 100644
--- a/doc/md/git-bug_show.md
+++ b/doc/md/git-bug_bug_show.md
@@ -1,9 +1,9 @@
-## git-bug show
+## git-bug bug show
-Display the details of a bug.
+Display the details of a bug
```
-git-bug show [ID] [flags]
+git-bug bug show [BUG_ID] [flags]
```
### Options
@@ -16,5 +16,5 @@ git-bug show [ID] [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug bug](git-bug_bug.md) - List bugs
diff --git a/doc/md/git-bug_bug_status.md b/doc/md/git-bug_bug_status.md
new file mode 100644
index 00000000..6e71e458
--- /dev/null
+++ b/doc/md/git-bug_bug_status.md
@@ -0,0 +1,20 @@
+## git-bug bug status
+
+Display the status of a bug
+
+```
+git-bug bug status [BUG_ID] [flags]
+```
+
+### Options
+
+```
+ -h, --help help for status
+```
+
+### SEE ALSO
+
+* [git-bug bug](git-bug_bug.md) - List bugs
+* [git-bug bug status close](git-bug_bug_status_close.md) - Mark a bug as closed
+* [git-bug bug status open](git-bug_bug_status_open.md) - Mark a bug as open
+
diff --git a/doc/md/git-bug_bug_status_close.md b/doc/md/git-bug_bug_status_close.md
new file mode 100644
index 00000000..f63fabb5
--- /dev/null
+++ b/doc/md/git-bug_bug_status_close.md
@@ -0,0 +1,18 @@
+## git-bug bug status close
+
+Mark a bug as closed
+
+```
+git-bug bug status close [BUG_ID] [flags]
+```
+
+### Options
+
+```
+ -h, --help help for close
+```
+
+### SEE ALSO
+
+* [git-bug bug status](git-bug_bug_status.md) - Display the status of a bug
+
diff --git a/doc/md/git-bug_bug_status_open.md b/doc/md/git-bug_bug_status_open.md
new file mode 100644
index 00000000..0899de30
--- /dev/null
+++ b/doc/md/git-bug_bug_status_open.md
@@ -0,0 +1,18 @@
+## git-bug bug status open
+
+Mark a bug as open
+
+```
+git-bug bug status open [BUG_ID] [flags]
+```
+
+### Options
+
+```
+ -h, --help help for open
+```
+
+### SEE ALSO
+
+* [git-bug bug status](git-bug_bug_status.md) - Display the status of a bug
+
diff --git a/doc/md/git-bug_bug_title.md b/doc/md/git-bug_bug_title.md
new file mode 100644
index 00000000..2650487e
--- /dev/null
+++ b/doc/md/git-bug_bug_title.md
@@ -0,0 +1,19 @@
+## git-bug bug title
+
+Display the title of a bug
+
+```
+git-bug bug title [BUG_ID] [flags]
+```
+
+### Options
+
+```
+ -h, --help help for title
+```
+
+### SEE ALSO
+
+* [git-bug bug](git-bug_bug.md) - List bugs
+* [git-bug bug title edit](git-bug_bug_title_edit.md) - Edit a title of a bug
+
diff --git a/doc/md/git-bug_title_edit.md b/doc/md/git-bug_bug_title_edit.md
index ae060680..0a26609d 100644
--- a/doc/md/git-bug_title_edit.md
+++ b/doc/md/git-bug_bug_title_edit.md
@@ -1,9 +1,9 @@
-## git-bug title edit
+## git-bug bug title edit
-Edit a title of a bug.
+Edit a title of a bug
```
-git-bug title edit [ID] [flags]
+git-bug bug title edit [BUG_ID] [flags]
```
### Options
@@ -16,5 +16,5 @@ git-bug title edit [ID] [flags]
### SEE ALSO
-* [git-bug title](git-bug_title.md) - Display or change a title of a bug.
+* [git-bug bug title](git-bug_bug_title.md) - Display the title of a bug
diff --git a/doc/md/git-bug_commands.md b/doc/md/git-bug_commands.md
index db1054f8..bce599dd 100644
--- a/doc/md/git-bug_commands.md
+++ b/doc/md/git-bug_commands.md
@@ -15,5 +15,5 @@ git-bug commands [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
diff --git a/doc/md/git-bug_comment.md b/doc/md/git-bug_comment.md
deleted file mode 100644
index 48050a97..00000000
--- a/doc/md/git-bug_comment.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## git-bug comment
-
-Display or add comments to a bug.
-
-```
-git-bug comment [ID] [flags]
-```
-
-### Options
-
-```
- -h, --help help for comment
-```
-
-### SEE ALSO
-
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
-* [git-bug comment add](git-bug_comment_add.md) - Add a new comment to a bug.
-* [git-bug comment edit](git-bug_comment_edit.md) - Edit an existing comment on a bug.
-
diff --git a/doc/md/git-bug_label.md b/doc/md/git-bug_label.md
index caeebe89..969edc16 100644
--- a/doc/md/git-bug_label.md
+++ b/doc/md/git-bug_label.md
@@ -1,9 +1,15 @@
## git-bug label
-Display, add or remove labels to/from a bug.
+List valid labels
+
+### Synopsis
+
+List valid labels.
+
+Note: in the future, a proper label policy could be implemented where valid labels are defined in a configuration file. Until that, the default behavior is to return the list of labels already used.
```
-git-bug label [ID] [flags]
+git-bug label [flags]
```
### Options
@@ -14,8 +20,5 @@ git-bug label [ID] [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
-* [git-bug label add](git-bug_label_add.md) - Add a label to a bug.
-* [git-bug label ls](git-bug_label_ls.md) - List valid labels.
-* [git-bug label rm](git-bug_label_rm.md) - Remove a label from a bug.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
diff --git a/doc/md/git-bug_label_add.md b/doc/md/git-bug_label_add.md
deleted file mode 100644
index c90b45d3..00000000
--- a/doc/md/git-bug_label_add.md
+++ /dev/null
@@ -1,18 +0,0 @@
-## git-bug label add
-
-Add a label to a bug.
-
-```
-git-bug label add [ID] LABEL... [flags]
-```
-
-### Options
-
-```
- -h, --help help for add
-```
-
-### SEE ALSO
-
-* [git-bug label](git-bug_label.md) - Display, add or remove labels to/from a bug.
-
diff --git a/doc/md/git-bug_label_ls.md b/doc/md/git-bug_label_ls.md
deleted file mode 100644
index cda6ebba..00000000
--- a/doc/md/git-bug_label_ls.md
+++ /dev/null
@@ -1,24 +0,0 @@
-## git-bug label ls
-
-List valid labels.
-
-### Synopsis
-
-List valid labels.
-
-Note: in the future, a proper label policy could be implemented where valid labels are defined in a configuration file. Until that, the default behavior is to return the list of labels already used.
-
-```
-git-bug label ls [flags]
-```
-
-### Options
-
-```
- -h, --help help for ls
-```
-
-### SEE ALSO
-
-* [git-bug label](git-bug_label.md) - Display, add or remove labels to/from a bug.
-
diff --git a/doc/md/git-bug_label_rm.md b/doc/md/git-bug_label_rm.md
deleted file mode 100644
index 15982d0e..00000000
--- a/doc/md/git-bug_label_rm.md
+++ /dev/null
@@ -1,18 +0,0 @@
-## git-bug label rm
-
-Remove a label from a bug.
-
-```
-git-bug label rm [ID] LABEL... [flags]
-```
-
-### Options
-
-```
- -h, --help help for rm
-```
-
-### SEE ALSO
-
-* [git-bug label](git-bug_label.md) - Display, add or remove labels to/from a bug.
-
diff --git a/doc/md/git-bug_pull.md b/doc/md/git-bug_pull.md
index 5c1d51b6..28f90959 100644
--- a/doc/md/git-bug_pull.md
+++ b/doc/md/git-bug_pull.md
@@ -1,6 +1,6 @@
## git-bug pull
-Pull bugs update from a git remote.
+Pull updates from a git remote
```
git-bug pull [REMOTE] [flags]
@@ -14,5 +14,5 @@ git-bug pull [REMOTE] [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
diff --git a/doc/md/git-bug_push.md b/doc/md/git-bug_push.md
index 18779700..a0213a01 100644
--- a/doc/md/git-bug_push.md
+++ b/doc/md/git-bug_push.md
@@ -1,6 +1,6 @@
## git-bug push
-Push bugs update to a git remote.
+Push updates to a git remote
```
git-bug push [REMOTE] [flags]
@@ -14,5 +14,5 @@ git-bug push [REMOTE] [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
diff --git a/doc/md/git-bug_status.md b/doc/md/git-bug_status.md
deleted file mode 100644
index 9eb56c6b..00000000
--- a/doc/md/git-bug_status.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## git-bug status
-
-Display or change a bug status.
-
-```
-git-bug status [ID] [flags]
-```
-
-### Options
-
-```
- -h, --help help for status
-```
-
-### SEE ALSO
-
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
-* [git-bug status close](git-bug_status_close.md) - Mark a bug as closed.
-* [git-bug status open](git-bug_status_open.md) - Mark a bug as open.
-
diff --git a/doc/md/git-bug_status_close.md b/doc/md/git-bug_status_close.md
deleted file mode 100644
index aee72649..00000000
--- a/doc/md/git-bug_status_close.md
+++ /dev/null
@@ -1,18 +0,0 @@
-## git-bug status close
-
-Mark a bug as closed.
-
-```
-git-bug status close [ID] [flags]
-```
-
-### Options
-
-```
- -h, --help help for close
-```
-
-### SEE ALSO
-
-* [git-bug status](git-bug_status.md) - Display or change a bug status.
-
diff --git a/doc/md/git-bug_status_open.md b/doc/md/git-bug_status_open.md
deleted file mode 100644
index 332a1d96..00000000
--- a/doc/md/git-bug_status_open.md
+++ /dev/null
@@ -1,18 +0,0 @@
-## git-bug status open
-
-Mark a bug as open.
-
-```
-git-bug status open [ID] [flags]
-```
-
-### Options
-
-```
- -h, --help help for open
-```
-
-### SEE ALSO
-
-* [git-bug status](git-bug_status.md) - Display or change a bug status.
-
diff --git a/doc/md/git-bug_termui.md b/doc/md/git-bug_termui.md
index 3da6869e..ccab380c 100644
--- a/doc/md/git-bug_termui.md
+++ b/doc/md/git-bug_termui.md
@@ -1,6 +1,6 @@
## git-bug termui
-Launch the terminal UI.
+Launch the terminal UI
```
git-bug termui [flags]
@@ -14,5 +14,5 @@ git-bug termui [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
diff --git a/doc/md/git-bug_title.md b/doc/md/git-bug_title.md
deleted file mode 100644
index 791fcb75..00000000
--- a/doc/md/git-bug_title.md
+++ /dev/null
@@ -1,19 +0,0 @@
-## git-bug title
-
-Display or change a title of a bug.
-
-```
-git-bug title [ID] [flags]
-```
-
-### Options
-
-```
- -h, --help help for title
-```
-
-### SEE ALSO
-
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
-* [git-bug title edit](git-bug_title_edit.md) - Edit a title of a bug.
-
diff --git a/doc/md/git-bug_user.md b/doc/md/git-bug_user.md
index 302a1eda..86939705 100644
--- a/doc/md/git-bug_user.md
+++ b/doc/md/git-bug_user.md
@@ -1,22 +1,22 @@
## git-bug user
-Display or change the user identity.
+List identities
```
-git-bug user [USER-ID] [flags]
+git-bug user [flags]
```
### Options
```
- -f, --field string Select field to display. Valid values are [email,humanId,id,lastModification,lastModificationLamports,login,metadata,name]
- -h, --help help for user
+ -f, --format string Select the output formatting style. Valid values are [default,json] (default "default")
+ -h, --help help for user
```
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
-* [git-bug user adopt](git-bug_user_adopt.md) - Adopt an existing identity as your own.
-* [git-bug user create](git-bug_user_create.md) - Create a new identity.
-* [git-bug user ls](git-bug_user_ls.md) - List identities.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
+* [git-bug user adopt](git-bug_user_adopt.md) - Adopt an existing identity as your own
+* [git-bug user new](git-bug_user_new.md) - Create a new identity
+* [git-bug user user](git-bug_user_user.md) - Display a user identity
diff --git a/doc/md/git-bug_user_adopt.md b/doc/md/git-bug_user_adopt.md
index 87d1305f..85a447ca 100644
--- a/doc/md/git-bug_user_adopt.md
+++ b/doc/md/git-bug_user_adopt.md
@@ -1,9 +1,9 @@
## git-bug user adopt
-Adopt an existing identity as your own.
+Adopt an existing identity as your own
```
-git-bug user adopt USER-ID [flags]
+git-bug user adopt USER_ID [flags]
```
### Options
@@ -14,5 +14,5 @@ git-bug user adopt USER-ID [flags]
### SEE ALSO
-* [git-bug user](git-bug_user.md) - Display or change the user identity.
+* [git-bug user](git-bug_user.md) - List identities
diff --git a/doc/md/git-bug_user_ls.md b/doc/md/git-bug_user_ls.md
deleted file mode 100644
index d86263e3..00000000
--- a/doc/md/git-bug_user_ls.md
+++ /dev/null
@@ -1,19 +0,0 @@
-## git-bug user ls
-
-List identities.
-
-```
-git-bug user ls [flags]
-```
-
-### Options
-
-```
- -f, --format string Select the output formatting style. Valid values are [default,json] (default "default")
- -h, --help help for ls
-```
-
-### SEE ALSO
-
-* [git-bug user](git-bug_user.md) - Display or change the user identity.
-
diff --git a/doc/md/git-bug_user_create.md b/doc/md/git-bug_user_new.md
index 68fc2c0e..f9c5ed41 100644
--- a/doc/md/git-bug_user_create.md
+++ b/doc/md/git-bug_user_new.md
@@ -1,9 +1,9 @@
-## git-bug user create
+## git-bug user new
-Create a new identity.
+Create a new identity
```
-git-bug user create [flags]
+git-bug user new [flags]
```
### Options
@@ -11,12 +11,12 @@ git-bug user create [flags]
```
-a, --avatar string Avatar URL
-e, --email string Email of the user
- -h, --help help for create
+ -h, --help help for new
-n, --name string Name to identify the user
--non-interactive Do not ask for user input
```
### SEE ALSO
-* [git-bug user](git-bug_user.md) - Display or change the user identity.
+* [git-bug user](git-bug_user.md) - List identities
diff --git a/doc/md/git-bug_user_user.md b/doc/md/git-bug_user_user.md
new file mode 100644
index 00000000..b3e6ac9b
--- /dev/null
+++ b/doc/md/git-bug_user_user.md
@@ -0,0 +1,19 @@
+## git-bug user user
+
+Display a user identity
+
+```
+git-bug user user show [USER_ID] [flags]
+```
+
+### Options
+
+```
+ -f, --field string Select field to display. Valid values are [email,humanId,id,lastModification,lastModificationLamports,login,metadata,name]
+ -h, --help help for user
+```
+
+### SEE ALSO
+
+* [git-bug user](git-bug_user.md) - List identities
+
diff --git a/doc/md/git-bug_version.md b/doc/md/git-bug_version.md
index 2d1a16a9..ceba8790 100644
--- a/doc/md/git-bug_version.md
+++ b/doc/md/git-bug_version.md
@@ -1,6 +1,6 @@
## git-bug version
-Show git-bug version information.
+Show git-bug version information
```
git-bug version [flags]
@@ -17,5 +17,5 @@ git-bug version [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
diff --git a/doc/md/git-bug_webui.md b/doc/md/git-bug_webui.md
index b1c54d3b..c342a9cf 100644
--- a/doc/md/git-bug_webui.md
+++ b/doc/md/git-bug_webui.md
@@ -1,6 +1,6 @@
## git-bug webui
-Launch the web UI.
+Launch the web UI
### Synopsis
@@ -29,5 +29,5 @@ git-bug webui [flags]
### SEE ALSO
-* [git-bug](git-bug.md) - A bug tracker embedded in Git.
+* [git-bug](git-bug.md) - A bug tracker embedded in Git
diff --git a/entities/identity/identity.go b/entities/identity/identity.go
index fd9da062..d497dbcc 100644
--- a/entities/identity/identity.go
+++ b/entities/identity/identity.go
@@ -22,7 +22,7 @@ const identityConfigKey = "git-bug.identity"
var ErrNonFastForwardMerge = errors.New("non fast-forward identity merge")
var ErrNoIdentitySet = errors.New("No identity is set.\n" +
"To interact with bugs, an identity first needs to be created using " +
- "\"git bug user create\" or adopted with \"git bug user adopt\"")
+ "\"git bug user new\" or adopted with \"git bug user adopt\"")
var ErrMultipleIdentitiesSet = errors.New("multiple user identities set")
func NewErrMultipleMatchIdentity(matching []entity.Id) *entity.ErrMultipleMatch {
diff --git a/go.mod b/go.mod
index 66c55162..0016de2f 100644
--- a/go.mod
+++ b/go.mod
@@ -23,7 +23,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/shurcooL/githubv4 v0.0.0-20190601194912-068505affed7
github.com/skratchdot/open-golang v0.0.0-20190402232053-79abb63cd66e
- github.com/spf13/cobra v1.5.0
+ github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
github.com/vektah/gqlparser/v2 v2.5.1
github.com/xanzy/go-gitlab v0.74.0
@@ -79,7 +79,7 @@ require (
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
github.com/imdario/mergo v0.3.12 // indirect
- github.com/inconshreveable/mousetrap v1.0.0 // indirect
+ github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/lucasb-eyer/go-colorful v1.0.3 // indirect
@@ -114,6 +114,5 @@ require (
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/go.sum b/go.sum
index 012320c5..683326c2 100644
--- a/go.sum
+++ b/go.sum
@@ -167,8 +167,9 @@ github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428/go.mod h1:uhpZMVGzny
github.com/ikawaha/kagome.ipadic v1.1.2/go.mod h1:DPSBbU0czaJhAb/5uKQZHMc9MTVRpDugJfX+HddPHHg=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
+github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
@@ -262,8 +263,8 @@ github.com/skratchdot/open-golang v0.0.0-20190402232053-79abb63cd66e/go.mod h1:s
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
-github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
+github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
+github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
diff --git a/misc/completion/bash/git-bug b/misc/completion/bash/git-bug
index 2bca660b..81eb0d3c 100644
--- a/misc/completion/bash/git-bug
+++ b/misc/completion/bash/git-bug
@@ -128,7 +128,7 @@ __git-bug_process_completion_results() {
__git-bug_handle_special_char "$cur" =
# Print the activeHelp statements before we finish
- if [ ${#activeHelp} -ne 0 ]; then
+ if [ ${#activeHelp[*]} -ne 0 ]; then
printf "\n";
printf "%s\n" "${activeHelp[@]}"
printf "\n"
diff --git a/misc/completion/powershell/git-bug b/misc/completion/powershell/git-bug
index 1b3e99d0..424ad8ac 100644
--- a/misc/completion/powershell/git-bug
+++ b/misc/completion/powershell/git-bug
@@ -10,7 +10,7 @@ filter __git-bug_escapeStringWithSpecialChars {
$_ -replace '\s|#|@|\$|;|,|''|\{|\}|\(|\)|"|`|\||<|>|&','`$&'
}
-Register-ArgumentCompleter -CommandName 'git-bug' -ScriptBlock {
+[scriptblock]$__git_bugCompleterBlock = {
param(
$WordToComplete,
$CommandAst,
@@ -226,3 +226,5 @@ Register-ArgumentCompleter -CommandName 'git-bug' -ScriptBlock {
}
}
+
+Register-ArgumentCompleter -CommandName 'git-bug' -ScriptBlock $__git_bugCompleterBlock
diff --git a/repository/config.go b/repository/config.go
index 4db8d4be..c6880b7d 100644
--- a/repository/config.go
+++ b/repository/config.go
@@ -26,7 +26,7 @@ type ConfigRead interface {
// there is zero or more than one entry for this key
ReadBool(key string) (bool, error)
- // ReadBool read a single string value from the config
+ // ReadString read a single string value from the config
// Return ErrNoConfigEntry or ErrMultipleConfigEntry if
// there is zero or more than one entry for this key
ReadString(key string) (string, error)
@@ -38,13 +38,13 @@ type ConfigRead interface {
}
type ConfigWrite interface {
- // Store writes a single key/value pair in the config
+ // StoreString writes a single string key/value pair in the config
StoreString(key, value string) error
- // Store writes a key and timestamp value to the config
+ // StoreTimestamp writes a key and timestamp value to the config
StoreTimestamp(key string, value time.Time) error
- // Store writes a key and boolean value to the config
+ // StoreBool writes a key and boolean value to the config
StoreBool(key string, value bool) error
// RemoveAll removes all key/value pair matching the key prefix