package cmd import ( "context" "errors" "flag" "fmt" "os" "os/exec" "os/user" "regexp" "strings" "go.jolheiser.com/git-ea/config" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/peterbourgon/ff/v3/ffcli" "github.com/rs/zerolog/log" ) var Version = "x.y.z" type Handler struct { Config *config.Config } func New() (*ffcli.Command, error) { cfg, err := config.Load() if err != nil { return nil, err } handler := Handler{ Config: cfg, } fs := flag.NewFlagSet("git-ea", flag.ContinueOnError) versionFlag := fs.Bool("version", false, "Print git-ea version") fs.BoolVar(versionFlag, "v", *versionFlag, "--version") c := &ffcli.Command{ Name: "git-ea", FlagSet: fs, ShortUsage: "git-ea ", ShortHelp: "git-ea is the base command", Subcommands: []*ffcli.Command{ handler.Cleanup(), handler.Backport(), handler.Branch(), handler.Frontport(), handler.IDE(), handler.Init(), handler.Post(), handler.PR(), }, } c.Exec = func(_ context.Context, _ []string) error { if *versionFlag { log.Info().Msgf("git-ea v%s", Version) return nil } dir := cfg.Base if fs.NArg() > 0 { if strings.EqualFold(fs.Arg(0), "help") { fmt.Println(ffcli.DefaultUsageFunc(c)) return nil } dir = cfg.WorkspaceBranch(fs.Arg(0)) } fmt.Println(dir) return nil } return c, nil } func (h *Handler) checkInit() error { if !h.Config.IsInit() { return errors.New("git-ea must be initialized first with `git ea init` in an appropriate directory") } return nil } func (h *Handler) run(ctx context.Context, cmd string, args ...string) error { return run(ctx, h.Config.Base, cmd, args...) } func run(ctx context.Context, dir, cmd string, args ...string) error { c := exec.CommandContext(ctx, cmd, args...) c.Dir = dir c.Stdout = os.Stdout c.Stderr = os.Stderr c.Stdin = os.Stdin return c.Run() } func (h *Handler) fetch(ctx context.Context) { if err := run(ctx, h.Config.Base, "git", "fetch", "upstream"); err != nil { log.Err(err).Msg("") } } func (h *Handler) repo() *git.Repository { repo, err := git.PlainOpen(h.Config.Base) if err != nil { log.Fatal().Err(err).Msg("cannot open git repository") } return repo } func (h *Handler) worktree() *git.Worktree { tree, err := h.repo().Worktree() if err != nil { log.Fatal().Err(err).Msg("cannot get git worktree") } return tree } func (h *Handler) head(name string) plumbing.Hash { ref, err := h.repo().Reference(plumbing.NewRemoteReferenceName("upstream", name), false) if err != nil { log.Fatal().Err(err).Msgf("cannot get remote upstream %s HEAD", name) } return ref.Hash() } var releaseRe = regexp.MustCompile(`release/v1\.(\d+)`) func (h *Handler) latestRelease() string { cmd := exec.Command("git", "ls-remote", "upstream", "release/*") cmd.Dir = h.Config.Base out, err := cmd.Output() if err != nil { log.Fatal().Err(err).Msg("could not get latest release") } matches := releaseRe.FindAllStringSubmatch(string(out), -1) var latest string for _, match := range matches { m := match[1] if len(m) < 3 { m = strings.Repeat("0", 3-len(m)) + m } if m > latest { latest = m } } return strings.TrimLeft(latest, "0") } func currentUser() string { u, err := user.Current() if err != nil { return "" } return u.Username }