aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--commands/add.go80
-rw-r--r--commands/bridge.go42
-rw-r--r--commands/bridge_auth.go40
-rw-r--r--commands/bridge_auth_addtoken.go90
-rw-r--r--commands/bridge_auth_rm.go38
-rw-r--r--commands/bridge_auth_show.go48
-rw-r--r--commands/bridge_configure.go216
-rw-r--r--commands/bridge_pull.go71
-rw-r--r--commands/bridge_push.go41
-rw-r--r--commands/bridge_rm.go36
-rw-r--r--commands/commands.go69
-rw-r--r--commands/comment.go57
-rw-r--r--commands/comment_add.go73
-rw-r--r--commands/deselect.go44
-rw-r--r--commands/env.go40
-rw-r--r--commands/label.go40
-rw-r--r--commands/label_add.go35
-rw-r--r--commands/label_rm.go34
-rw-r--r--commands/ls-id.go33
-rw-r--r--commands/ls-labels.go41
-rw-r--r--commands/ls.go186
-rw-r--r--commands/pull.go42
-rw-r--r--commands/push.go37
-rw-r--r--commands/root.go133
-rw-r--r--commands/select.go60
-rw-r--r--commands/show.go153
-rw-r--r--commands/status.go38
-rw-r--r--commands/status_close.go33
-rw-r--r--commands/status_open.go33
-rw-r--r--commands/termui.go35
-rw-r--r--commands/title.go39
-rw-r--r--commands/title_edit.go65
-rw-r--r--commands/user.go89
-rw-r--r--commands/user_adopt.go38
-rw-r--r--commands/user_create.go39
-rw-r--r--commands/user_ls.go62
-rw-r--r--commands/version.go89
-rw-r--r--commands/webui.go100
-rw-r--r--doc/gen_docs.go4
-rw-r--r--doc/man/git-bug-bridge-pull.18
-rw-r--r--doc/md/git-bug_bridge_pull.md2
-rw-r--r--misc/gen_completion.go8
42 files changed, 1339 insertions, 1122 deletions
diff --git a/commands/add.go b/commands/add.go
index e656a262..8b5facaf 100644
--- a/commands/add.go
+++ b/commands/add.go
@@ -1,42 +1,65 @@
package commands
import (
- "fmt"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/input"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-var (
- addTitle string
- addMessage string
- addMessageFile string
-)
+type addOptions struct {
+ title string
+ message string
+ messageFile string
+}
+
+func newAddCommand() *cobra.Command {
+ env := newEnv()
+ options := addOptions{}
+
+ cmd := &cobra.Command{
+ Use: "add",
+ Short: "Create a new bug.",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runAdd(env, options)
+ },
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
-func runAddBug(cmd *cobra.Command, args []string) error {
- var err error
+ flags.StringVarP(&options.title, "title", "t", "",
+ "Provide a title to describe the issue")
+ flags.StringVarP(&options.message, "message", "m", "",
+ "Provide a message to describe the issue")
+ flags.StringVarP(&options.messageFile, "file", "F", "",
+ "Take the message from the given file. Use - to read the message from the standard input")
- backend, err := cache.NewRepoCache(repo)
+ return cmd
+}
+
+func runAdd(env *Env, opts addOptions) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
defer backend.Close()
interrupt.RegisterCleaner(backend.Close)
- if addMessageFile != "" && addMessage == "" {
- addTitle, addMessage, err = input.BugCreateFileInput(addMessageFile)
+ if opts.messageFile != "" && opts.message == "" {
+ opts.title, opts.message, err = input.BugCreateFileInput(opts.messageFile)
if err != nil {
return err
}
}
- if addMessageFile == "" && (addMessage == "" || addTitle == "") {
- addTitle, addMessage, err = input.BugCreateEditorInput(backend, addTitle, addMessage)
+ if opts.messageFile == "" && (opts.message == "" || opts.title == "") {
+ opts.title, opts.message, err = input.BugCreateEditorInput(backend, opts.title, opts.message)
if err == input.ErrEmptyTitle {
- fmt.Println("Empty title, aborting.")
+ env.out.Println("Empty title, aborting.")
return nil
}
if err != nil {
@@ -44,35 +67,12 @@ func runAddBug(cmd *cobra.Command, args []string) error {
}
}
- b, _, err := backend.NewBug(addTitle, addMessage)
+ b, _, err := backend.NewBug(opts.title, opts.message)
if err != nil {
return err
}
- fmt.Printf("%s created\n", b.Id().Human())
+ env.out.Printf("%s created\n", b.Id().Human())
return nil
}
-
-var addCmd = &cobra.Command{
- Use: "add",
- Short: "Create a new bug.",
- PreRunE: loadRepoEnsureUser,
- RunE: runAddBug,
-}
-
-func init() {
- RootCmd.AddCommand(addCmd)
-
- addCmd.Flags().SortFlags = false
-
- addCmd.Flags().StringVarP(&addTitle, "title", "t", "",
- "Provide a title to describe the issue",
- )
- addCmd.Flags().StringVarP(&addMessage, "message", "m", "",
- "Provide a message to describe the issue",
- )
- addCmd.Flags().StringVarP(&addMessageFile, "file", "F", "",
- "Take the message from the given file. Use - to read the message from the standard input",
- )
-}
diff --git a/commands/bridge.go b/commands/bridge.go
index 3c398e6b..8a2cf38b 100644
--- a/commands/bridge.go
+++ b/commands/bridge.go
@@ -1,8 +1,6 @@
package commands
import (
- "fmt"
-
"github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/bridge"
@@ -10,8 +8,30 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runBridge(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newBridgeCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "bridge",
+ Short: "Configure and use bridges to other bug trackers.",
+ PreRunE: loadRepo(env),
+ RunE: 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 {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -24,20 +44,8 @@ func runBridge(cmd *cobra.Command, args []string) error {
}
for _, c := range configured {
- fmt.Println(c)
+ env.out.Println(c)
}
return nil
}
-
-var bridgeCmd = &cobra.Command{
- Use: "bridge",
- Short: "Configure and use bridges to other bug trackers.",
- PreRunE: loadRepo,
- RunE: runBridge,
- Args: cobra.NoArgs,
-}
-
-func init() {
- RootCmd.AddCommand(bridgeCmd)
-}
diff --git a/commands/bridge_auth.go b/commands/bridge_auth.go
index 3a0e0c29..e51b9b9d 100644
--- a/commands/bridge_auth.go
+++ b/commands/bridge_auth.go
@@ -1,7 +1,6 @@
package commands
import (
- "fmt"
"sort"
"strings"
@@ -15,8 +14,28 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runBridgeAuth(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newBridgeAuthCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "auth",
+ Short: "List all known bridge authentication credentials.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runBridgeAuth(env)
+ },
+ Args: cobra.NoArgs,
+ }
+
+ cmd.AddCommand(newBridgeAuthAddTokenCommand())
+ cmd.AddCommand(newBridgeAuthRm())
+ cmd.AddCommand(newBridgeAuthShow())
+
+ return cmd
+}
+
+func runBridgeAuth(env *Env) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -44,7 +63,7 @@ func runBridgeAuth(cmd *cobra.Command, args []string) error {
sort.Strings(meta)
metaFmt := strings.Join(meta, ",")
- fmt.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()),
@@ -55,16 +74,3 @@ func runBridgeAuth(cmd *cobra.Command, args []string) error {
return nil
}
-
-var bridgeAuthCmd = &cobra.Command{
- Use: "auth",
- Short: "List all known bridge authentication credentials.",
- PreRunE: loadRepo,
- RunE: runBridgeAuth,
- Args: cobra.NoArgs,
-}
-
-func init() {
- bridgeCmd.AddCommand(bridgeAuthCmd)
- bridgeAuthCmd.Flags().SortFlags = false
-}
diff --git a/commands/bridge_auth_addtoken.go b/commands/bridge_auth_addtoken.go
index 8eda28ac..dde7a6dd 100644
--- a/commands/bridge_auth_addtoken.go
+++ b/commands/bridge_auth_addtoken.go
@@ -17,34 +17,61 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-var (
- bridgeAuthAddTokenTarget string
- bridgeAuthAddTokenLogin string
- bridgeAuthAddTokenUser string
-)
+type bridgeAuthAddTokenOptions struct {
+ target string
+ login string
+ user string
+}
+
+func newBridgeAuthAddTokenCommand() *cobra.Command {
+ env := newEnv()
+ options := bridgeAuthAddTokenOptions{}
+
+ cmd := &cobra.Command{
+ Use: "add-token [<token>]",
+ Short: "Store a new token",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runBridgeAuthAddToken(env, options, args)
+ },
+ Args: cobra.MaximumNArgs(1),
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.StringVarP(&options.target, "target", "t", "",
+ fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(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")
-func runBridgeTokenAdd(cmd *cobra.Command, args []string) error {
+ return cmd
+}
+
+func runBridgeAuthAddToken(env *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
// checking it would require a cumbersome UX (need to provide a base URL for some bridges, ...)
// so it's probably not worth it, unless we refactor that entirely.
- if bridgeAuthAddTokenTarget == "" {
+ if opts.target == "" {
return fmt.Errorf("flag --target is required")
}
- if bridgeAuthAddTokenLogin == "" {
+ if opts.login == "" {
return fmt.Errorf("flag --login is required")
}
- backend, err := cache.NewRepoCache(repo)
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
defer backend.Close()
interrupt.RegisterCleaner(backend.Close)
- if !core.TargetExist(bridgeAuthAddTokenTarget) {
+ if !core.TargetExist(opts.target) {
return fmt.Errorf("unknown target")
}
@@ -55,7 +82,7 @@ func runBridgeTokenAdd(cmd *cobra.Command, args []string) error {
} else {
// Read from Stdin
if isatty.IsTerminal(os.Stdin.Fd()) {
- fmt.Println("Enter the token:")
+ env.err.Println("Enter the token:")
}
reader := bufio.NewReader(os.Stdin)
raw, err := reader.ReadString('\n')
@@ -67,62 +94,43 @@ func runBridgeTokenAdd(cmd *cobra.Command, args []string) error {
var user *cache.IdentityCache
- if bridgeAuthAddTokenUser == "" {
+ if opts.user == "" {
user, err = backend.GetUserIdentity()
} else {
- user, err = backend.ResolveIdentityPrefix(bridgeAuthAddTokenUser)
+ user, err = backend.ResolveIdentityPrefix(opts.user)
}
if err != nil {
return err
}
- metaKey, _ := bridge.LoginMetaKey(bridgeAuthAddTokenTarget)
+ metaKey, _ := bridge.LoginMetaKey(opts.target)
login, ok := user.ImmutableMetadata()[metaKey]
switch {
- case ok && login == bridgeAuthAddTokenLogin:
+ case ok && login == opts.login:
// nothing to do
- case ok && login != bridgeAuthAddTokenLogin:
- return fmt.Errorf("this user is already tagged with a different %s login", bridgeAuthAddTokenTarget)
+ case ok && login != opts.login:
+ return fmt.Errorf("this user is already tagged with a different %s login", opts.target)
default:
- user.SetMetadata(metaKey, bridgeAuthAddTokenLogin)
+ user.SetMetadata(metaKey, opts.login)
err = user.Commit()
if err != nil {
return err
}
}
- token := auth.NewToken(bridgeAuthAddTokenTarget, value)
- token.SetMetadata(auth.MetaKeyLogin, bridgeAuthAddTokenLogin)
+ token := auth.NewToken(opts.target, value)
+ token.SetMetadata(auth.MetaKeyLogin, opts.login)
if err := token.Validate(); err != nil {
return errors.Wrap(err, "invalid token")
}
- err = auth.Store(repo, token)
+ err = auth.Store(env.repo, token)
if err != nil {
return err
}
- fmt.Printf("token %s added\n", token.ID())
+ env.out.Printf("token %s added\n", token.ID())
return nil
}
-
-var bridgeAuthAddTokenCmd = &cobra.Command{
- Use: "add-token [<token>]",
- Short: "Store a new token",
- PreRunE: loadRepoEnsureUser,
- RunE: runBridgeTokenAdd,
- Args: cobra.MaximumNArgs(1),
-}
-
-func init() {
- bridgeAuthCmd.AddCommand(bridgeAuthAddTokenCmd)
- bridgeAuthAddTokenCmd.Flags().StringVarP(&bridgeAuthAddTokenTarget, "target", "t", "",
- fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ",")))
- bridgeAuthAddTokenCmd.Flags().StringVarP(&bridgeAuthAddTokenLogin,
- "login", "l", "", "The login in the remote bug-tracker")
- bridgeAuthAddTokenCmd.Flags().StringVarP(&bridgeAuthAddTokenUser,
- "user", "u", "", "The user to add the token to. Default is the current user")
- bridgeAuthAddTokenCmd.Flags().SortFlags = false
-}
diff --git a/commands/bridge_auth_rm.go b/commands/bridge_auth_rm.go
index 17e70625..b2a44e92 100644
--- a/commands/bridge_auth_rm.go
+++ b/commands/bridge_auth_rm.go
@@ -1,36 +1,38 @@
package commands
import (
- "fmt"
-
"github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/bridge/core/auth"
)
-func runBridgeAuthRm(cmd *cobra.Command, args []string) error {
- cred, err := auth.LoadWithPrefix(repo, args[0])
+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),
+ }
+
+ 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(repo, cred.ID())
+ err = auth.Remove(env.repo, cred.ID())
if err != nil {
return err
}
- fmt.Printf("credential %s removed\n", cred.ID())
+ env.out.Printf("credential %s removed\n", cred.ID())
return nil
}
-
-var bridgeAuthRmCmd = &cobra.Command{
- Use: "rm <id>",
- Short: "Remove a credential.",
- PreRunE: loadRepo,
- RunE: runBridgeAuthRm,
- Args: cobra.ExactArgs(1),
-}
-
-func init() {
- bridgeAuthCmd.AddCommand(bridgeAuthRmCmd)
-}
diff --git a/commands/bridge_auth_show.go b/commands/bridge_auth_show.go
index fbbf60a7..f8b15c9a 100644
--- a/commands/bridge_auth_show.go
+++ b/commands/bridge_auth_show.go
@@ -13,30 +13,46 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runBridgeAuthShow(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newBridgeAuthShow() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "show",
+ Short: "Display an authentication credential.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runBridgeAuthShow(env, args)
+ },
+ Args: cobra.ExactArgs(1),
+ }
+
+ return cmd
+}
+
+func runBridgeAuthShow(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
defer backend.Close()
interrupt.RegisterCleaner(backend.Close)
- cred, err := auth.LoadWithPrefix(repo, args[0])
+ cred, err := auth.LoadWithPrefix(env.repo, args[0])
if err != nil {
return err
}
- fmt.Printf("Id: %s\n", cred.ID())
- fmt.Printf("Target: %s\n", cred.Target())
- fmt.Printf("Kind: %s\n", cred.Kind())
- fmt.Printf("Creation: %s\n", cred.CreateTime().Format(time.RFC822))
+ 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:
- fmt.Printf("Value: %s\n", cred.Value)
+ env.out.Printf("Value: %s\n", cred.Value)
}
- fmt.Println("Metadata:")
+ env.out.Println("Metadata:")
meta := make([]string, 0, len(cred.Metadata()))
for key, value := range cred.Metadata() {
@@ -44,19 +60,7 @@ func runBridgeAuthShow(cmd *cobra.Command, args []string) error {
}
sort.Strings(meta)
- fmt.Print(strings.Join(meta, ""))
+ env.out.Print(strings.Join(meta, ""))
return nil
}
-
-var bridgeAuthShowCmd = &cobra.Command{
- Use: "show",
- Short: "Display an authentication credential.",
- PreRunE: loadRepo,
- RunE: runBridgeAuthShow,
- Args: cobra.ExactArgs(1),
-}
-
-func init() {
- bridgeAuthCmd.AddCommand(bridgeAuthShowCmd)
-}
diff --git a/commands/bridge_configure.go b/commands/bridge_configure.go
index 89553633..83555b0c 100644
--- a/commands/bridge_configure.go
+++ b/commands/bridge_configure.go
@@ -17,79 +17,161 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-const (
- defaultName = "default"
-)
+type bridgeConfigureOptions struct {
+ name string
+ target string
+ params core.BridgeParams
+ token string
+ tokenStdin bool
+}
-var (
- bridgeConfigureName string
- bridgeConfigureTarget string
- bridgeConfigureParams core.BridgeParams
- bridgeConfigureToken string
- bridgeConfigureTokenStdin bool
-)
+func newBridgeConfigureCommand() *cobra.Command {
+ env := newEnv()
+ options := bridgeConfigureOptions{}
+
+ cmd := &cobra.Command{
+ Use: "configure",
+ 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
+[2]: gitlab
+[3]: jira
+[4]: launchpad-preview
+
+target: 1
+name [default]: default
+
+Detected projects:
+[1]: github.com/a-hilaly/git-bug
+[2]: github.com/MichaelMure/git-bug
+
+[0]: Another project
+
+Select option: 1
+
+[1]: user provided token
+[2]: interactive token creation
+Select option: 1
+
+You can generate a new token by visiting https://github.com/settings/tokens.
+Choose 'Generate new token' and set the necessary access scope for your repository.
+
+The access scope depend on the type of repository.
+Public:
+ - 'public_repo': to be able to read public repositories
+Private:
+ - 'repo' : to be able to read private repositories
+
+Enter token: 87cf5c03b64029f18ea5f9ca5679daa08ccbd700
+Successfully configured bridge: default
+
+# For GitHub
+git bug bridge configure \
+ --name=default \
+ --target=github \
+ --owner=$(OWNER) \
+ --project=$(PROJECT) \
+ --token=$(TOKEN)
+
+# For Launchpad
+git bug bridge configure \
+ --name=default \
+ --target=launchpad-preview \
+ --url=https://bugs.launchpad.net/ubuntu/
-func runBridgeConfigure(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+# For Gitlab
+git bug bridge configure \
+ --name=default \
+ --target=github \
+ --url=https://github.com/michaelmure/git-bug \
+ --token=$(TOKEN)`,
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runBridgeConfigure(env, options)
+ },
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ 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(), ",")))
+ 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")
+ flags.StringVarP(&options.params.CredPrefix, "credential", "c", "", "The identifier or prefix of an already known credential for your remote issue tracker (see \"git-bug bridge auth\")")
+ flags.StringVar(&options.token, "token", "", "A raw authentication token for the remote issue tracker")
+ flags.BoolVar(&options.tokenStdin, "token-stdin", false, "Will read the token from stdin and ignore --token")
+ flags.StringVarP(&options.params.Owner, "owner", "o", "", "The owner of the remote repository")
+ flags.StringVarP(&options.params.Project, "project", "p", "", "The name of the remote repository")
+
+ return cmd
+}
+
+func runBridgeConfigure(env *Env, opts bridgeConfigureOptions) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
defer backend.Close()
interrupt.RegisterCleaner(backend.Close)
- if (bridgeConfigureTokenStdin || bridgeConfigureToken != "" || bridgeConfigureParams.CredPrefix != "") &&
- (bridgeConfigureName == "" || bridgeConfigureTarget == "") {
+ if (opts.tokenStdin || opts.token != "" || opts.params.CredPrefix != "") &&
+ (opts.name == "" || opts.target == "") {
return fmt.Errorf("you must provide a bridge name and target to configure a bridge with a credential")
}
// early fail
- if bridgeConfigureParams.CredPrefix != "" {
- if _, err := auth.LoadWithPrefix(repo, bridgeConfigureParams.CredPrefix); err != nil {
+ if opts.params.CredPrefix != "" {
+ if _, err := auth.LoadWithPrefix(env.repo, opts.params.CredPrefix); err != nil {
return err
}
}
switch {
- case bridgeConfigureTokenStdin:
+ case opts.tokenStdin:
reader := bufio.NewReader(os.Stdin)
token, err := reader.ReadString('\n')
if err != nil {
return fmt.Errorf("reading from stdin: %v", err)
}
- bridgeConfigureParams.TokenRaw = strings.TrimSpace(token)
- case bridgeConfigureToken != "":
- bridgeConfigureParams.TokenRaw = bridgeConfigureToken
+ opts.params.TokenRaw = strings.TrimSpace(token)
+ case opts.token != "":
+ opts.params.TokenRaw = opts.token
}
- if bridgeConfigureTarget == "" {
- bridgeConfigureTarget, err = promptTarget()
+ if opts.target == "" {
+ opts.target, err = promptTarget()
if err != nil {
return err
}
}
- if bridgeConfigureName == "" {
- bridgeConfigureName, err = promptName(repo)
+ if opts.name == "" {
+ opts.name, err = promptName(env.repo)
if err != nil {
return err
}
}
- b, err := bridge.NewBridge(backend, bridgeConfigureTarget, bridgeConfigureName)
+ b, err := bridge.NewBridge(backend, opts.target, opts.name)
if err != nil {
return err
}
- err = b.Configure(bridgeConfigureParams)
+ err = b.Configure(opts.params)
if err != nil {
return err
}
- fmt.Printf("Successfully configured bridge: %s\n", bridgeConfigureName)
+ env.out.Printf("Successfully configured bridge: %s\n", opts.name)
return nil
}
func promptTarget() (string, error) {
+ // TODO: use the reusable prompt from the input package
targets := bridge.Targets()
for {
@@ -117,6 +199,9 @@ func promptTarget() (string, error) {
}
func promptName(repo repository.RepoConfig) (string, error) {
+ // TODO: use the reusable prompt from the input package
+ const defaultName = "default"
+
defaultExist := core.BridgeExist(repo, defaultName)
for {
@@ -149,80 +234,3 @@ func promptName(repo repository.RepoConfig) (string, error) {
fmt.Println("a bridge with the same name already exist")
}
}
-
-var bridgeConfigureCmd = &cobra.Command{
- Use: "configure",
- 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
-[2]: gitlab
-[3]: jira
-[4]: launchpad-preview
-
-target: 1
-name [default]: default
-
-Detected projects:
-[1]: github.com/a-hilaly/git-bug
-[2]: github.com/MichaelMure/git-bug
-
-[0]: Another project
-
-Select option: 1
-
-[1]: user provided token
-[2]: interactive token creation
-Select option: 1
-
-You can generate a new token by visiting https://github.com/settings/tokens.
-Choose 'Generate new token' and set the necessary access scope for your repository.
-
-The access scope depend on the type of repository.
-Public:
- - 'public_repo': to be able to read public repositories
-Private:
- - 'repo' : to be able to read private repositories
-
-Enter token: 87cf5c03b64029f18ea5f9ca5679daa08ccbd700
-Successfully configured bridge: default
-
-# For GitHub
-git bug bridge configure \
- --name=default \
- --target=github \
- --owner=$(OWNER) \
- --project=$(PROJECT) \
- --token=$(TOKEN)
-
-# For Launchpad
-git bug bridge configure \
- --name=default \
- --target=launchpad-preview \
- --url=https://bugs.launchpad.net/ubuntu/
-
-# For Gitlab
-git bug bridge configure \
- --name=default \
- --target=github \
- --url=https://github.com/michaelmure/git-bug \
- --token=$(TOKEN)`,
- PreRunE: loadRepo,
- RunE: runBridgeConfigure,
-}
-
-func init() {
- bridgeCmd.AddCommand(bridgeConfigureCmd)
- bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureName, "name", "n", "", "A distinctive name to identify the bridge")
- bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureTarget, "target", "t", "",
- fmt.Sprintf("The target of the bridge. Valid values are [%s]", strings.Join(bridge.Targets(), ",")))
- bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.URL, "url", "u", "", "The URL of the remote repository")
- bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.BaseURL, "base-url", "b", "", "The base URL of your remote issue tracker")
- bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.Login, "login", "l", "", "The login on your remote issue tracker")
- bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.CredPrefix, "credential", "c", "", "The identifier or prefix of an already known credential for your remote issue tracker (see \"git-bug bridge auth\")")
- bridgeConfigureCmd.Flags().StringVar(&bridgeConfigureToken, "token", "", "A raw authentication token for the remote issue tracker")
- bridgeConfigureCmd.Flags().BoolVar(&bridgeConfigureTokenStdin, "token-stdin", false, "Will read the token from stdin and ignore --token")
- bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.Owner, "owner", "o", "", "The owner of the remote repository")
- bridgeConfigureCmd.Flags().StringVarP(&bridgeConfigureParams.Project, "project", "p", "", "The name of the remote repository")
- bridgeConfigureCmd.Flags().SortFlags = false
-}
diff --git a/commands/bridge_pull.go b/commands/bridge_pull.go
index 2dd3d93e..dc8825fa 100644
--- a/commands/bridge_pull.go
+++ b/commands/bridge_pull.go
@@ -17,17 +17,40 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-var (
- bridgePullImportSince string
- bridgePullNoResume bool
-)
+type bridgePullOptions struct {
+ importSince string
+ noResume bool
+}
+
+func newBridgePullCommand() *cobra.Command {
+ env := newEnv()
+ options := bridgePullOptions{}
+
+ cmd := &cobra.Command{
+ Use: "pull [<name>]",
+ Short: "Pull updates.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runBridgePull(env, options, args)
+ },
+ Args: cobra.MaximumNArgs(1),
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.BoolVarP(&options.noResume, "no-resume", "n", false, "force importing all bugs")
+ flags.StringVarP(&options.importSince, "since", "s", "", "import only bugs updated after the given date (ex: \"200h\" or \"june 2 2019\")")
-func runBridgePull(cmd *cobra.Command, args []string) error {
- if bridgePullNoResume && bridgePullImportSince != "" {
+ return cmd
+}
+
+func runBridgePull(env *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")
}
- backend, err := cache.NewRepoCache(repo)
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -58,14 +81,14 @@ func runBridgePull(cmd *cobra.Command, args []string) error {
interrupt.RegisterCleaner(func() error {
mu.Lock()
if interruptCount > 0 {
- fmt.Println("Received another interrupt before graceful stop, terminating...")
+ env.err.Println("Received another interrupt before graceful stop, terminating...")
os.Exit(0)
}
interruptCount++
mu.Unlock()
- fmt.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()
@@ -77,10 +100,10 @@ func runBridgePull(cmd *cobra.Command, args []string) error {
var events <-chan core.ImportResult
switch {
- case bridgePullNoResume:
+ case opts.noResume:
events, err = b.ImportAllSince(ctx, time.Time{})
- case bridgePullImportSince != "":
- since, err2 := parseSince(bridgePullImportSince)
+ case opts.importSince != "":
+ since, err2 := parseSince(opts.importSince)
if err2 != nil {
return errors.Wrap(err2, "import time parsing")
}
@@ -102,23 +125,23 @@ func runBridgePull(cmd *cobra.Command, args []string) error {
case core.ImportEventBug:
importedIssues++
- fmt.Println(result.String())
+ env.out.Println(result.String())
case core.ImportEventIdentity:
importedIdentities++
- fmt.Println(result.String())
+ env.out.Println(result.String())
case core.ImportEventError:
if result.Err != context.Canceled {
- fmt.Println(result.String())
+ env.out.Println(result.String())
}
default:
- fmt.Println(result.String())
+ env.out.Println(result.String())
}
}
- fmt.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)
@@ -134,17 +157,3 @@ func parseSince(since string) (time.Time, error) {
return dateparse.ParseLocal(since)
}
-
-var bridgePullCmd = &cobra.Command{
- Use: "pull [<name>]",
- Short: "Pull updates.",
- PreRunE: loadRepo,
- RunE: runBridgePull,
- Args: cobra.MaximumNArgs(1),
-}
-
-func init() {
- bridgeCmd.AddCommand(bridgePullCmd)
- bridgePullCmd.Flags().BoolVarP(&bridgePullNoResume, "no-resume", "n", false, "force importing all bugs")
- bridgePullCmd.Flags().StringVarP(&bridgePullImportSince, "since", "s", "", "import only bugs updated after the given date (ex: \"200h\" or \"june 2 2019\")")
-}
diff --git a/commands/bridge_push.go b/commands/bridge_push.go
index 52d23a97..73df87fb 100644
--- a/commands/bridge_push.go
+++ b/commands/bridge_push.go
@@ -2,7 +2,6 @@ package commands
import (
"context"
- "fmt"
"os"
"sync"
"time"
@@ -15,8 +14,24 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runBridgePush(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newBridgePushCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "push [<name>]",
+ Short: "Push updates.",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runBridgePush(env, args)
+ },
+ Args: cobra.MaximumNArgs(1),
+ }
+
+ return cmd
+}
+
+func runBridgePush(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -46,14 +61,14 @@ func runBridgePush(cmd *cobra.Command, args []string) error {
interrupt.RegisterCleaner(func() error {
mu.Lock()
if interruptCount > 0 {
- fmt.Println("Received another interrupt before graceful stop, terminating...")
+ env.err.Println("Received another interrupt before graceful stop, terminating...")
os.Exit(0)
}
interruptCount++
mu.Unlock()
- fmt.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()
@@ -71,7 +86,7 @@ func runBridgePush(cmd *cobra.Command, args []string) error {
exportedIssues := 0
for result := range events {
if result.Event != core.ExportEventNothing {
- fmt.Println(result.String())
+ env.out.Println(result.String())
}
switch result.Event {
@@ -80,21 +95,9 @@ func runBridgePush(cmd *cobra.Command, args []string) error {
}
}
- fmt.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)
return nil
}
-
-var bridgePushCmd = &cobra.Command{
- Use: "push [<name>]",
- Short: "Push updates.",
- PreRunE: loadRepoEnsureUser,
- RunE: runBridgePush,
- Args: cobra.MaximumNArgs(1),
-}
-
-func init() {
- bridgeCmd.AddCommand(bridgePushCmd)
-}
diff --git a/commands/bridge_rm.go b/commands/bridge_rm.go
index 76ad5949..4ff963db 100644
--- a/commands/bridge_rm.go
+++ b/commands/bridge_rm.go
@@ -1,8 +1,6 @@
package commands
import (
- "fmt"
-
"github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/bridge"
@@ -10,8 +8,24 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runBridgeRm(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newBridgeRm() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "rm <name>",
+ Short: "Delete a configured bridge.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runBridgeRm(env, args)
+ },
+ Args: cobra.ExactArgs(1),
+ }
+
+ return cmd
+}
+
+func runBridgeRm(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -23,18 +37,6 @@ func runBridgeRm(cmd *cobra.Command, args []string) error {
return err
}
- fmt.Printf("Successfully removed bridge configuration %v\n", args[0])
+ env.out.Printf("Successfully removed bridge configuration %v\n", args[0])
return nil
}
-
-var bridgeRmCmd = &cobra.Command{
- Use: "rm <name>",
- Short: "Delete a configured bridge.",
- PreRunE: loadRepo,
- RunE: runBridgeRm,
- Args: cobra.ExactArgs(1),
-}
-
-func init() {
- bridgeCmd.AddCommand(bridgeRmCmd)
-}
diff --git a/commands/commands.go b/commands/commands.go
index bd8cb14d..103d5412 100644
--- a/commands/commands.go
+++ b/commands/commands.go
@@ -1,27 +1,42 @@
package commands
import (
- "fmt"
"sort"
"github.com/spf13/cobra"
)
-var (
- commandsDesc bool
-)
+type commandOptions struct {
+ desc bool
+}
-type commandSorterByName []*cobra.Command
+func newCommandsCommand() *cobra.Command {
+ env := newEnv()
+ options := commandOptions{}
-func (c commandSorterByName) Len() int { return len(c) }
-func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
-func (c commandSorterByName) Less(i, j int) bool { return c[i].CommandPath() < c[j].CommandPath() }
+ cmd := &cobra.Command{
+ Use: "commands [<option>...]",
+ Short: "Display available commands.",
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runCommands(env, options)
+ },
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.BoolVarP(&options.desc, "pretty", "p", false,
+ "Output the command description as well as Markdown compatible comment",
+ )
-func runCommands(cmd *cobra.Command, args []string) error {
+ return cmd
+}
+
+func runCommands(env *Env, opts commandOptions) error {
first := true
var allCmds []*cobra.Command
- queue := []*cobra.Command{RootCmd}
+ queue := []*cobra.Command{NewRootCommand()}
for len(queue) > 0 {
cmd := queue[0]
@@ -34,41 +49,31 @@ func runCommands(cmd *cobra.Command, args []string) error {
for _, cmd := range allCmds {
if !first {
- fmt.Println()
+ env.out.Println()
}
first = false
- if commandsDesc {
- fmt.Printf("# %s\n", cmd.Short)
+ if opts.desc {
+ env.out.Printf("# %s\n", cmd.Short)
}
- fmt.Print(cmd.UseLine())
+ env.out.Print(cmd.UseLine())
- if commandsDesc {
- fmt.Println()
+ if opts.desc {
+ env.out.Println()
}
}
- if !commandsDesc {
- fmt.Println()
+ if !opts.desc {
+ env.out.Println()
}
return nil
}
-var commandsCmd = &cobra.Command{
- Use: "commands [<option>...]",
- Short: "Display available commands.",
- RunE: runCommands,
-}
-
-func init() {
- RootCmd.AddCommand(commandsCmd)
-
- commandsCmd.Flags().SortFlags = false
+type commandSorterByName []*cobra.Command
- commandsCmd.Flags().BoolVarP(&commandsDesc, "pretty", "p", false,
- "Output the command description as well as Markdown compatible comment",
- )
-}
+func (c commandSorterByName) Len() int { return len(c) }
+func (c commandSorterByName) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
+func (c commandSorterByName) Less(i, j int) bool { return c[i].CommandPath() < c[j].CommandPath() }
diff --git a/commands/comment.go b/commands/comment.go
index 4be39a84..82e7d9f6 100644
--- a/commands/comment.go
+++ b/commands/comment.go
@@ -1,20 +1,34 @@
package commands
import (
- "fmt"
-
- "github.com/MichaelMure/go-term-text"
+ text "github.com/MichaelMure/go-term-text"
"github.com/spf13/cobra"
- "github.com/MichaelMure/git-bug/bug"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/util/colors"
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runComment(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newCommentCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "comment [<id>]",
+ Short: "Display or add comments to a bug.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runComment(env, args)
+ },
+ }
+
+ cmd.AddCommand(newCommentAddCommand())
+
+ return cmd
+}
+
+func runComment(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -28,33 +42,16 @@ func runComment(cmd *cobra.Command, args []string) error {
snap := b.Snapshot()
- commentsTextOutput(snap.Comments)
-
- return nil
-}
-
-func commentsTextOutput(comments []bug.Comment) {
- for i, comment := range comments {
+ for i, comment := range snap.Comments {
if i != 0 {
- fmt.Println()
+ env.out.Println()
}
- fmt.Printf("Author: %s\n", colors.Magenta(comment.Author.DisplayName()))
- fmt.Printf("Id: %s\n", colors.Cyan(comment.Id().Human()))
- fmt.Printf("Date: %s\n\n", comment.FormatTime())
- fmt.Println(text.LeftPadLines(comment.Message, 4))
+ env.out.Printf("Author: %s\n", colors.Magenta(comment.Author.DisplayName()))
+ env.out.Printf("Id: %s\n", colors.Cyan(comment.Id().Human()))
+ env.out.Printf("Date: %s\n\n", comment.FormatTime())
+ env.out.Println(text.LeftPadLines(comment.Message, 4))
}
-}
-var commentCmd = &cobra.Command{
- Use: "comment [<id>]",
- Short: "Display or add comments to a bug.",
- PreRunE: loadRepo,
- RunE: runComment,
-}
-
-func init() {
- RootCmd.AddCommand(commentCmd)
-
- commentCmd.Flags().SortFlags = false
+ return nil
}
diff --git a/commands/comment_add.go b/commands/comment_add.go
index dfd63e38..1a560b5e 100644
--- a/commands/comment_add.go
+++ b/commands/comment_add.go
@@ -1,22 +1,46 @@
package commands
import (
- "fmt"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/input"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-var (
- commentAddMessageFile string
- commentAddMessage string
-)
+type commentAddOptions struct {
+ messageFile string
+ message string
+}
+
+func newCommentAddCommand() *cobra.Command {
+ env := newEnv()
+ options := commentAddOptions{}
+
+ cmd := &cobra.Command{
+ Use: "add [<id>]",
+ Short: "Add a new comment to a bug.",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runCommentAdd(env, options, args)
+ },
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.StringVarP(&options.messageFile, "file", "F", "",
+ "Take the message from the given file. Use - to read the message from the standard input")
+
+ flags.StringVarP(&options.message, "message", "m", "",
+ "Provide the new message from the command line")
-func runCommentAdd(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+ return cmd
+}
+
+func runCommentAdd(env *Env, opts commentAddOptions, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -28,17 +52,17 @@ func runCommentAdd(cmd *cobra.Command, args []string) error {
return err
}
- if commentAddMessageFile != "" && commentAddMessage == "" {
- commentAddMessage, err = input.BugCommentFileInput(commentAddMessageFile)
+ if opts.messageFile != "" && opts.message == "" {
+ opts.message, err = input.BugCommentFileInput(opts.messageFile)
if err != nil {
return err
}
}
- if commentAddMessageFile == "" && commentAddMessage == "" {
- commentAddMessage, err = input.BugCommentEditorInput(backend, "")
+ if opts.messageFile == "" && opts.message == "" {
+ opts.message, err = input.BugCommentEditorInput(backend, "")
if err == input.ErrEmptyMessage {
- fmt.Println("Empty message, aborting.")
+ env.err.Println("Empty message, aborting.")
return nil
}
if err != nil {
@@ -46,31 +70,10 @@ func runCommentAdd(cmd *cobra.Command, args []string) error {
}
}
- _, err = b.AddComment(commentAddMessage)
+ _, err = b.AddComment(opts.message)
if err != nil {
return err
}
return b.Commit()
}
-
-var commentAddCmd = &cobra.Command{
- Use: "add [<id>]",
- Short: "Add a new comment to a bug.",
- PreRunE: loadRepoEnsureUser,
- RunE: runCommentAdd,
-}
-
-func init() {
- commentCmd.AddCommand(commentAddCmd)
-
- commentAddCmd.Flags().SortFlags = false
-
- commentAddCmd.Flags().StringVarP(&commentAddMessageFile, "file", "F", "",
- "Take the message from the given file. Use - to read the message from the standard input",
- )
-
- commentAddCmd.Flags().StringVarP(&commentAddMessage, "message", "m", "",
- "Provide the new message from the command line",
- )
-}
diff --git a/commands/deselect.go b/commands/deselect.go
index f92c81fd..22a5f55d 100644
--- a/commands/deselect.go
+++ b/commands/deselect.go
@@ -1,14 +1,35 @@
package commands
import (
+ "github.com/spf13/cobra"
+
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runDeselect(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+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: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runDeselect(env)
+ },
+ }
+
+ return cmd
+}
+
+func runDeselect(env *Env) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -22,20 +43,3 @@ func runDeselect(cmd *cobra.Command, args []string) error {
return nil
}
-
-var deselectCmd = &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: loadRepo,
- RunE: runDeselect,
-}
-
-func init() {
- RootCmd.AddCommand(deselectCmd)
- deselectCmd.Flags().SortFlags = false
-}
diff --git a/commands/env.go b/commands/env.go
new file mode 100644
index 00000000..daba8420
--- /dev/null
+++ b/commands/env.go
@@ -0,0 +1,40 @@
+package commands
+
+import (
+ "fmt"
+ "io"
+ "os"
+
+ "github.com/MichaelMure/git-bug/repository"
+)
+
+// Env is the environment of a command
+type Env struct {
+ repo repository.ClockedRepo
+ out out
+ err out
+}
+
+func newEnv() *Env {
+ return &Env{
+ repo: nil,
+ out: out{Writer: os.Stdout},
+ err: out{Writer: os.Stderr},
+ }
+}
+
+type out struct {
+ io.Writer
+}
+
+func (o out) Printf(format string, a ...interface{}) {
+ _, _ = fmt.Fprintf(o, format, a...)
+}
+
+func (o out) Print(a ...interface{}) {
+ _, _ = fmt.Fprint(o, a...)
+}
+
+func (o out) Println(a ...interface{}) {
+ _, _ = fmt.Fprintln(o, a...)
+}
diff --git a/commands/label.go b/commands/label.go
index a07e9efc..e48be18e 100644
--- a/commands/label.go
+++ b/commands/label.go
@@ -1,16 +1,33 @@
package commands
import (
- "fmt"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runLabel(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newLabelCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "label [<id>]",
+ Short: "Display, add or remove labels to/from a bug.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runLabel(env, args)
+ },
+ }
+
+ cmd.AddCommand(newLabelAddCommand())
+ cmd.AddCommand(newLabelRmCommand())
+
+ return cmd
+}
+
+func runLabel(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -25,21 +42,8 @@ func runLabel(cmd *cobra.Command, args []string) error {
snap := b.Snapshot()
for _, l := range snap.Labels {
- fmt.Println(l)
+ env.out.Println(l)
}
return nil
}
-
-var labelCmd = &cobra.Command{
- Use: "label [<id>]",
- Short: "Display, add or remove labels to/from a bug.",
- PreRunE: loadRepo,
- RunE: runLabel,
-}
-
-func init() {
- RootCmd.AddCommand(labelCmd)
-
- labelCmd.Flags().SortFlags = false
-}
diff --git a/commands/label_add.go b/commands/label_add.go
index 39dfb085..83a9f064 100644
--- a/commands/label_add.go
+++ b/commands/label_add.go
@@ -1,16 +1,30 @@
package commands
import (
- "fmt"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runLabelAdd(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newLabelAddCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "add [<id>] <label>[...]",
+ Short: "Add a label to a bug.",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runLabelAdd(env, args)
+ },
+ }
+
+ return cmd
+}
+
+func runLabelAdd(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -25,7 +39,7 @@ func runLabelAdd(cmd *cobra.Command, args []string) error {
changes, _, err := b.ChangeLabels(args, nil)
for _, change := range changes {
- fmt.Println(change)
+ env.out.Println(change)
}
if err != nil {
@@ -34,14 +48,3 @@ func runLabelAdd(cmd *cobra.Command, args []string) error {
return b.Commit()
}
-
-var labelAddCmd = &cobra.Command{
- Use: "add [<id>] <label>[...]",
- Short: "Add a label to a bug.",
- PreRunE: loadRepoEnsureUser,
- RunE: runLabelAdd,
-}
-
-func init() {
- labelCmd.AddCommand(labelAddCmd)
-}
diff --git a/commands/label_rm.go b/commands/label_rm.go
index 11300c78..5fba4150 100644
--- a/commands/label_rm.go
+++ b/commands/label_rm.go
@@ -1,8 +1,6 @@
package commands
import (
- "fmt"
-
"github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
@@ -10,8 +8,23 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runLabelRm(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newLabelRmCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "rm [<id>] <label>[...]",
+ Short: "Remove a label from a bug.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runLabelRm(env, args)
+ },
+ }
+
+ return cmd
+}
+
+func runLabelRm(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -26,7 +39,7 @@ func runLabelRm(cmd *cobra.Command, args []string) error {
changes, _, err := b.ChangeLabels(nil, args)
for _, change := range changes {
- fmt.Println(change)
+ env.out.Println(change)
}
if err != nil {
@@ -35,14 +48,3 @@ func runLabelRm(cmd *cobra.Command, args []string) error {
return b.Commit()
}
-
-var labelRmCmd = &cobra.Command{
- Use: "rm [<id>] <label>[...]",
- Short: "Remove a label from a bug.",
- PreRunE: loadRepo,
- RunE: runLabelRm,
-}
-
-func init() {
- labelCmd.AddCommand(labelRmCmd)
-}
diff --git a/commands/ls-id.go b/commands/ls-id.go
index 22357eb4..6624793d 100644
--- a/commands/ls-id.go
+++ b/commands/ls-id.go
@@ -1,17 +1,29 @@
package commands
import (
- "fmt"
-
"github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runLsID(cmd *cobra.Command, args []string) error {
+func newLsIdCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "ls-id [<prefix>]",
+ Short: "List bug identifiers.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runLsId(env, args)
+ },
+ }
+
+ return cmd
+}
- backend, err := cache.NewRepoCache(repo)
+func runLsId(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -25,20 +37,9 @@ func runLsID(cmd *cobra.Command, args []string) error {
for _, id := range backend.AllBugsIds() {
if prefix == "" || id.HasPrefix(prefix) {
- fmt.Println(id)
+ env.out.Println(id)
}
}
return nil
}
-
-var listBugIDCmd = &cobra.Command{
- Use: "ls-id [<prefix>]",
- Short: "List bug identifiers.",
- PreRunE: loadRepo,
- RunE: runLsID,
-}
-
-func init() {
- RootCmd.AddCommand(listBugIDCmd)
-}
diff --git a/commands/ls-labels.go b/commands/ls-labels.go
index 5610fb56..3473aadd 100644
--- a/commands/ls-labels.go
+++ b/commands/ls-labels.go
@@ -1,15 +1,32 @@
package commands
import (
- "fmt"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runLsLabel(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+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: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runLsLabel(env)
+ },
+ }
+
+ return cmd
+}
+
+func runLsLabel(env *Env) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -19,22 +36,8 @@ func runLsLabel(cmd *cobra.Command, args []string) error {
labels := backend.ValidLabels()
for _, l := range labels {
- fmt.Println(l)
+ env.out.Println(l)
}
return nil
}
-
-var lsLabelCmd = &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: loadRepo,
- RunE: runLsLabel,
-}
-
-func init() {
- RootCmd.AddCommand(lsLabelCmd)
-}
diff --git a/commands/ls.go b/commands/ls.go
index 34f1f982..f48a5796 100644
--- a/commands/ls.go
+++ b/commands/ls.go
@@ -15,18 +15,67 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-var (
- lsQuery query.Query
-
- lsStatusQuery []string
- lsNoQuery []string
- lsSortBy string
- lsSortDirection string
- lsOutputFormat string
-)
+type lsOptions struct {
+ query query.Query
+
+ statusQuery []string
+ noQuery []string
+ sortBy string
+ sortDirection string
+ outputFormat string
+}
+
+func newLsCommand() *cobra.Command {
+ env := newEnv()
+ options := lsOptions{}
+
+ cmd := &cobra.Command{
+ Use: "ls [<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 or with flags.`,
+ Example: `List open bugs sorted by last edition with a query:
+git bug ls status:open sort:edit-desc
+
+List closed bugs sorted by creation with flags:
+git bug ls --status closed --by creation
+`,
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runLs(env, options, args)
+ },
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
-func runLsBug(_ *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+ flags.StringSliceVarP(&options.statusQuery, "status", "s", nil,
+ "Filter by status. Valid values are [open,closed]")
+ flags.StringSliceVarP(&options.query.Author, "author", "a", nil,
+ "Filter by author")
+ flags.StringSliceVarP(&options.query.Participant, "participant", "p", nil,
+ "Filter by participant")
+ flags.StringSliceVarP(&options.query.Actor, "actor", "A", nil,
+ "Filter by actor")
+ flags.StringSliceVarP(&options.query.Label, "label", "l", nil,
+ "Filter by label")
+ flags.StringSliceVarP(&options.query.Title, "title", "t", nil,
+ "Filter by title")
+ flags.StringSliceVarP(&options.noQuery, "no", "n", nil,
+ "Filter by absence of something. Valid values are [label]")
+ flags.StringVarP(&options.sortBy, "by", "b", "creation",
+ "Sort the results by a characteristic. Valid values are [id,creation,edit]")
+ flags.StringVarP(&options.sortDirection, "direction", "d", "asc",
+ "Select the sorting direction. Valid values are [asc,desc]")
+ flags.StringVarP(&options.outputFormat, "format", "f", "default",
+ "Select the output formatting style. Valid values are [default,plain,json,org-mode]")
+
+ return cmd
+}
+
+func runLs(env *Env, opts lsOptions, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -41,11 +90,11 @@ func runLsBug(_ *cobra.Command, args []string) error {
return err
}
} else {
- err = completeQuery()
+ err = completeQuery(&opts)
if err != nil {
return err
}
- q = &lsQuery
+ q = &opts.query
}
allIds := backend.QueryBugs(q)
@@ -59,17 +108,17 @@ func runLsBug(_ *cobra.Command, args []string) error {
bugExcerpt[i] = b
}
- switch lsOutputFormat {
+ switch opts.outputFormat {
case "org-mode":
- return lsOrgmodeFormatter(backend, bugExcerpt)
+ return lsOrgmodeFormatter(env, backend, bugExcerpt)
case "plain":
- return lsPlainFormatter(backend, bugExcerpt)
+ return lsPlainFormatter(env, backend, bugExcerpt)
case "json":
- return lsJsonFormatter(backend, bugExcerpt)
+ return lsJsonFormatter(env, backend, bugExcerpt)
case "default":
- return lsDefaultFormatter(backend, bugExcerpt)
+ return lsDefaultFormatter(env, backend, bugExcerpt)
default:
- return fmt.Errorf("unknown format %s", lsOutputFormat)
+ return fmt.Errorf("unknown format %s", opts.outputFormat)
}
}
@@ -90,7 +139,7 @@ type JSONBugExcerpt struct {
Metadata map[string]string `json:"metadata"`
}
-func lsJsonFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
+func lsJsonFormatter(env *Env, backend *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
jsonBugs := make([]JSONBugExcerpt, len(bugExcerpts))
for i, b := range bugExcerpts {
jsonBug := JSONBugExcerpt{
@@ -136,11 +185,11 @@ func lsJsonFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerpt)
jsonBugs[i] = jsonBug
}
jsonObject, _ := json.MarshalIndent(jsonBugs, "", " ")
- fmt.Printf("%s\n", jsonObject)
+ env.out.Printf("%s\n", jsonObject)
return nil
}
-func lsDefaultFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
+func lsDefaultFormatter(env *Env, backend *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
for _, b := range bugExcerpts {
var name string
if b.AuthorId != "" {
@@ -171,7 +220,7 @@ func lsDefaultFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerp
comments = " ∞ 💬"
}
- fmt.Printf("%s %s\t%s\t%s\t%s\n",
+ env.out.Printf("%s %s\t%s\t%s\t%s\n",
colors.Cyan(b.Id.Human()),
colors.Yellow(b.Status),
titleFmt+labelsFmt,
@@ -182,15 +231,15 @@ func lsDefaultFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerp
return nil
}
-func lsPlainFormatter(_ *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
+func lsPlainFormatter(env *Env, _ *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
for _, b := range bugExcerpts {
- fmt.Printf("%s [%s] %s\n", b.Id.Human(), b.Status, b.Title)
+ env.out.Printf("%s [%s] %s\n", b.Id.Human(), b.Status, b.Title)
}
return nil
}
-func lsOrgmodeFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
- fmt.Println("+TODO: OPEN | CLOSED")
+func lsOrgmodeFormatter(env *Env, backend *cache.RepoCache, bugExcerpts []*cache.BugExcerpt) error {
+ env.out.Println("+TODO: OPEN | CLOSED")
for _, b := range bugExcerpts {
status := strings.Title(b.Status.String())
@@ -221,7 +270,7 @@ func lsOrgmodeFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerp
labelsString = ""
}
- fmt.Printf("* %s %s [%s] %s: %s %s\n",
+ env.out.Printf("* %s %s [%s] %s: %s %s\n",
b.Id.Human(),
status,
b.CreateTime(),
@@ -230,29 +279,29 @@ func lsOrgmodeFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerp
labelsString,
)
- fmt.Printf("** Last Edited: %s\n", b.EditTime().String())
+ env.out.Printf("** Last Edited: %s\n", b.EditTime().String())
- fmt.Printf("** Actors:\n")
+ env.out.Printf("** Actors:\n")
for _, element := range b.Actors {
actor, err := backend.ResolveIdentityExcerpt(element)
if err != nil {
return err
}
- fmt.Printf(": %s %s\n",
+ env.out.Printf(": %s %s\n",
actor.Id.Human(),
actor.DisplayName(),
)
}
- fmt.Printf("** Participants:\n")
+ env.out.Printf("** Participants:\n")
for _, element := range b.Participants {
participant, err := backend.ResolveIdentityExcerpt(element)
if err != nil {
return err
}
- fmt.Printf(": %s %s\n",
+ env.out.Printf(": %s %s\n",
participant.Id.Human(),
participant.DisplayName(),
)
@@ -263,86 +312,43 @@ func lsOrgmodeFormatter(backend *cache.RepoCache, bugExcerpts []*cache.BugExcerp
}
// Finish the command flags transformation into the query.Query
-func completeQuery() error {
- for _, str := range lsStatusQuery {
+func completeQuery(opts *lsOptions) error {
+ for _, str := range opts.statusQuery {
status, err := bug.StatusFromString(str)
if err != nil {
return err
}
- lsQuery.Status = append(lsQuery.Status, status)
+ opts.query.Status = append(opts.query.Status, status)
}
- for _, no := range lsNoQuery {
+ for _, no := range opts.noQuery {
switch no {
case "label":
- lsQuery.NoLabel = true
+ opts.query.NoLabel = true
default:
return fmt.Errorf("unknown \"no\" filter %s", no)
}
}
- switch lsSortBy {
+ switch opts.sortBy {
case "id":
- lsQuery.OrderBy = query.OrderById
+ opts.query.OrderBy = query.OrderById
case "creation":
- lsQuery.OrderBy = query.OrderByCreation
+ opts.query.OrderBy = query.OrderByCreation
case "edit":
- lsQuery.OrderBy = query.OrderByEdit
+ opts.query.OrderBy = query.OrderByEdit
default:
- return fmt.Errorf("unknown sort flag %s", lsSortBy)
+ return fmt.Errorf("unknown sort flag %s", opts.sortBy)
}
- switch lsSortDirection {
+ switch opts.sortDirection {
case "asc":
- lsQuery.OrderDirection = query.OrderAscending
+ opts.query.OrderDirection = query.OrderAscending
case "desc":
- lsQuery.OrderDirection = query.OrderDescending
+ opts.query.OrderDirection = query.OrderDescending
default:
- return fmt.Errorf("unknown sort direction %s", lsSortDirection)
+ return fmt.Errorf("unknown sort direction %s", opts.sortDirection)
}
return nil
}
-
-var lsCmd = &cobra.Command{
- Use: "ls [<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 or with flags.`,
- Example: `List open bugs sorted by last edition with a query:
-git bug ls status:open sort:edit-desc
-
-List closed bugs sorted by creation with flags:
-git bug ls --status closed --by creation
-`,
- PreRunE: loadRepo,
- RunE: runLsBug,
-}
-
-func init() {
- RootCmd.AddCommand(lsCmd)
-
- lsCmd.Flags().SortFlags = false
-
- lsCmd.Flags().StringSliceVarP(&lsStatusQuery, "status", "s", nil,
- "Filter by status. Valid values are [open,closed]")
- lsCmd.Flags().StringSliceVarP(&lsQuery.Author, "author", "a", nil,
- "Filter by author")
- lsCmd.Flags().StringSliceVarP(&lsQuery.Participant, "participant", "p", nil,
- "Filter by participant")
- lsCmd.Flags().StringSliceVarP(&lsQuery.Actor, "actor", "A", nil,
- "Filter by actor")
- lsCmd.Flags().StringSliceVarP(&lsQuery.Label, "label", "l", nil,
- "Filter by label")
- lsCmd.Flags().StringSliceVarP(&lsQuery.Title, "title", "t", nil,
- "Filter by title")
- lsCmd.Flags().StringSliceVarP(&lsNoQuery, "no", "n", nil,
- "Filter by absence of something. Valid values are [label]")
- lsCmd.Flags().StringVarP(&lsSortBy, "by", "b", "creation",
- "Sort the results by a characteristic. Valid values are [id,creation,edit]")
- lsCmd.Flags().StringVarP(&lsSortDirection, "direction", "d", "asc",
- "Select the sorting direction. Valid values are [asc,desc]")
- lsCmd.Flags().StringVarP(&lsOutputFormat, "format", "f", "default",
- "Select the output formatting style. Valid values are [default,plain,json,org-mode]")
-}
diff --git a/commands/pull.go b/commands/pull.go
index 0439ab41..fb50a03b 100644
--- a/commands/pull.go
+++ b/commands/pull.go
@@ -2,7 +2,6 @@ package commands
import (
"errors"
- "fmt"
"github.com/spf13/cobra"
@@ -11,7 +10,22 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runPull(cmd *cobra.Command, args []string) error {
+func newPullCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "pull [<remote>]",
+ Short: "Pull bugs update from a git remote.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runPull(env, args)
+ },
+ }
+
+ return cmd
+}
+
+func runPull(env *Env, args []string) error {
if len(args) > 1 {
return errors.New("Only pulling from one remote at a time is supported")
}
@@ -21,45 +35,33 @@ func runPull(cmd *cobra.Command, args []string) error {
remote = args[0]
}
- backend, err := cache.NewRepoCache(repo)
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
defer backend.Close()
interrupt.RegisterCleaner(backend.Close)
- fmt.Println("Fetching remote ...")
+ env.out.Println("Fetching remote ...")
stdout, err := backend.Fetch(remote)
if err != nil {
return err
}
- fmt.Println(stdout)
+ env.out.Println(stdout)
- fmt.Println("Merging data ...")
+ env.out.Println("Merging data ...")
for result := range backend.MergeAll(remote) {
if result.Err != nil {
- fmt.Println(result.Err)
+ env.err.Println(result.Err)
}
if result.Status != entity.MergeStatusNothing {
- fmt.Printf("%s: %s\n", result.Id.Human(), result)
+ env.out.Printf("%s: %s\n", result.Id.Human(), result)
}
}
return nil
}
-
-// showCmd defines the "push" subcommand.
-var pullCmd = &cobra.Command{
- Use: "pull [<remote>]",
- Short: "Pull bugs update from a git remote.",
- PreRunE: loadRepo,
- RunE: runPull,
-}
-
-func init() {
- RootCmd.AddCommand(pullCmd)
-}
diff --git a/commands/push.go b/commands/push.go
index 8f67d3c0..fee8a50d 100644
--- a/commands/push.go
+++ b/commands/push.go
@@ -2,14 +2,29 @@ package commands
import (
"errors"
- "fmt"
+
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runPush(cmd *cobra.Command, args []string) error {
+func newPushCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "push [<remote>]",
+ Short: "Push bugs update to a git remote.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runPush(env, args)
+ },
+ }
+
+ return cmd
+}
+
+func runPush(env *Env, args []string) error {
if len(args) > 1 {
return errors.New("Only pushing to one remote at a time is supported")
}
@@ -19,7 +34,7 @@ func runPush(cmd *cobra.Command, args []string) error {
remote = args[0]
}
- backend, err := cache.NewRepoCache(repo)
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -31,19 +46,7 @@ func runPush(cmd *cobra.Command, args []string) error {
return err
}
- fmt.Println(stdout)
+ env.out.Println(stdout)
return nil
}
-
-// showCmd defines the "push" subcommand.
-var pushCmd = &cobra.Command{
- Use: "push [<remote>]",
- Short: "Push bugs update to a git remote.",
- PreRunE: loadRepo,
- RunE: runPush,
-}
-
-func init() {
- RootCmd.AddCommand(pushCmd)
-}
diff --git a/commands/root.go b/commands/root.go
index 2ea95d4b..42859d19 100644
--- a/commands/root.go
+++ b/commands/root.go
@@ -14,14 +14,16 @@ import (
const rootCommandName = "git-bug"
-// package scoped var to hold the repo after the PreRun execution
-var repo repository.ClockedRepo
+// These variables are initialized externally during the build. See the Makefile.
+var GitCommit string
+var GitLastTag string
+var GitExactTag string
-// RootCmd represents the base command when called without any subcommands
-var RootCmd = &cobra.Command{
- Use: rootCommandName,
- Short: "A bug tracker embedded in Git.",
- Long: `git-bug is a bug tracker embedded in git.
+func NewRootCommand() *cobra.Command {
+ cmd := &cobra.Command{
+ Use: 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
history. As bugs are regular git objects, they can be pushed and pulled from/to
@@ -29,65 +31,104 @@ the same git remote you are already using to collaborate with other people.
`,
- // For the root command, force the execution of the PreRun
- // even if we just display the help. This is to make sure that we check
- // the repository and give the user early feedback.
- Run: func(cmd *cobra.Command, args []string) {
- if err := cmd.Help(); err != nil {
- os.Exit(1)
- }
- },
-
- SilenceUsage: true,
- DisableAutoGenTag: true,
-
- // Custom bash code to connect the git completion for "git bug" to the
- // git-bug completion for "git-bug"
- BashCompletionFunction: `
+ PersistentPreRun: func(cmd *cobra.Command, args []string) {
+ root := cmd.Root()
+
+ if GitExactTag == "undefined" {
+ GitExactTag = ""
+ }
+ root.Version = GitLastTag
+ if GitExactTag == "" {
+ root.Version = fmt.Sprintf("%s-dev-%.10s", root.Version, GitCommit)
+ }
+ },
+
+ // For the root command, force the execution of the PreRun
+ // even if we just display the help. This is to make sure that we check
+ // the repository and give the user early feedback.
+ Run: func(cmd *cobra.Command, args []string) {
+ if err := cmd.Help(); err != nil {
+ os.Exit(1)
+ }
+ },
+
+ SilenceUsage: true,
+ DisableAutoGenTag: true,
+
+ // Custom bash code to connect the git completion for "git bug" to the
+ // git-bug completion for "git-bug"
+ BashCompletionFunction: `
_git_bug() {
__start_git-bug "$@"
}
`,
+ }
+
+ cmd.AddCommand(newAddCommand())
+ cmd.AddCommand(newBridgeCommand())
+ 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(newSelectCommand())
+ cmd.AddCommand(newShowCommand())
+ cmd.AddCommand(newStatusCommand())
+ cmd.AddCommand(newTermUICommand())
+ cmd.AddCommand(newTitleCommand())
+ cmd.AddCommand(newUserCommand())
+ cmd.AddCommand(newVersionCommand())
+ cmd.AddCommand(newWebUICommand())
+
+ return cmd
}
func Execute() {
- if err := RootCmd.Execute(); err != nil {
+ if err := NewRootCommand().Execute(); err != nil {
os.Exit(1)
}
}
// loadRepo is a pre-run function that load the repository for use in a command
-func loadRepo(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)
- }
+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)
+ }
- repo, err = repository.NewGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader})
- if err == repository.ErrNotARepo {
- return fmt.Errorf("%s must be run from within a git repo", rootCommandName)
- }
+ env.repo, err = repository.NewGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader})
+ if err == repository.ErrNotARepo {
+ return fmt.Errorf("%s must be run from within a git repo", rootCommandName)
+ }
- if err != nil {
- return err
- }
+ if err != nil {
+ return err
+ }
- return nil
+ return nil
+ }
}
// 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(cmd *cobra.Command, args []string) error {
- err := loadRepo(cmd, args)
- if err != nil {
- return err
- }
+func loadRepoEnsureUser(env *Env) func(*cobra.Command, []string) error {
+ return func(cmd *cobra.Command, args []string) error {
+ err := loadRepo(env)(cmd, args)
+ if err != nil {
+ return err
+ }
- _, err = identity.GetUserIdentity(repo)
- if err != nil {
- return err
- }
+ _, err = identity.GetUserIdentity(env.repo)
+ if err != nil {
+ return err
+ }
- return nil
+ return nil
+ }
}
diff --git a/commands/select.go b/commands/select.go
index f2ae33ca..e4916650 100644
--- a/commands/select.go
+++ b/commands/select.go
@@ -2,7 +2,6 @@ package commands
import (
"errors"
- "fmt"
"github.com/spf13/cobra"
@@ -11,12 +10,40 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runSelect(cmd *cobra.Command, args []string) error {
+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: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runSelect(env, args)
+ },
+ }
+
+ return cmd
+}
+
+func runSelect(env *Env, args []string) error {
if len(args) == 0 {
return errors.New("You must provide a bug id")
}
- backend, err := cache.NewRepoCache(repo)
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -35,32 +62,7 @@ func runSelect(cmd *cobra.Command, args []string) error {
return err
}
- fmt.Printf("selected bug %s: %s\n", b.Id().Human(), b.Snapshot().Title)
+ env.out.Printf("selected bug %s: %s\n", b.Id().Human(), b.Snapshot().Title)
return nil
}
-
-var selectCmd = &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: loadRepo,
- RunE: runSelect,
-}
-
-func init() {
- RootCmd.AddCommand(selectCmd)
- selectCmd.Flags().SortFlags = false
-}
diff --git a/commands/show.go b/commands/show.go
index 2f4e46ed..9e6a8e8c 100644
--- a/commands/show.go
+++ b/commands/show.go
@@ -15,13 +15,37 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-var (
- showFieldsQuery string
- showOutputFormat string
-)
+type showOptions struct {
+ query string
+ format string
+}
+
+func newShowCommand() *cobra.Command {
+ env := newEnv()
+ options := showOptions{}
+
+ cmd := &cobra.Command{
+ Use: "show [<id>]",
+ Short: "Display the details of a bug.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runShow(env, options, args)
+ },
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
-func runShowBug(_ *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+ flags.StringVarP(&options.query, "field", "", "",
+ "Select field to display. Valid values are [author,authorEmail,createTime,lastEdit,humanId,id,labels,shortId,status,title,actors,participants]")
+ 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 {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -33,77 +57,77 @@ func runShowBug(_ *cobra.Command, args []string) error {
return err
}
- snapshot := b.Snapshot()
+ snap := b.Snapshot()
- if len(snapshot.Comments) == 0 {
+ if len(snap.Comments) == 0 {
return errors.New("invalid bug: no comment")
}
- if showFieldsQuery != "" {
- switch showFieldsQuery {
+ if opts.query != "" {
+ switch opts.query {
case "author":
- fmt.Printf("%s\n", snapshot.Author.DisplayName())
+ env.out.Printf("%s\n", snap.Author.DisplayName())
case "authorEmail":
- fmt.Printf("%s\n", snapshot.Author.Email())
+ env.out.Printf("%s\n", snap.Author.Email())
case "createTime":
- fmt.Printf("%s\n", snapshot.CreateTime.String())
+ env.out.Printf("%s\n", snap.CreateTime.String())
case "lastEdit":
- fmt.Printf("%s\n", snapshot.EditTime().String())
+ env.out.Printf("%s\n", snap.EditTime().String())
case "humanId":
- fmt.Printf("%s\n", snapshot.Id().Human())
+ env.out.Printf("%s\n", snap.Id().Human())
case "id":
- fmt.Printf("%s\n", snapshot.Id())
+ env.out.Printf("%s\n", snap.Id())
case "labels":
- for _, l := range snapshot.Labels {
- fmt.Printf("%s\n", l.String())
+ for _, l := range snap.Labels {
+ env.out.Printf("%s\n", l.String())
}
case "actors":
- for _, a := range snapshot.Actors {
- fmt.Printf("%s\n", a.DisplayName())
+ for _, a := range snap.Actors {
+ env.out.Printf("%s\n", a.DisplayName())
}
case "participants":
- for _, p := range snapshot.Participants {
- fmt.Printf("%s\n", p.DisplayName())
+ for _, p := range snap.Participants {
+ env.out.Printf("%s\n", p.DisplayName())
}
case "shortId":
- fmt.Printf("%s\n", snapshot.Id().Human())
+ env.out.Printf("%s\n", snap.Id().Human())
case "status":
- fmt.Printf("%s\n", snapshot.Status)
+ env.out.Printf("%s\n", snap.Status)
case "title":
- fmt.Printf("%s\n", snapshot.Title)
+ env.out.Printf("%s\n", snap.Title)
default:
- return fmt.Errorf("\nUnsupported field: %s\n", showFieldsQuery)
+ return fmt.Errorf("\nUnsupported field: %s\n", opts.query)
}
return nil
}
- switch showOutputFormat {
+ switch opts.format {
case "org-mode":
- return showOrgmodeFormatter(snapshot)
+ return showOrgModeFormatter(env, snap)
case "json":
- return showJsonFormatter(snapshot)
+ return showJsonFormatter(env, snap)
case "default":
- return showDefaultFormatter(snapshot)
+ return showDefaultFormatter(env, snap)
default:
- return fmt.Errorf("unknown format %s", showOutputFormat)
+ return fmt.Errorf("unknown format %s", opts.format)
}
}
-func showDefaultFormatter(snapshot *bug.Snapshot) error {
+func showDefaultFormatter(env *Env, snapshot *bug.Snapshot) error {
// Header
- fmt.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,
)
- fmt.Printf("%s opened this issue %s\n",
+ env.out.Printf("%s opened this issue %s\n",
colors.Magenta(snapshot.Author.DisplayName()),
snapshot.CreateTime.String(),
)
- fmt.Printf("This was last edited at %s\n\n",
+ env.out.Printf("This was last edited at %s\n\n",
snapshot.EditTime().String(),
)
@@ -113,7 +137,7 @@ func showDefaultFormatter(snapshot *bug.Snapshot) error {
labels[i] = string(snapshot.Labels[i])
}
- fmt.Printf("labels: %s\n",
+ env.out.Printf("labels: %s\n",
strings.Join(labels, ", "),
)
@@ -123,7 +147,7 @@ func showDefaultFormatter(snapshot *bug.Snapshot) error {
actors[i] = snapshot.Actors[i].DisplayName()
}
- fmt.Printf("actors: %s\n",
+ env.out.Printf("actors: %s\n",
strings.Join(actors, ", "),
)
@@ -133,7 +157,7 @@ func showDefaultFormatter(snapshot *bug.Snapshot) error {
participants[i] = snapshot.Participants[i].DisplayName()
}
- fmt.Printf("participants: %s\n\n",
+ env.out.Printf("participants: %s\n\n",
strings.Join(participants, ", "),
)
@@ -142,7 +166,7 @@ func showDefaultFormatter(snapshot *bug.Snapshot) error {
for i, comment := range snapshot.Comments {
var message string
- fmt.Printf("%s#%d %s <%s>\n\n",
+ env.out.Printf("%s#%d %s <%s>\n\n",
indent,
i,
comment.Author.DisplayName(),
@@ -155,7 +179,7 @@ func showDefaultFormatter(snapshot *bug.Snapshot) error {
message = comment.Message
}
- fmt.Printf("%s%s\n\n\n",
+ env.out.Printf("%s%s\n\n\n",
indent,
message,
)
@@ -194,7 +218,7 @@ func NewJSONComment(comment bug.Comment) JSONComment {
}
}
-func showJsonFormatter(snapshot *bug.Snapshot) error {
+func showJsonFormatter(env *Env, snapshot *bug.Snapshot) error {
jsonBug := JSONBugSnapshot{
Id: snapshot.Id().String(),
HumanId: snapshot.Id().Human(),
@@ -222,28 +246,28 @@ func showJsonFormatter(snapshot *bug.Snapshot) error {
}
jsonObject, _ := json.MarshalIndent(jsonBug, "", " ")
- fmt.Printf("%s\n", jsonObject)
+ env.out.Printf("%s\n", jsonObject)
return nil
}
-func showOrgmodeFormatter(snapshot *bug.Snapshot) error {
+func showOrgModeFormatter(env *Env, snapshot *bug.Snapshot) error {
// Header
- fmt.Printf("%s [%s] %s\n",
+ env.out.Printf("%s [%s] %s\n",
snapshot.Id().Human(),
snapshot.Status,
snapshot.Title,
)
- fmt.Printf("* Author: %s\n",
+ env.out.Printf("* Author: %s\n",
snapshot.Author.DisplayName(),
)
- fmt.Printf("* Creation Time: %s\n",
+ env.out.Printf("* Creation Time: %s\n",
snapshot.CreateTime.String(),
)
- fmt.Printf("* Last Edit: %s\n",
+ env.out.Printf("* Last Edit: %s\n",
snapshot.EditTime().String(),
)
@@ -253,9 +277,9 @@ func showOrgmodeFormatter(snapshot *bug.Snapshot) error {
labels[i] = string(label)
}
- fmt.Printf("* Labels:\n")
+ env.out.Printf("* Labels:\n")
if len(labels) > 0 {
- fmt.Printf("** %s\n",
+ env.out.Printf("** %s\n",
strings.Join(labels, "\n** "),
)
}
@@ -269,7 +293,7 @@ func showOrgmodeFormatter(snapshot *bug.Snapshot) error {
)
}
- fmt.Printf("* Actors:\n** %s\n",
+ env.out.Printf("* Actors:\n** %s\n",
strings.Join(actors, "\n** "),
)
@@ -282,18 +306,16 @@ func showOrgmodeFormatter(snapshot *bug.Snapshot) error {
)
}
- fmt.Printf("* Participants:\n** %s\n",
+ env.out.Printf("* Participants:\n** %s\n",
strings.Join(participants, "\n** "),
)
- fmt.Printf("* Comments:\n")
+ env.out.Printf("* Comments:\n")
for i, comment := range snapshot.Comments {
var message string
- fmt.Printf("** #%d %s\n",
- i,
- comment.Author.DisplayName(),
- )
+ env.out.Printf("** #%d %s\n",
+ i, comment.Author.DisplayName())
if comment.Message == "" {
message = "No description provided."
@@ -301,25 +323,8 @@ func showOrgmodeFormatter(snapshot *bug.Snapshot) error {
message = strings.ReplaceAll(comment.Message, "\n", "\n: ")
}
- fmt.Printf(": %s\n",
- message,
- )
+ env.out.Printf(": %s\n", message)
}
return nil
}
-
-var showCmd = &cobra.Command{
- Use: "show [<id>]",
- Short: "Display the details of a bug.",
- PreRunE: loadRepo,
- RunE: runShowBug,
-}
-
-func init() {
- RootCmd.AddCommand(showCmd)
- showCmd.Flags().StringVarP(&showFieldsQuery, "field", "", "",
- "Select field to display. Valid values are [author,authorEmail,createTime,lastEdit,humanId,id,labels,shortId,status,title,actors,participants]")
- showCmd.Flags().StringVarP(&showOutputFormat, "format", "f", "default",
- "Select the output formatting style. Valid values are [default,json,org-mode]")
-}
diff --git a/commands/status.go b/commands/status.go
index 4675195d..aaf9e636 100644
--- a/commands/status.go
+++ b/commands/status.go
@@ -1,16 +1,33 @@
package commands
import (
- "fmt"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runStatus(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newStatusCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "status [<id>]",
+ Short: "Display or change a bug status.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runStatus(env, args)
+ },
+ }
+
+ cmd.AddCommand(newStatusCloseCommand())
+ cmd.AddCommand(newStatusOpenCommand())
+
+ return cmd
+}
+
+func runStatus(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -24,18 +41,7 @@ func runStatus(cmd *cobra.Command, args []string) error {
snap := b.Snapshot()
- fmt.Println(snap.Status)
+ env.out.Println(snap.Status)
return nil
}
-
-var statusCmd = &cobra.Command{
- Use: "status [<id>]",
- Short: "Display or change a bug status.",
- PreRunE: loadRepo,
- RunE: runStatus,
-}
-
-func init() {
- RootCmd.AddCommand(statusCmd)
-}
diff --git a/commands/status_close.go b/commands/status_close.go
index 08c67e87..2c7079e6 100644
--- a/commands/status_close.go
+++ b/commands/status_close.go
@@ -1,14 +1,30 @@
package commands
import (
+ "github.com/spf13/cobra"
+
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runStatusClose(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newStatusCloseCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "close [<id>]",
+ Short: "Mark a bug as closed.",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runStatusClose(env, args)
+ },
+ }
+
+ return cmd
+}
+
+func runStatusClose(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -27,14 +43,3 @@ func runStatusClose(cmd *cobra.Command, args []string) error {
return b.Commit()
}
-
-var closeCmd = &cobra.Command{
- Use: "close [<id>]",
- Short: "Mark a bug as closed.",
- PreRunE: loadRepoEnsureUser,
- RunE: runStatusClose,
-}
-
-func init() {
- statusCmd.AddCommand(closeCmd)
-}
diff --git a/commands/status_open.go b/commands/status_open.go
index 1b1c426e..ff98fa33 100644
--- a/commands/status_open.go
+++ b/commands/status_open.go
@@ -1,14 +1,30 @@
package commands
import (
+ "github.com/spf13/cobra"
+
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runStatusOpen(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newStatusOpenCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "open [<id>]",
+ Short: "Mark a bug as open.",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runStatusOpen(env, args)
+ },
+ }
+
+ return cmd
+}
+
+func runStatusOpen(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -27,14 +43,3 @@ func runStatusOpen(cmd *cobra.Command, args []string) error {
return b.Commit()
}
-
-var openCmd = &cobra.Command{
- Use: "open [<id>]",
- Short: "Mark a bug as open.",
- PreRunE: loadRepoEnsureUser,
- RunE: runStatusOpen,
-}
-
-func init() {
- statusCmd.AddCommand(openCmd)
-}
diff --git a/commands/termui.go b/commands/termui.go
index 2cdc3507..174d60ec 100644
--- a/commands/termui.go
+++ b/commands/termui.go
@@ -1,14 +1,31 @@
package commands
import (
+ "github.com/spf13/cobra"
+
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/termui"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runTermUI(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newTermUICommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "termui",
+ Aliases: []string{"tui"},
+ Short: "Launch the terminal UI.",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runTermUI(env)
+ },
+ }
+
+ return cmd
+}
+
+func runTermUI(env *Env) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -17,15 +34,3 @@ func runTermUI(cmd *cobra.Command, args []string) error {
return termui.Run(backend)
}
-
-var termUICmd = &cobra.Command{
- Use: "termui",
- Aliases: []string{"tui"},
- Short: "Launch the terminal UI.",
- PreRunE: loadRepoEnsureUser,
- RunE: runTermUI,
-}
-
-func init() {
- RootCmd.AddCommand(termUICmd)
-}
diff --git a/commands/title.go b/commands/title.go
index 66a9de7a..c1a0e7fb 100644
--- a/commands/title.go
+++ b/commands/title.go
@@ -1,16 +1,32 @@
package commands
import (
- "fmt"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runTitle(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newTitleCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "title [<id>]",
+ Short: "Display or change a title of a bug.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runTitle(env, args)
+ },
+ }
+
+ cmd.AddCommand(newTitleEditCommand())
+
+ return cmd
+}
+
+func runTitle(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -24,20 +40,7 @@ func runTitle(cmd *cobra.Command, args []string) error {
snap := b.Snapshot()
- fmt.Println(snap.Title)
+ env.out.Println(snap.Title)
return nil
}
-
-var titleCmd = &cobra.Command{
- Use: "title [<id>]",
- Short: "Display or change a title of a bug.",
- PreRunE: loadRepo,
- RunE: runTitle,
-}
-
-func init() {
- RootCmd.AddCommand(titleCmd)
-
- titleCmd.Flags().SortFlags = false
-}
diff --git a/commands/title_edit.go b/commands/title_edit.go
index 3e40bd9e..853622cd 100644
--- a/commands/title_edit.go
+++ b/commands/title_edit.go
@@ -1,21 +1,43 @@
package commands
import (
- "fmt"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/commands/select"
"github.com/MichaelMure/git-bug/input"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-var (
- titleEditTitle string
-)
+type titleEditOptions struct {
+ title string
+}
+
+func newTitleEditCommand() *cobra.Command {
+ env := newEnv()
+ options := titleEditOptions{}
+
+ cmd := &cobra.Command{
+ Use: "edit [<id>]",
+ Short: "Edit a title of a bug.",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runTitleEdit(env, options, args)
+ },
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.StringVarP(&options.title, "title", "t", "",
+ "Provide a title to describe the issue",
+ )
-func runTitleEdit(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+ return cmd
+}
+
+func runTitleEdit(env *Env, opts titleEditOptions, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -29,10 +51,10 @@ func runTitleEdit(cmd *cobra.Command, args []string) error {
snap := b.Snapshot()
- if titleEditTitle == "" {
- titleEditTitle, err = input.BugTitleEditorInput(repo, snap.Title)
+ if opts.title == "" {
+ opts.title, err = input.BugTitleEditorInput(env.repo, snap.Title)
if err == input.ErrEmptyTitle {
- fmt.Println("Empty title, aborting.")
+ env.out.Println("Empty title, aborting.")
return nil
}
if err != nil {
@@ -40,31 +62,14 @@ func runTitleEdit(cmd *cobra.Command, args []string) error {
}
}
- if titleEditTitle == snap.Title {
- fmt.Println("No change, aborting.")
+ if opts.title == snap.Title {
+ env.err.Println("No change, aborting.")
}
- _, err = b.SetTitle(titleEditTitle)
+ _, err = b.SetTitle(opts.title)
if err != nil {
return err
}
return b.Commit()
}
-
-var titleEditCmd = &cobra.Command{
- Use: "edit [<id>]",
- Short: "Edit a title of a bug.",
- PreRunE: loadRepoEnsureUser,
- RunE: runTitleEdit,
-}
-
-func init() {
- titleCmd.AddCommand(titleEditCmd)
-
- titleEditCmd.Flags().SortFlags = false
-
- titleEditCmd.Flags().StringVarP(&titleEditTitle, "title", "t", "",
- "Provide a title to describe the issue",
- )
-}
diff --git a/commands/user.go b/commands/user.go
index 2888e131..35e00a7c 100644
--- a/commands/user.go
+++ b/commands/user.go
@@ -10,12 +10,38 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-var (
- userFieldsQuery string
-)
+type userOptions struct {
+ fieldsQuery string
+}
+
+func newUserCommand() *cobra.Command {
+ env := newEnv()
+ options := userOptions{}
+
+ cmd := &cobra.Command{
+ Use: "user [<user-id>]",
+ Short: "Display or change the user identity.",
+ PreRunE: loadRepoEnsureUser(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runUser(env, options, args)
+ },
+ }
+
+ cmd.AddCommand(newUserAdoptCommand())
+ cmd.AddCommand(newUserCreateCommand())
+ cmd.AddCommand(newUserLsCommand())
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.StringVarP(&options.fieldsQuery, "field", "f", "",
+ "Select field to display. Valid values are [email,humanId,id,lastModification,lastModificationLamport,login,metadata,name]")
-func runUser(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+ return cmd
+}
+
+func runUser(env *Env, opts userOptions, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -37,62 +63,47 @@ func runUser(cmd *cobra.Command, args []string) error {
return err
}
- if userFieldsQuery != "" {
- switch userFieldsQuery {
+ if opts.fieldsQuery != "" {
+ switch opts.fieldsQuery {
case "email":
- fmt.Printf("%s\n", id.Email())
+ env.out.Printf("%s\n", id.Email())
case "login":
- fmt.Printf("%s\n", id.Login())
+ env.out.Printf("%s\n", id.Login())
case "humanId":
- fmt.Printf("%s\n", id.Id().Human())
+ env.out.Printf("%s\n", id.Id().Human())
case "id":
- fmt.Printf("%s\n", id.Id())
+ env.out.Printf("%s\n", id.Id())
case "lastModification":
- fmt.Printf("%s\n", id.LastModification().
+ env.out.Printf("%s\n", id.LastModification().
Time().Format("Mon Jan 2 15:04:05 2006 +0200"))
case "lastModificationLamport":
- fmt.Printf("%d\n", id.LastModificationLamport())
+ env.out.Printf("%d\n", id.LastModificationLamport())
case "metadata":
for key, value := range id.ImmutableMetadata() {
- fmt.Printf("%s\n%s\n", key, value)
+ env.out.Printf("%s\n%s\n", key, value)
}
case "name":
- fmt.Printf("%s\n", id.Name())
+ env.out.Printf("%s\n", id.Name())
default:
- return fmt.Errorf("\nUnsupported field: %s\n", userFieldsQuery)
+ return fmt.Errorf("\nUnsupported field: %s\n", opts.fieldsQuery)
}
return nil
}
- fmt.Printf("Id: %s\n", id.Id())
- fmt.Printf("Name: %s\n", id.Name())
- fmt.Printf("Email: %s\n", id.Email())
- fmt.Printf("Login: %s\n", id.Login())
- fmt.Printf("Last modification: %s (lamport %d)\n",
+ 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 (lamport %d)\n",
id.LastModification().Time().Format("Mon Jan 2 15:04:05 2006 +0200"),
id.LastModificationLamport())
- fmt.Println("Metadata:")
+ env.out.Println("Metadata:")
for key, value := range id.ImmutableMetadata() {
- fmt.Printf(" %s --> %s\n", key, value)
+ env.out.Printf(" %s --> %s\n", key, value)
}
- // fmt.Printf("Protected: %v\n", id.IsProtected())
+ // env.out.Printf("Protected: %v\n", id.IsProtected())
return nil
}
-
-var userCmd = &cobra.Command{
- Use: "user [<user-id>]",
- Short: "Display or change the user identity.",
- PreRunE: loadRepoEnsureUser,
- RunE: runUser,
-}
-
-func init() {
- RootCmd.AddCommand(userCmd)
- userCmd.Flags().SortFlags = false
-
- userCmd.Flags().StringVarP(&userFieldsQuery, "field", "f", "",
- "Select field to display. Valid values are [email,humanId,id,lastModification,lastModificationLamport,login,metadata,name]")
-}
diff --git a/commands/user_adopt.go b/commands/user_adopt.go
index 7054f1f7..0eb8b467 100644
--- a/commands/user_adopt.go
+++ b/commands/user_adopt.go
@@ -1,17 +1,30 @@
package commands
import (
- "fmt"
- "os"
-
"github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/util/interrupt"
)
-func runUserAdopt(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+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: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runUserAdopt(env, args)
+ },
+ }
+
+ return cmd
+}
+
+func runUserAdopt(env *Env, args []string) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -30,20 +43,7 @@ func runUserAdopt(cmd *cobra.Command, args []string) error {
return err
}
- _, _ = fmt.Fprintf(os.Stderr, "Your identity is now: %s\n", i.DisplayName())
+ env.out.Printf("Your identity is now: %s\n", i.DisplayName())
return nil
}
-
-var userAdoptCmd = &cobra.Command{
- Use: "adopt <user-id>",
- Short: "Adopt an existing identity as your own.",
- PreRunE: loadRepo,
- RunE: runUserAdopt,
- Args: cobra.ExactArgs(1),
-}
-
-func init() {
- userCmd.AddCommand(userAdoptCmd)
- userAdoptCmd.Flags().SortFlags = false
-}
diff --git a/commands/user_create.go b/commands/user_create.go
index df4aa8e9..6433d38e 100644
--- a/commands/user_create.go
+++ b/commands/user_create.go
@@ -1,17 +1,30 @@
package commands
import (
- "fmt"
- "os"
+ "github.com/spf13/cobra"
"github.com/MichaelMure/git-bug/cache"
"github.com/MichaelMure/git-bug/input"
"github.com/MichaelMure/git-bug/util/interrupt"
- "github.com/spf13/cobra"
)
-func runUserCreate(cmd *cobra.Command, args []string) error {
- backend, err := cache.NewRepoCache(repo)
+func newUserCreateCommand() *cobra.Command {
+ env := newEnv()
+
+ cmd := &cobra.Command{
+ Use: "create",
+ Short: "Create a new identity.",
+ PreRunE: loadRepo(env),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runUserCreate(env)
+ },
+ }
+
+ return cmd
+}
+
+func runUserCreate(env *Env) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -65,20 +78,8 @@ func runUserCreate(cmd *cobra.Command, args []string) error {
}
}
- _, _ = fmt.Fprintln(os.Stderr)
- fmt.Println(id.Id())
+ env.err.Println()
+ env.out.Println(id.Id())
return nil
}
-
-var userCreateCmd = &cobra.Command{
- Use: "create",
- Short: "Create a new identity.",
- PreRunE: loadRepo,
- RunE: runUserCreate,
-}
-
-func init() {
- userCmd.AddCommand(userCreateCmd)
- userCreateCmd.Flags().SortFlags = false
-}
diff --git a/commands/user_ls.go b/commands/user_ls.go
index b3fb32e6..5087ebd4 100644
--- a/commands/user_ls.go
+++ b/commands/user_ls.go
@@ -11,12 +11,34 @@ import (
"github.com/MichaelMure/git-bug/util/interrupt"
)
-var (
- userLsOutputFormat string
-)
+type userLsOptions struct {
+ format string
+}
+
+func newUserLsCommand() *cobra.Command {
+ env := newEnv()
+ options := userLsOptions{}
+
+ cmd := &cobra.Command{
+ Use: "ls",
+ Short: "List identities.",
+ PreRunE: loadRepo(env),
+ RunE: 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]")
-func runUserLs(_ *cobra.Command, _ []string) error {
- backend, err := cache.NewRepoCache(repo)
+ return cmd
+}
+
+func runUserLs(env *Env, opts userLsOptions) error {
+ backend, err := cache.NewRepoCache(env.repo)
if err != nil {
return err
}
@@ -33,19 +55,19 @@ func runUserLs(_ *cobra.Command, _ []string) error {
users = append(users, user)
}
- switch userLsOutputFormat {
+ switch opts.format {
case "json":
- return userLsJsonFormatter(users)
+ return userLsJsonFormatter(env, users)
case "default":
- return userLsDefaultFormatter(users)
+ return userLsDefaultFormatter(env, users)
default:
- return fmt.Errorf("unknown format %s", userLsOutputFormat)
+ return fmt.Errorf("unknown format %s", opts.format)
}
}
-func userLsDefaultFormatter(users []*cache.IdentityExcerpt) error {
+func userLsDefaultFormatter(env *Env, users []*cache.IdentityExcerpt) error {
for _, user := range users {
- fmt.Printf("%s %s\n",
+ env.out.Printf("%s %s\n",
colors.Cyan(user.Id.Human()),
user.DisplayName(),
)
@@ -54,27 +76,13 @@ func userLsDefaultFormatter(users []*cache.IdentityExcerpt) error {
return nil
}
-func userLsJsonFormatter(users []*cache.IdentityExcerpt) error {
+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, "", " ")
- fmt.Printf("%s\n", jsonObject)
+ env.out.Printf("%s\n", jsonObject)
return nil
}
-
-var userLsCmd = &cobra.Command{
- Use: "ls",
- Short: "List identities.",
- PreRunE: loadRepo,
- RunE: runUserLs,
-}
-
-func init() {
- userCmd.AddCommand(userLsCmd)
- userLsCmd.Flags().SortFlags = false
- userLsCmd.Flags().StringVarP(&userLsOutputFormat, "format", "f", "default",
- "Select the output formatting style. Valid values are [default,json]")
-}
diff --git a/commands/version.go b/commands/version.go
index 668c37fe..71baba40 100644
--- a/commands/version.go
+++ b/commands/version.go
@@ -1,71 +1,62 @@
package commands
import (
- "fmt"
"runtime"
"github.com/spf13/cobra"
)
-// These variables are initialized externally during the build. See the Makefile.
-var GitCommit string
-var GitLastTag string
-var GitExactTag string
+type versionOptions struct {
+ number bool
+ commit bool
+ all bool
+}
-var (
- versionNumber bool
- versionCommit bool
- versionAll bool
-)
+func newVersionCommand() *cobra.Command {
+ env := newEnv()
+ options := versionOptions{}
-func runVersionCmd(cmd *cobra.Command, args []string) {
- if versionAll {
- fmt.Printf("%s version: %s\n", rootCommandName, RootCmd.Version)
- fmt.Printf("System version: %s/%s\n", runtime.GOARCH, runtime.GOOS)
- fmt.Printf("Golang version: %s\n", runtime.Version())
- return
+ cmd := &cobra.Command{
+ Use: "version",
+ Short: "Show git-bug version information.",
+ Run: func(cmd *cobra.Command, args []string) {
+ runVersion(env, options, cmd.Root())
+ },
}
- if versionNumber {
- fmt.Println(RootCmd.Version)
- return
- }
+ flags := cmd.Flags()
+ flags.SortFlags = false
- if versionCommit {
- fmt.Println(GitCommit)
- return
- }
-
- fmt.Printf("%s version: %s\n", rootCommandName, RootCmd.Version)
-}
+ flags.BoolVarP(&options.number, "number", "n", false,
+ "Only show the version number",
+ )
+ flags.BoolVarP(&options.commit, "commit", "c", false,
+ "Only show the commit hash",
+ )
+ flags.BoolVarP(&options.all, "all", "a", false,
+ "Show all version information",
+ )
-var versionCmd = &cobra.Command{
- Use: "version",
- Short: "Show git-bug version information.",
- Run: runVersionCmd,
+ return cmd
}
-func init() {
- if GitExactTag == "undefined" {
- GitExactTag = ""
+func runVersion(env *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())
+ return
}
- RootCmd.Version = GitLastTag
-
- if GitExactTag == "" {
- RootCmd.Version = fmt.Sprintf("%s-dev-%.10s", RootCmd.Version, GitCommit)
+ if opts.number {
+ env.out.Println(root.Version)
+ return
}
- RootCmd.AddCommand(versionCmd)
- versionCmd.Flags().SortFlags = false
+ if opts.commit {
+ env.out.Println(GitCommit)
+ return
+ }
- versionCmd.Flags().BoolVarP(&versionNumber, "number", "n", false,
- "Only show the version number",
- )
- versionCmd.Flags().BoolVarP(&versionCommit, "commit", "c", false,
- "Only show the commit hash",
- )
- versionCmd.Flags().BoolVarP(&versionAll, "all", "a", false,
- "Show all version information",
- )
+ env.out.Printf("%s version: %s\n", rootCommandName, root.Version)
}
diff --git a/commands/webui.go b/commands/webui.go
index 83480e08..4d87a303 100644
--- a/commands/webui.go
+++ b/commands/webui.go
@@ -24,25 +24,54 @@ import (
"github.com/MichaelMure/git-bug/webui"
)
-var (
- webUIPort int
- webUIOpen bool
- webUINoOpen bool
- webUIReadOnly bool
-)
-
const webUIOpenConfigKey = "git-bug.webui.open"
-func runWebUI(cmd *cobra.Command, args []string) error {
- if webUIPort == 0 {
+type webUIOptions struct {
+ port int
+ open bool
+ noOpen bool
+ readOnly bool
+}
+
+func newWebUICommand() *cobra.Command {
+ env := newEnv()
+ options := webUIOptions{}
+
+ cmd := &cobra.Command{
+ Use: "webui",
+ 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),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return runWebUI(env, options, args)
+ },
+ }
+
+ flags := cmd.Flags()
+ flags.SortFlags = false
+
+ flags.BoolVar(&options.open, "open", false, "Automatically open the web UI in the default browser")
+ flags.BoolVar(&options.noOpen, "no-open", false, "Prevent the automatic opening of the web UI in the default browser")
+ flags.IntVarP(&options.port, "port", "p", 0, "Port to listen to (default is random)")
+ flags.BoolVar(&options.readOnly, "read-only", false, "Whether to run the web UI in read-only mode")
+
+ return cmd
+}
+
+func runWebUI(env *Env, opts webUIOptions, args []string) error {
+ if opts.port == 0 {
var err error
- webUIPort, err = freeport.GetFreePort()
+ opts.port, err = freeport.GetFreePort()
if err != nil {
return err
}
}
- addr := fmt.Sprintf("127.0.0.1:%d", webUIPort)
+ addr := fmt.Sprintf("127.0.0.1:%d", opts.port)
webUiAddr := fmt.Sprintf("http://%s", addr)
router := mux.NewRouter()
@@ -50,8 +79,8 @@ func runWebUI(cmd *cobra.Command, args []string) error {
// If the webUI is not read-only, use an authentication middleware with a
// fixed identity: the default user of the repo
// TODO: support dynamic authentication with OAuth
- if !webUIReadOnly {
- author, err := identity.GetUserIdentity(repo)
+ if !opts.readOnly {
+ author, err := identity.GetUserIdentity(env.repo)
if err != nil {
return err
}
@@ -59,7 +88,7 @@ func runWebUI(cmd *cobra.Command, args []string) error {
}
mrc := cache.NewMultiRepoCache()
- _, err := mrc.RegisterDefaultRepository(repo)
+ _, err := mrc.RegisterDefaultRepository(env.repo)
if err != nil {
return err
}
@@ -86,7 +115,7 @@ func runWebUI(cmd *cobra.Command, args []string) error {
go func() {
<-quit
- fmt.Println("WebUI is shutting down...")
+ env.out.Println("WebUI is shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
@@ -99,18 +128,18 @@ func runWebUI(cmd *cobra.Command, args []string) error {
// Teardown
err := graphqlHandler.Close()
if err != nil {
- fmt.Println(err)
+ env.out.Println(err)
}
close(done)
}()
- fmt.Printf("Web UI: %s\n", webUiAddr)
- fmt.Printf("Graphql API: http://%s/graphql\n", addr)
- fmt.Printf("Graphql Playground: http://%s/playground\n", addr)
- fmt.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 := repo.LocalConfig().ReadBool(webUIOpenConfigKey)
+ configOpen, err := env.repo.LocalConfig().ReadBool(webUIOpenConfigKey)
if err == repository.ErrNoConfigEntry {
// default to true
configOpen = true
@@ -118,12 +147,12 @@ func runWebUI(cmd *cobra.Command, args []string) error {
return err
}
- shouldOpen := (configOpen && !webUINoOpen) || webUIOpen
+ shouldOpen := (configOpen && !opts.noOpen) || opts.open
if shouldOpen {
err = open.Run(webUiAddr)
if err != nil {
- fmt.Println(err)
+ env.out.Println(err)
}
}
@@ -134,29 +163,6 @@ func runWebUI(cmd *cobra.Command, args []string) error {
<-done
- fmt.Println("WebUI stopped")
+ env.out.Println("WebUI stopped")
return nil
}
-
-var webUICmd = &cobra.Command{
- Use: "webui",
- 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,
- RunE: runWebUI,
-}
-
-func init() {
- RootCmd.AddCommand(webUICmd)
-
- webUICmd.Flags().SortFlags = false
-
- webUICmd.Flags().BoolVar(&webUIOpen, "open", false, "Automatically open the web UI in the default browser")
- webUICmd.Flags().BoolVar(&webUINoOpen, "no-open", false, "Prevent the automatic opening of the web UI in the default browser")
- webUICmd.Flags().IntVarP(&webUIPort, "port", "p", 0, "Port to listen to (default is random)")
- webUICmd.Flags().BoolVar(&webUIReadOnly, "read-only", false, "Whether to run the web UI in read-only mode")
-}
diff --git a/doc/gen_docs.go b/doc/gen_docs.go
index 31960b65..83997488 100644
--- a/doc/gen_docs.go
+++ b/doc/gen_docs.go
@@ -62,7 +62,7 @@ func genManPage() error {
}
}
- return doc.GenManTree(commands.RootCmd, header, dir)
+ return doc.GenManTree(commands.NewRootCommand(), header, dir)
}
func genMarkdown() error {
@@ -79,5 +79,5 @@ func genMarkdown() error {
}
}
- return doc.GenMarkdownTree(commands.RootCmd, dir)
+ return doc.GenMarkdownTree(commands.NewRootCommand(), dir)
}
diff --git a/doc/man/git-bug-bridge-pull.1 b/doc/man/git-bug-bridge-pull.1
index 055d2472..4a9e78db 100644
--- a/doc/man/git-bug-bridge-pull.1
+++ b/doc/man/git-bug-bridge-pull.1
@@ -19,10 +19,6 @@ Pull updates.
.SH OPTIONS
.PP
-\fB\-h\fP, \fB\-\-help\fP[=false]
- help for pull
-
-.PP
\fB\-n\fP, \fB\-\-no\-resume\fP[=false]
force importing all bugs
@@ -30,6 +26,10 @@ Pull updates.
\fB\-s\fP, \fB\-\-since\fP=""
import only bugs updated after the given date (ex: "200h" or "june 2 2019")
+.PP
+\fB\-h\fP, \fB\-\-help\fP[=false]
+ help for pull
+
.SH SEE ALSO
.PP
diff --git a/doc/md/git-bug_bridge_pull.md b/doc/md/git-bug_bridge_pull.md
index 9a497c84..fea92b85 100644
--- a/doc/md/git-bug_bridge_pull.md
+++ b/doc/md/git-bug_bridge_pull.md
@@ -13,9 +13,9 @@ git-bug bridge pull [<name>] [flags]
### Options
```
- -h, --help help for pull
-n, --no-resume force importing all bugs
-s, --since string import only bugs updated after the given date (ex: "200h" or "june 2 2019")
+ -h, --help help for pull
```
### SEE ALSO
diff --git a/misc/gen_completion.go b/misc/gen_completion.go
index 0ebb5eeb..80b89902 100644
--- a/misc/gen_completion.go
+++ b/misc/gen_completion.go
@@ -39,23 +39,23 @@ func main() {
func genBash() error {
cwd, _ := os.Getwd()
dir := path.Join(cwd, "misc", "bash_completion", "git-bug")
- return commands.RootCmd.GenBashCompletionFile(dir)
+ return commands.NewRootCommand().GenBashCompletionFile(dir)
}
func genFish() error {
cwd, _ := os.Getwd()
dir := path.Join(cwd, "misc", "fish_completion", "git-bug")
- return commands.RootCmd.GenFishCompletionFile(dir, true)
+ return commands.NewRootCommand().GenFishCompletionFile(dir, true)
}
func genPowerShell() error {
cwd, _ := os.Getwd()
filepath := path.Join(cwd, "misc", "powershell_completion", "git-bug")
- return commands.RootCmd.GenPowerShellCompletionFile(filepath)
+ return commands.NewRootCommand().GenPowerShellCompletionFile(filepath)
}
func genZsh() error {
cwd, _ := os.Getwd()
filepath := path.Join(cwd, "misc", "zsh_completion", "git-bug")
- return commands.RootCmd.GenZshCompletionFile(filepath)
+ return commands.NewRootCommand().GenZshCompletionFile(filepath)
}