Polish and cleanup, move to worktree
ci/woodpecker/push/goreleaser Pipeline was successful Details

Signed-off-by: jolheiser <john.olheiser@gmail.com>
main
jolheiser 2022-09-03 16:58:02 -05:00
parent 86ce1bed45
commit 9c0fec9616
Signed by: jolheiser
GPG Key ID: B853ADA5DA7BBF7A
12 changed files with 562 additions and 85 deletions

167
DOCS.md 100644
View File

@ -0,0 +1,167 @@
# git-ea
git-ea is the base command
```
git-ea
├─ backport
├─ branch
├─ frontport
└─ init
```
```
[--help]
[--v]
[--version]
```
**Usage**:
```
git-ea <cmd>
```
**--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] <name>
```
**--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: <latest>)
**--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
-----

View File

@ -15,42 +15,49 @@ import (
"github.com/skratchdot/open-golang/open" "github.com/skratchdot/open-golang/open"
) )
var ( func (h *Handler) Backport() *ffcli.Command {
backportFS = flag.NewFlagSet("backport", flag.ContinueOnError) fs := flag.NewFlagSet("backport", flag.ContinueOnError)
backportFromFlag = backportFS.String("from", "", "Release to backport from (ex: `main`, default: main)") fromFlag := fs.String("from", "", "Release to backport from (ex: `main`, default: main)")
backportToFlag = backportFS.String("to", "", "Release to backport to (ex: `1.17`, default: <latest>)") fs.StringVar(fromFlag, "f", *fromFlag, "--from")
backportListFlag = backportFS.Bool("list", false, "Open repository to see needed backports") toFlag := fs.String("to", "", "Release to backport to (ex: `1.17`, default: `latest`)")
Backport = &ffcli.Command{ 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", Name: "backport",
FlagSet: backportFS, FlagSet: fs,
ShortUsage: "backport --from [release=main] --to [release=latest]", ShortUsage: "backport --from [release=main] --to [release=latest]",
ShortHelp: "backport cherry-picks a <commit> and applies it to a clean branch based on <release>", ShortHelp: "backport cherry-picks a commit and applies it to a clean branch based on `release`",
Exec: func(ctx context.Context, _ []string) error { Exec: func(ctx context.Context, _ []string) error {
to := *backportToFlag if err := h.checkInit(); err != nil {
if to == "" { return err
to = latestRelease()
} }
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 { 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 err
} }
return nil return nil
} }
fetch(ctx) h.fetch(ctx)
if !isClean() { if isClean() {
log.Fatal().Msg("working tree is dirty") log.Fatal().Msg("working tree is dirty")
} }
from := *backportFromFlag from := *fromFlag
if from == "" { if from == "" {
from = "main" from = "main"
} }
commits, err := repo().Log(&git.LogOptions{ commits, err := h.repo().Log(&git.LogOptions{
From: head(from), From: h.head(from),
}) })
if err != nil { if err != nil {
return err return err
@ -78,11 +85,11 @@ var (
hash := optMap[resp] hash := optMap[resp]
branch := fmt.Sprintf("backport-%s", hash) branch := fmt.Sprintf("backport-%s", hash)
base := fmt.Sprintf("upstream/release/v1.%s", to) 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 err
} }
return run(ctx, "git", "cherry-pick", hash.String()) return run(ctx, h.Config.WorkspaceBranch(branch), "git", "cherry-pick", hash.String())
}, },
} }
) }

View File

@ -4,40 +4,44 @@ import (
"context" "context"
"errors" "errors"
"flag" "flag"
"fmt"
"path/filepath"
"strings"
"github.com/peterbourgon/ff/v3/ffcli" "github.com/peterbourgon/ff/v3/ffcli"
"github.com/rs/zerolog/log"
) )
var ( func (h *Handler) Branch() *ffcli.Command {
branchFS = flag.NewFlagSet("branch", flag.ContinueOnError) fs := flag.NewFlagSet("branch", flag.ContinueOnError)
branchNoFetchFlag = branchFS.Bool("no-fetch", false, "Skip fetching") noFetchFlag := fs.Bool("no-fetch", false, "Skip fetching")
branchBaseFlag = branchFS.String("base", "main", "Ref to base from") fs.BoolVar(noFetchFlag, "nf", *noFetchFlag, "--no-fetch")
Branch = &ffcli.Command{ baseFlag := fs.String("base", "main", "Ref to base from")
fs.StringVar(baseFlag, "b", *baseFlag, "--base")
return &ffcli.Command{
Name: "branch", Name: "branch",
FlagSet: branchFS, FlagSet: fs,
ShortUsage: "branch --base [ref=main] <name>", ShortUsage: "branch --base [ref=main] <name>",
ShortHelp: "branch creates a new branch called <name> based on <base>", ShortHelp: "branch creates a new branch called `name` based on `base`",
Exec: func(ctx context.Context, args []string) error { Exec: func(ctx context.Context, args []string) error {
if err := h.checkInit(); err != nil {
return err
}
if len(args) < 1 { if len(args) < 1 {
return errors.New("branch requires one argument") return errors.New("branch requires a name")
} }
name := args[0] name := args[0]
base := *branchBaseFlag base := *baseFlag
if base == "" { if !strings.HasPrefix(base, "upstream") {
base = "upstream/main" base = fmt.Sprintf("upstream/%s", base)
} }
if !isClean() { if !*noFetchFlag {
log.Fatal().Msg("working tree is dirty") h.fetch(ctx)
} }
if !*branchNoFetchFlag { return h.run(ctx, "git", "worktree", "add", "-B", name, filepath.Join(h.Config.Workspace(), name), base)
fetch(ctx)
}
return run(ctx, "git", "checkout", "-b", name, base)
}, },
} }
) }

75
cmd/cleanup.go 100644
View File

@ -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)
}

View File

@ -2,26 +2,93 @@ package cmd
import ( import (
"context" "context"
"errors"
"flag"
"fmt"
"os" "os"
"os/exec" "os/exec"
"regexp" "regexp"
"strings" "strings"
"go.jolheiser.com/git-ea/config"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
"github.com/peterbourgon/ff/v3/ffcli"
"github.com/rs/zerolog/log" "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 <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 := exec.CommandContext(ctx, cmd, args...)
c.Dir = dir
c.Stdout = os.Stdout c.Stdout = os.Stdout
c.Stderr = os.Stderr c.Stderr = os.Stderr
c.Stdin = os.Stdin c.Stdin = os.Stdin
return c.Run() return c.Run()
} }
func fetch(ctx context.Context) { func (h *Handler) fetch(ctx context.Context) {
if err := run(ctx, "git", "fetch", "upstream"); err != nil { if err := run(ctx, h.Config.Base, "git", "fetch", "upstream"); err != nil {
log.Err(err).Msg("") log.Err(err).Msg("")
} }
} }
@ -35,26 +102,24 @@ func isClean() bool {
return len(o) == 0 return len(o) == 0
} }
func repo() *git.Repository { func (h *Handler) repo() *git.Repository {
repo, err := git.PlainOpenWithOptions(".", &git.PlainOpenOptions{ repo, err := git.PlainOpen(h.Config.Base)
DetectDotGit: true,
})
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("cannot open git repository") log.Fatal().Err(err).Msg("cannot open git repository")
} }
return repo return repo
} }
func worktree() *git.Worktree { func (h *Handler) worktree() *git.Worktree {
tree, err := repo().Worktree() tree, err := h.repo().Worktree()
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("cannot get git worktree") log.Fatal().Err(err).Msg("cannot get git worktree")
} }
return tree return tree
} }
func head(name string) plumbing.Hash { func (h *Handler) head(name string) plumbing.Hash {
ref, err := repo().Reference(plumbing.NewRemoteReferenceName("upstream", name), false) ref, err := h.repo().Reference(plumbing.NewRemoteReferenceName("upstream", name), false)
if err != nil { if err != nil {
log.Fatal().Err(err).Msgf("cannot get remote upstream %s HEAD", name) 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+)`) var releaseRe = regexp.MustCompile(`release/v1\.(\d+)`)
func latestRelease() string { func (h *Handler) latestRelease() string {
cmd := exec.Command("git", "ls-remote", "upstream", "release/*") cmd := exec.Command("git", "ls-remote", "upstream", "release/*")
cmd.Dir = h.Config.Base
out, err := cmd.Output() out, err := cmd.Output()
if err != nil { if err != nil {
log.Fatal().Err(err).Msg("could not get latest release") log.Fatal().Err(err).Msg("could not get latest release")

View File

@ -14,32 +14,38 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
var ( func (h *Handler) Frontport() *ffcli.Command {
frontportFS = flag.NewFlagSet("frontport", flag.ContinueOnError) fs := flag.NewFlagSet("frontport", flag.ContinueOnError)
frontportFromFlag = frontportFS.String("from", "", "Release to frontport from (ex: `1.17`, default: <latest>)") fromFlag := fs.String("from", "", "Release to frontport from (ex: `1.17`, default: <latest>)")
frontportToFlag = frontportFS.String("to", "", "Release to frontport to (ex: `main`, default: `main`)") fs.StringVar(fromFlag, "f", *fromFlag, "--from")
Frontport = &ffcli.Command{ toFlag := fs.String("to", "", "Release to frontport to (ex: `main`, default: `main`)")
fs.StringVar(toFlag, "t", *toFlag, "--to")
return &ffcli.Command{
Name: "frontport", Name: "frontport",
FlagSet: frontportFS, FlagSet: fs,
ShortUsage: "frontport --from [release=latest] --to [release=main]", ShortUsage: "frontport --from [release=latest] --to [release=main]",
ShortHelp: "frontport cherry-picks a <commit> and applies it to a clean branch based on <release>", ShortHelp: "frontport cherry-picks a commit and applies it to a clean branch based on `release`",
Exec: func(ctx context.Context, _ []string) error { Exec: func(ctx context.Context, _ []string) error {
from := *frontportFromFlag if err := h.checkInit(); err != nil {
return err
}
from := *fromFlag
if from == "" { if from == "" {
from = latestRelease() from = h.latestRelease()
} }
if !strings.HasPrefix(from, "release") { if !strings.HasPrefix(from, "release") {
from = fmt.Sprintf("release/v%s", from) from = fmt.Sprintf("release/v%s", from)
} }
fetch(ctx) h.fetch(ctx)
if !isClean() { if !isClean() {
log.Fatal().Msg("working tree is dirty") log.Fatal().Msg("working tree is dirty")
} }
commits, err := repo().Log(&git.LogOptions{ commits, err := h.repo().Log(&git.LogOptions{
From: head(from), From: h.head(from),
}) })
if err != nil { if err != nil {
return err return err
@ -67,18 +73,18 @@ var (
hash := optMap[resp] hash := optMap[resp]
branch := fmt.Sprintf("frontport-%s", hash) branch := fmt.Sprintf("frontport-%s", hash)
base := *frontportToFlag base := *toFlag
if base == "" { if base == "" {
base = "upstream/main" base = "upstream/main"
} }
if !strings.HasPrefix(base, "upstream") { if !strings.HasPrefix(base, "upstream") {
base = fmt.Sprintf("upstream/release/v1.%s", base) 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 err
} }
return run(ctx, "git", "cherry-pick", hash.String()) return run(ctx, h.Config.WorkspaceBranch(branch), "git", "cherry-pick", hash.String())
}, },
} }
) }

48
cmd/init.go 100644
View File

@ -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)
},
}
}

76
config/config.go 100644
View File

@ -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)
}

34
ffmd.go 100644
View File

@ -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)
}
}

1
go.mod
View File

@ -8,6 +8,7 @@ require (
github.com/peterbourgon/ff/v3 v3.3.0 github.com/peterbourgon/ff/v3 v3.3.0
github.com/rs/zerolog v1.27.0 github.com/rs/zerolog v1.27.0
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
go.jolheiser.com/ffmd v0.0.2
) )
require ( require (

8
go.sum
View File

@ -1,5 +1,6 @@
github.com/AlecAivazis/survey/v2 v2.3.5 h1:A8cYupsAZkjaUmhtTYv3sSqc7LO5mp1XDfqe5E/9wRQ= 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/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.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 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= 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.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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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.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.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 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 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 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/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 h1:PaKe7GW8orVFh8Unb5jNHS+JZBwWUMa2se0HM6/BI24=
github.com/peterbourgon/ff/v3 v3.3.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= 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= 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/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 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= 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-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-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=

19
main.go
View File

@ -6,29 +6,16 @@ import (
"go.jolheiser.com/git-ea/cmd" "go.jolheiser.com/git-ea/cmd"
"github.com/peterbourgon/ff/v3/ffcli"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
var Version = "x.y.z"
func main() { func main() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
c := &ffcli.Command{ c, err := cmd.New()
Name: "ea", if err != nil {
ShortUsage: "ea <cmd>", log.Fatal().Err(err).Msg("could not initialize command")
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
},
} }
if err := c.ParseAndRun(context.Background(), os.Args[1:]); err != nil { if err := c.ParseAndRun(context.Background(), os.Args[1:]); err != nil {