git-ea/cmd/cmd.go

153 lines
3.2 KiB
Go

package cmd
import (
"context"
"errors"
"flag"
"fmt"
"os"
"os/exec"
"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")
return &ffcli.Command{
Name: "git-ea",
FlagSet: fs,
ShortUsage: "git-ea <cmd>",
ShortHelp: "git-ea is the base command",
Subcommands: []*ffcli.Command{
handler.Cleanup(),
handler.Backport(),
handler.Branch(),
handler.Frontport(),
handler.Init(),
},
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 {
dir = cfg.WorkspaceBranch(fs.Arg(0))
}
fmt.Println(dir)
return nil
},
}, 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 isClean() bool {
c := exec.Command("git", "status", "--porcelain")
o, err := c.Output()
if err != nil {
log.Fatal().Err(err).Msg("could not get git status")
}
return len(o) == 0
}
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")
}