diff --git a/DOCS.md b/DOCS.md new file mode 100644 index 0000000..1b097d4 --- /dev/null +++ b/DOCS.md @@ -0,0 +1,167 @@ +# git-ea + +git-ea is the base command + +``` +git-ea +├─ backport +├─ branch +├─ frontport +└─ init +``` + + +``` +[--help] +[--v] +[--version] +``` +**Usage**: + +``` +git-ea +``` + +**--help**: Show help + + +**--v**: --version + + +**--version**: Print git-ea version + + +----- + +## backport + +backport cherry-picks a commit and applies it to a clean branch based on `release` + + +``` +[--f]=[value] +[--from]=[value] +[--help] +[--l] +[--list] +[--t]=[value] +[--to]=[value] +``` +**Usage**: + +``` +backport --from [release=main] --to [release=latest] +``` + +**--f**="": --from + + +**--from**="": Release to backport from (ex: `main`, default: main) + + +**--help**: Show help + + +**--l**: --list + + +**--list**: Open repository to see needed backports + + +**--t**="": --to + + +**--to**="": Release to backport to (ex: `1.17`, default: `latest`) + + +----- + +## branch + +branch creates a new branch called `name` based on `base` + + +``` +[--b]=[value] +[--base]=[value] +[--help] +[--nf] +[--no-fetch] +``` +**Usage**: + +``` +branch --base [ref=main] +``` + +**--b**="": --base (default: `main`) + + +**--base**="": Ref to base from (default: `main`) + + +**--help**: Show help + + +**--nf**: --no-fetch + + +**--no-fetch**: Skip fetching + + +----- + +## frontport + +frontport cherry-picks a commit and applies it to a clean branch based on `release` + + +``` +[--f]=[value] +[--from]=[value] +[--help] +[--t]=[value] +[--to]=[value] +``` +**Usage**: + +``` +frontport --from [release=latest] --to [release=main] +``` + +**--f**="": --from + + +**--from**="": Release to frontport from (ex: `1.17`, default: ) + + +**--help**: Show help + + +**--t**="": --to + + +**--to**="": Release to frontport to (ex: `main`, default: `main`) + + +----- + +## init + +init initializes a workspace for Gitea + + +``` +[--help] +``` +**Usage**: + +``` +init +``` + +**--help**: Show help + + +----- + diff --git a/cmd/backport.go b/cmd/backport.go index e97b8ce..885596e 100644 --- a/cmd/backport.go +++ b/cmd/backport.go @@ -15,42 +15,49 @@ import ( "github.com/skratchdot/open-golang/open" ) -var ( - backportFS = flag.NewFlagSet("backport", flag.ContinueOnError) - backportFromFlag = backportFS.String("from", "", "Release to backport from (ex: `main`, default: main)") - backportToFlag = backportFS.String("to", "", "Release to backport to (ex: `1.17`, default: )") - backportListFlag = backportFS.Bool("list", false, "Open repository to see needed backports") - Backport = &ffcli.Command{ +func (h *Handler) Backport() *ffcli.Command { + fs := flag.NewFlagSet("backport", flag.ContinueOnError) + fromFlag := fs.String("from", "", "Release to backport from (ex: `main`, default: main)") + fs.StringVar(fromFlag, "f", *fromFlag, "--from") + toFlag := fs.String("to", "", "Release to backport to (ex: `1.17`, default: `latest`)") + fs.StringVar(toFlag, "t", *toFlag, "--to") + listFlag := fs.Bool("list", false, "Open repository to see needed backports") + fs.BoolVar(listFlag, "l", *listFlag, "--list") + return &ffcli.Command{ Name: "backport", - FlagSet: backportFS, + FlagSet: fs, ShortUsage: "backport --from [release=main] --to [release=latest]", - ShortHelp: "backport cherry-picks a and applies it to a clean branch based on ", + ShortHelp: "backport cherry-picks a commit and applies it to a clean branch based on `release`", Exec: func(ctx context.Context, _ []string) error { - to := *backportToFlag - if to == "" { - to = latestRelease() + if err := h.checkInit(); err != nil { + return err } - if *backportListFlag { + to := *toFlag + if to == "" { + to = h.latestRelease() + } + + if *listFlag { if err := open.Run(fmt.Sprintf("https://github.com/go-gitea/gitea/pulls?q=is%%3Apr+-label%%3Abackport%%2Fdone+label%%3Abackport%%2Fv1.%s+is%%3Amerged", to)); err != nil { return err } return nil } - fetch(ctx) + h.fetch(ctx) - if !isClean() { + if isClean() { log.Fatal().Msg("working tree is dirty") } - from := *backportFromFlag + from := *fromFlag if from == "" { from = "main" } - commits, err := repo().Log(&git.LogOptions{ - From: head(from), + commits, err := h.repo().Log(&git.LogOptions{ + From: h.head(from), }) if err != nil { return err @@ -78,11 +85,11 @@ var ( hash := optMap[resp] branch := fmt.Sprintf("backport-%s", hash) base := fmt.Sprintf("upstream/release/v1.%s", to) - if err := Branch.ParseAndRun(ctx, []string{"--base", base, branch}); err != nil { + if err := h.Branch().ParseAndRun(ctx, []string{"--base", base, branch}); err != nil { return err } - return run(ctx, "git", "cherry-pick", hash.String()) + return run(ctx, h.Config.WorkspaceBranch(branch), "git", "cherry-pick", hash.String()) }, } -) +} diff --git a/cmd/branch.go b/cmd/branch.go index 655e812..511fdf6 100644 --- a/cmd/branch.go +++ b/cmd/branch.go @@ -4,40 +4,44 @@ import ( "context" "errors" "flag" + "fmt" + "path/filepath" + "strings" "github.com/peterbourgon/ff/v3/ffcli" - "github.com/rs/zerolog/log" ) -var ( - branchFS = flag.NewFlagSet("branch", flag.ContinueOnError) - branchNoFetchFlag = branchFS.Bool("no-fetch", false, "Skip fetching") - branchBaseFlag = branchFS.String("base", "main", "Ref to base from") - Branch = &ffcli.Command{ +func (h *Handler) Branch() *ffcli.Command { + fs := flag.NewFlagSet("branch", flag.ContinueOnError) + noFetchFlag := fs.Bool("no-fetch", false, "Skip fetching") + fs.BoolVar(noFetchFlag, "nf", *noFetchFlag, "--no-fetch") + baseFlag := fs.String("base", "main", "Ref to base from") + fs.StringVar(baseFlag, "b", *baseFlag, "--base") + return &ffcli.Command{ Name: "branch", - FlagSet: branchFS, + FlagSet: fs, ShortUsage: "branch --base [ref=main] ", - ShortHelp: "branch creates a new branch called based on ", + ShortHelp: "branch creates a new branch called `name` based on `base`", Exec: func(ctx context.Context, args []string) error { + if err := h.checkInit(); err != nil { + return err + } + if len(args) < 1 { - return errors.New("branch requires one argument") + return errors.New("branch requires a name") } name := args[0] - base := *branchBaseFlag - if base == "" { - base = "upstream/main" + base := *baseFlag + if !strings.HasPrefix(base, "upstream") { + base = fmt.Sprintf("upstream/%s", base) } - if !isClean() { - log.Fatal().Msg("working tree is dirty") + if !*noFetchFlag { + h.fetch(ctx) } - if !*branchNoFetchFlag { - fetch(ctx) - } - - return run(ctx, "git", "checkout", "-b", name, base) + return h.run(ctx, "git", "worktree", "add", "-B", name, filepath.Join(h.Config.Workspace(), name), base) }, } -) +} diff --git a/cmd/cleanup.go b/cmd/cleanup.go new file mode 100644 index 0000000..dc91a78 --- /dev/null +++ b/cmd/cleanup.go @@ -0,0 +1,75 @@ +package cmd + +import ( + "context" + "errors" + "flag" + "os" + + "github.com/AlecAivazis/survey/v2" + "github.com/peterbourgon/ff/v3/ffcli" +) + +func (h *Handler) Cleanup() *ffcli.Command { + fs := flag.NewFlagSet("cleanup", flag.ContinueOnError) + return &ffcli.Command{ + Name: "cleanup", + FlagSet: fs, + ShortUsage: "cleanup [branches...]", + ShortHelp: "cleanup removes named branches, or interactive if no arguments", + Exec: func(ctx context.Context, args []string) error { + if err := h.checkInit(); err != nil { + return err + } + + if len(args) > 0 { + for _, arg := range args { + if err := removeWorktree(h, ctx, arg); err != nil { + return err + } + } + return nil + } + + dirs, err := os.ReadDir(h.Config.Workspace()) + if err != nil { + return err + } + + opts := make([]string, 0, len(dirs)) + for _, dir := range dirs { + if !dir.IsDir() { + continue + } + opts = append(opts, dir.Name()) + } + + if len(opts) == 0 { + return errors.New("no worktrees currently exist") + } + + var remove []string + if err := survey.AskOne(&survey.MultiSelect{ + Message: "Worktrees to remove", + Options: opts, + }, &remove); err != nil { + return err + } + + for _, rm := range remove { + if err := removeWorktree(h, ctx, rm); err != nil { + return err + } + } + + return nil + }, + } +} + +func removeWorktree(h *Handler, ctx context.Context, name string) error { + if err := h.run(ctx, "git", "worktree", "remove", name); err != nil { + return nil + } + return h.run(ctx, "git", "branch", "-D", name) +} diff --git a/cmd/cmd.go b/cmd/cmd.go index 2d34eeb..1dcbac7 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -2,26 +2,93 @@ 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" ) -func run(ctx context.Context, cmd string, args ...string) error { +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 ", + 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 fetch(ctx context.Context) { - if err := run(ctx, "git", "fetch", "upstream"); err != nil { +func (h *Handler) fetch(ctx context.Context) { + if err := run(ctx, h.Config.Base, "git", "fetch", "upstream"); err != nil { log.Err(err).Msg("") } } @@ -35,26 +102,24 @@ func isClean() bool { return len(o) == 0 } -func repo() *git.Repository { - repo, err := git.PlainOpenWithOptions(".", &git.PlainOpenOptions{ - DetectDotGit: true, - }) +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 worktree() *git.Worktree { - tree, err := repo().Worktree() +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 head(name string) plumbing.Hash { - ref, err := repo().Reference(plumbing.NewRemoteReferenceName("upstream", name), false) +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) } @@ -63,8 +128,9 @@ func head(name string) plumbing.Hash { var releaseRe = regexp.MustCompile(`release/v1\.(\d+)`) -func latestRelease() string { +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") diff --git a/cmd/frontport.go b/cmd/frontport.go index 557e3f8..9a0e3e7 100644 --- a/cmd/frontport.go +++ b/cmd/frontport.go @@ -14,32 +14,38 @@ import ( "github.com/rs/zerolog/log" ) -var ( - frontportFS = flag.NewFlagSet("frontport", flag.ContinueOnError) - frontportFromFlag = frontportFS.String("from", "", "Release to frontport from (ex: `1.17`, default: )") - frontportToFlag = frontportFS.String("to", "", "Release to frontport to (ex: `main`, default: `main`)") - Frontport = &ffcli.Command{ +func (h *Handler) Frontport() *ffcli.Command { + fs := flag.NewFlagSet("frontport", flag.ContinueOnError) + fromFlag := fs.String("from", "", "Release to frontport from (ex: `1.17`, default: )") + fs.StringVar(fromFlag, "f", *fromFlag, "--from") + toFlag := fs.String("to", "", "Release to frontport to (ex: `main`, default: `main`)") + fs.StringVar(toFlag, "t", *toFlag, "--to") + return &ffcli.Command{ Name: "frontport", - FlagSet: frontportFS, + FlagSet: fs, ShortUsage: "frontport --from [release=latest] --to [release=main]", - ShortHelp: "frontport cherry-picks a and applies it to a clean branch based on ", + ShortHelp: "frontport cherry-picks a commit and applies it to a clean branch based on `release`", Exec: func(ctx context.Context, _ []string) error { - from := *frontportFromFlag + if err := h.checkInit(); err != nil { + return err + } + + from := *fromFlag if from == "" { - from = latestRelease() + from = h.latestRelease() } if !strings.HasPrefix(from, "release") { from = fmt.Sprintf("release/v%s", from) } - fetch(ctx) + h.fetch(ctx) if !isClean() { log.Fatal().Msg("working tree is dirty") } - commits, err := repo().Log(&git.LogOptions{ - From: head(from), + commits, err := h.repo().Log(&git.LogOptions{ + From: h.head(from), }) if err != nil { return err @@ -67,18 +73,18 @@ var ( hash := optMap[resp] branch := fmt.Sprintf("frontport-%s", hash) - base := *frontportToFlag + base := *toFlag if base == "" { base = "upstream/main" } if !strings.HasPrefix(base, "upstream") { base = fmt.Sprintf("upstream/release/v1.%s", base) } - if err := Branch.ParseAndRun(ctx, []string{branch, base}); err != nil { + if err := h.Branch().ParseAndRun(ctx, []string{branch, base}); err != nil { return err } - return run(ctx, "git", "cherry-pick", hash.String()) + return run(ctx, h.Config.WorkspaceBranch(branch), "git", "cherry-pick", hash.String()) }, } -) +} diff --git a/cmd/init.go b/cmd/init.go new file mode 100644 index 0000000..8033d7e --- /dev/null +++ b/cmd/init.go @@ -0,0 +1,48 @@ +package cmd + +import ( + "context" + "flag" + "fmt" + "os" + + "go.jolheiser.com/git-ea/config" + + "github.com/peterbourgon/ff/v3/ffcli" +) + +func (h *Handler) Init() *ffcli.Command { + fs := flag.NewFlagSet("init", flag.ContinueOnError) + return &ffcli.Command{ + Name: "init", + FlagSet: fs, + ShortUsage: "init", + ShortHelp: "init initializes a workspace for Gitea", + Exec: func(ctx context.Context, args []string) error { + if h.Config.Base != "" { + return fmt.Errorf("a git-ea workspace already exists at %q", h.Config.Base) + } + + cwd, err := os.Getwd() + if err != nil { + return err + } + if err := run(ctx, ".", "git", "clone", "--bare", "git@github.com:jolheiser/gitea.git", "."); err != nil { + return err + } + if err := run(ctx, ".", "git", "remote", "add", "upstream", "https://github.com/go-gitea/gitea.git"); err != nil { + return err + } + + cfg := config.Config{ + Base: cwd, + } + + if err := os.MkdirAll(cfg.Workspace(), os.ModePerm); err != nil { + return err + } + + return config.Save(cfg) + }, + } +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..80f303c --- /dev/null +++ b/config/config.go @@ -0,0 +1,76 @@ +package config + +import ( + "encoding/json" + "errors" + "io/fs" + "os" + "path/filepath" +) + +type Config struct { + Base string `json:"base"` +} + +func (c *Config) Workspace() string { + return filepath.Join(c.Base, ".workspace") +} + +func (c *Config) WorkspaceBranch(name string) string { + return filepath.Join(c.Workspace(), name) +} + +func (c *Config) IsInit() bool { + return c.Base != "" +} + +func path() (string, error) { + userCfgDir, err := os.UserConfigDir() + if err != nil { + return "", err + } + cfgDir := filepath.Join(userCfgDir, "git-ea") + return filepath.Join(cfgDir, "config.json"), os.MkdirAll(cfgDir, os.ModePerm) +} + +func Load() (*Config, error) { + cfgPath, err := path() + if err != nil { + return nil, err + } + + fi, err := os.Open(cfgPath) + if err != nil { + if !errors.Is(err, fs.ErrNotExist) { + return nil, err + } + fi, err = os.Create(cfgPath) + if err != nil { + return nil, err + } + if _, err := fi.WriteString("{}"); err != nil { + return nil, err + } + if _, err := fi.Seek(0, 0); err != nil { + return nil, err + } + } + defer fi.Close() + + var cfg Config + return &cfg, json.NewDecoder(fi).Decode(&cfg) +} + +func Save(c Config) error { + cfgPath, err := path() + if err != nil { + return err + } + + fi, err := os.Create(cfgPath) + if err != nil { + return err + } + defer fi.Close() + return json.NewEncoder(fi).Encode(c) +} diff --git a/ffmd.go b/ffmd.go new file mode 100644 index 0000000..97331bf --- /dev/null +++ b/ffmd.go @@ -0,0 +1,34 @@ +//go:build generate + +package main + +import ( + "os" + + "go.jolheiser.com/git-ea/cmd" + + "go.jolheiser.com/ffmd" +) + +//go:generate go run ffmd.go +func main() { + c, err := cmd.New() + if err != nil { + panic(err) + } + + docs, err := ffmd.Command(c) + if err != nil { + panic(err) + } + + fi, err := os.Create("DOCS.md") + if err != nil { + panic(err) + } + defer fi.Close() + + if _, err := fi.WriteString(docs); err != nil { + panic(err) + } +} diff --git a/go.mod b/go.mod index b188058..978a1e0 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/peterbourgon/ff/v3 v3.3.0 github.com/rs/zerolog v1.27.0 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 + go.jolheiser.com/ffmd v0.0.2 ) require ( diff --git a/go.sum b/go.sum index 465340f..94d477f 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ github.com/AlecAivazis/survey/v2 v2.3.5 h1:A8cYupsAZkjaUmhtTYv3sSqc7LO5mp1XDfqe5E/9wRQ= github.com/AlecAivazis/survey/v2 v2.3.5/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= @@ -56,8 +57,9 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -69,6 +71,8 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyex github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/peterbourgon/ff/v3 v3.1.2/go.mod h1:XNJLY8EIl6MjMVjBS4F0+G0LYoAqs0DTa4rmHHukKDE= github.com/peterbourgon/ff/v3 v3.3.0 h1:PaKe7GW8orVFh8Unb5jNHS+JZBwWUMa2se0HM6/BI24= github.com/peterbourgon/ff/v3 v3.3.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -93,6 +97,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +go.jolheiser.com/ffmd v0.0.2 h1:rNOUq5wQKsNQU3pc51XNaks9+GK9hLlFTsPHrQhlGRU= +go.jolheiser.com/ffmd v0.0.2/go.mod h1:NLhcXZqO+dwvQ2/X9z3TUA3gORxUuRlgOjKC931vCZ4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= diff --git a/main.go b/main.go index 8a0dcee..7d157a7 100644 --- a/main.go +++ b/main.go @@ -6,29 +6,16 @@ import ( "go.jolheiser.com/git-ea/cmd" - "github.com/peterbourgon/ff/v3/ffcli" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) -var Version = "x.y.z" - func main() { log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) - c := &ffcli.Command{ - Name: "ea", - ShortUsage: "ea ", - ShortHelp: "ea is the base command", - Subcommands: []*ffcli.Command{ - cmd.Backport, - cmd.Branch, - cmd.Frontport, - }, - Exec: func(_ context.Context, _ []string) error { - log.Info().Msgf("git-ea v%s", Version) - return nil - }, + c, err := cmd.New() + if err != nil { + log.Fatal().Err(err).Msg("could not initialize command") } if err := c.ParseAndRun(context.Background(), os.Args[1:]); err != nil {