root.go

  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}