root.go

  1// Package commands contains the CLI commands
  2package commands
  3
  4import (
  5	"fmt"
  6	"os"
  7	"runtime/debug"
  8
  9	"github.com/spf13/cobra"
 10
 11	bridgecmd "github.com/MichaelMure/git-bug/commands/bridge"
 12	bugcmd "github.com/MichaelMure/git-bug/commands/bug"
 13	"github.com/MichaelMure/git-bug/commands/execenv"
 14	usercmd "github.com/MichaelMure/git-bug/commands/user"
 15)
 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:   execenv.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
 41			// release version
 42			root.Version = GitLastTag
 43
 44			// dev version
 45			if GitExactTag == "" {
 46				if root.Version != "" {
 47					// if we have a tag, append the commit hash
 48					root.Version = fmt.Sprintf("%s-dev-%.10s", root.Version, GitCommit)
 49				} else {
 50					// if we don't have a tag, try to read
 51					// commit and dirty state from the build info
 52					commit, dirty := getCommitAndDirty()
 53					root.Version = fmt.Sprintf("dev-%.10s", commit)
 54
 55					if dirty != "" {
 56						root.Version = fmt.Sprintf("%s-dirty", root.Version)
 57					}
 58				}
 59			}
 60		},
 61
 62		// For the root command, force the execution of the PreRun
 63		// even if we just display the help. This is to make sure that we check
 64		// the repository and give the user early feedback.
 65		Run: func(cmd *cobra.Command, args []string) {
 66			if err := cmd.Help(); err != nil {
 67				os.Exit(1)
 68			}
 69		},
 70
 71		SilenceUsage:      true,
 72		DisableAutoGenTag: true,
 73	}
 74
 75	const entityGroup = "entity"
 76	const uiGroup = "ui"
 77	const remoteGroup = "remote"
 78
 79	cmd.AddGroup(&cobra.Group{ID: entityGroup, Title: "Entities"})
 80	cmd.AddGroup(&cobra.Group{ID: uiGroup, Title: "Interactive interfaces"})
 81	cmd.AddGroup(&cobra.Group{ID: remoteGroup, Title: "Interaction with the outside world"})
 82
 83	addCmdWithGroup := func(child *cobra.Command, groupID string) {
 84		cmd.AddCommand(child)
 85		child.GroupID = groupID
 86	}
 87
 88	addCmdWithGroup(bugcmd.NewBugCommand(), entityGroup)
 89	addCmdWithGroup(usercmd.NewUserCommand(), entityGroup)
 90	addCmdWithGroup(newLabelCommand(), entityGroup)
 91
 92	addCmdWithGroup(newTermUICommand(), uiGroup)
 93	addCmdWithGroup(newWebUICommand(), uiGroup)
 94
 95	addCmdWithGroup(newPullCommand(), remoteGroup)
 96	addCmdWithGroup(newPushCommand(), remoteGroup)
 97	addCmdWithGroup(bridgecmd.NewBridgeCommand(), remoteGroup)
 98
 99	cmd.AddCommand(newCommandsCommand())
100	cmd.AddCommand(newVersionCommand())
101
102	return cmd
103}
104
105func Execute() {
106	if err := NewRootCommand().Execute(); err != nil {
107		os.Exit(1)
108	}
109}
110
111func getCommitAndDirty() (commit, dirty string) {
112	var d, c string
113
114	info, ok := debug.ReadBuildInfo()
115
116	if !ok {
117		fmt.Println("could not get commit")
118	}
119
120	// get the commit and
121	// modified status (that is the flag for repository dirty or not)
122	for _, kv := range info.Settings {
123		switch kv.Key {
124		case "vcs.revision":
125			c = kv.Value
126		case "vcs.modified":
127			if kv.Value == "true" {
128				d = "dirty"
129			}
130		}
131	}
132
133	return c, d
134}