git-ea/cmd/frontport.go

80 lines
1.9 KiB
Go

package cmd
import (
"context"
"errors"
"flag"
"fmt"
"strings"
"github.com/AlecAivazis/survey/v2"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/peterbourgon/ff/v3/ffcli"
"github.com/rs/zerolog/log"
)
var (
frontportFS = flag.NewFlagSet("frontport", flag.ContinueOnError)
Frontport = &ffcli.Command{
Name: "frontport",
FlagSet: frontportFS,
ShortUsage: "frontport <from> [release=main]",
ShortHelp: "frontport cherry-picks a <commit> and applies it to a clean branch based on <release>",
Exec: func(ctx context.Context, args []string) error {
if len(args) < 1 {
return errors.New("frontport requires at least one argument")
}
from := args[0]
if !strings.HasPrefix(from, "release") {
from = fmt.Sprintf("release/v%s", args[0])
}
fetch(ctx)
if !isClean() {
log.Fatal().Msg("working tree is dirty")
}
commits, err := repo().Log(&git.LogOptions{
From: head(from),
})
if err != nil {
return err
}
optMap := make(map[string]plumbing.Hash)
var opts []string
if err := commits.ForEach(func(c *object.Commit) error {
title := strings.Split(c.Message, "\n")[0]
opts = append(opts, title)
optMap[title] = c.Hash
return nil
}); err != nil {
return err
}
var resp string
if err := survey.AskOne(&survey.Select{
Message: "Commit to cherry-pick",
Options: opts,
}, &resp, survey.WithValidator(survey.Required)); err != nil {
return err
}
hash := optMap[resp]
branch := fmt.Sprintf("frontport-%s", hash)
base := "upstream/main"
if len(args) > 1 {
base = fmt.Sprintf("upstream/release/v%s", args[1])
}
if err := Branch.ParseAndRun(ctx, []string{branch, base}); err != nil {
return err
}
return run(ctx, "git", "cherry-pick", hash.String())
},
}
)