1// Package commands contains the CLI commands
2package commands
3
4import (
5 "fmt"
6 "os"
7
8 "github.com/spf13/cobra"
9
10 "github.com/MichaelMure/git-bug/bug"
11 "github.com/MichaelMure/git-bug/identity"
12 "github.com/MichaelMure/git-bug/repository"
13)
14
15const rootCommandName = "git-bug"
16
17// These variables are initialized externally during the build. See the Makefile.
18var GitCommit string
19var GitLastTag string
20var GitExactTag string
21
22func NewRootCommand() *cobra.Command {
23 cmd := &cobra.Command{
24 Use: rootCommandName,
25 Short: "A bug tracker embedded in Git.",
26 Long: `git-bug is a bug tracker embedded in git.
27
28git-bug use git objects to store the bug tracking separated from the files
29history. As bugs are regular git objects, they can be pushed and pulled from/to
30the same git remote you are already using to collaborate with other people.
31
32`,
33
34 PersistentPreRun: func(cmd *cobra.Command, args []string) {
35 root := cmd.Root()
36
37 if GitExactTag == "undefined" {
38 GitExactTag = ""
39 }
40 root.Version = GitLastTag
41 if GitExactTag == "" {
42 root.Version = fmt.Sprintf("%s-dev-%.10s", root.Version, GitCommit)
43 }
44 },
45
46 // For the root command, force the execution of the PreRun
47 // even if we just display the help. This is to make sure that we check
48 // the repository and give the user early feedback.
49 Run: func(cmd *cobra.Command, args []string) {
50 if err := cmd.Help(); err != nil {
51 os.Exit(1)
52 }
53 },
54
55 SilenceUsage: true,
56 DisableAutoGenTag: true,
57
58 // Custom bash code to connect the git completion for "git bug" to the
59 // git-bug completion for "git-bug"
60 BashCompletionFunction: `
61_git_bug() {
62 __start_git-bug "$@"
63}
64`,
65 }
66
67 cmd.AddCommand(newAddCommand())
68 cmd.AddCommand(newBridgeCommand())
69 cmd.AddCommand(newCommandsCommand())
70 cmd.AddCommand(newCommentCommand())
71 cmd.AddCommand(newDeselectCommand())
72 cmd.AddCommand(newLabelCommand())
73 cmd.AddCommand(newLsCommand())
74 cmd.AddCommand(newLsIdCommand())
75 cmd.AddCommand(newLsLabelCommand())
76 cmd.AddCommand(newPullCommand())
77 cmd.AddCommand(newPushCommand())
78 cmd.AddCommand(newSelectCommand())
79 cmd.AddCommand(newShowCommand())
80 cmd.AddCommand(newStatusCommand())
81 cmd.AddCommand(newTermUICommand())
82 cmd.AddCommand(newTitleCommand())
83 cmd.AddCommand(newUserCommand())
84 cmd.AddCommand(newVersionCommand())
85 cmd.AddCommand(newWebUICommand())
86
87 return cmd
88}
89
90func Execute() {
91 if err := NewRootCommand().Execute(); err != nil {
92 os.Exit(1)
93 }
94}
95
96// loadRepo is a pre-run function that load the repository for use in a command
97func loadRepo(env *Env) func(*cobra.Command, []string) error {
98 return func(cmd *cobra.Command, args []string) error {
99 cwd, err := os.Getwd()
100 if err != nil {
101 return fmt.Errorf("unable to get the current working directory: %q", err)
102 }
103
104 env.repo, err = repository.NewGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader})
105 if err == repository.ErrNotARepo {
106 return fmt.Errorf("%s must be run from within a git repo", rootCommandName)
107 }
108
109 if err != nil {
110 return err
111 }
112
113 return nil
114 }
115}
116
117// loadRepoEnsureUser is the same as loadRepo, but also ensure that the user has configured
118// an identity. Use this pre-run function when an error after using the configured user won't
119// do.
120func loadRepoEnsureUser(env *Env) func(*cobra.Command, []string) error {
121 return func(cmd *cobra.Command, args []string) error {
122 err := loadRepo(env)(cmd, args)
123 if err != nil {
124 return err
125 }
126
127 _, err = identity.GetUserIdentity(env.repo)
128 if err != nil {
129 return err
130 }
131
132 return nil
133 }
134}