From fe0e2e57075910ad7d5c46528a96cbe87299b083 Mon Sep 17 00:00:00 2001 From: jolheiser Date: Tue, 27 Dec 2022 22:40:45 -0600 Subject: [PATCH] feat: tag command and force cleanup Signed-off-by: jolheiser --- cmd/cleanup.go | 15 +++++-- cmd/cmd.go | 1 + cmd/ide.go | 5 ++- cmd/tag.go | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 6 deletions(-) create mode 100644 cmd/tag.go diff --git a/cmd/cleanup.go b/cmd/cleanup.go index f581950..b1d0e2b 100644 --- a/cmd/cleanup.go +++ b/cmd/cleanup.go @@ -11,6 +11,8 @@ import ( func (h *Handler) Cleanup() *ffcli.Command { fs := flag.NewFlagSet("cleanup", flag.ContinueOnError) + forceFlag := fs.Bool("force", false, "Force cleanup") + fs.BoolVar(forceFlag, "f", *forceFlag, "--force") return &ffcli.Command{ Name: "cleanup", FlagSet: fs, @@ -23,7 +25,7 @@ func (h *Handler) Cleanup() *ffcli.Command { if len(args) > 0 { for _, arg := range args { - if err := removeWorktree(h, ctx, arg); err != nil { + if err := removeWorktree(h, ctx, arg, *forceFlag); err != nil { return err } } @@ -48,7 +50,7 @@ func (h *Handler) Cleanup() *ffcli.Command { } for _, rm := range remove { - if err := removeWorktree(h, ctx, rm); err != nil { + if err := removeWorktree(h, ctx, rm, *forceFlag); err != nil { return err } } @@ -58,8 +60,13 @@ func (h *Handler) Cleanup() *ffcli.Command { } } -func removeWorktree(h *Handler, ctx context.Context, name string) error { - if err := h.run(ctx, "git", "worktree", "remove", name); err != nil { +func removeWorktree(h *Handler, ctx context.Context, name string, force bool) error { + args := []string{"worktree", "remove"} + if force { + args = append(args, "--force") + } + args = append(args, name) + if err := h.run(ctx, "git", args...); err != nil { return nil } return h.run(ctx, "git", "branch", "-D", name) diff --git a/cmd/cmd.go b/cmd/cmd.go index 7ca65e1..1767ce0 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -53,6 +53,7 @@ func New() (*ffcli.Command, error) { handler.Init(), handler.Post(), handler.PR(), + handler.Tag(), }, } c.Exec = func(_ context.Context, _ []string) error { diff --git a/cmd/ide.go b/cmd/ide.go index 946eb8a..991919b 100644 --- a/cmd/ide.go +++ b/cmd/ide.go @@ -3,10 +3,11 @@ package cmd import ( "context" "flag" - "github.com/AlecAivazis/survey/v2" - "github.com/peterbourgon/ff/v3/ffcli" "os" "os/exec" + + "github.com/AlecAivazis/survey/v2" + "github.com/peterbourgon/ff/v3/ffcli" ) func (h *Handler) IDE() *ffcli.Command { diff --git a/cmd/tag.go b/cmd/tag.go new file mode 100644 index 0000000..58afd7f --- /dev/null +++ b/cmd/tag.go @@ -0,0 +1,113 @@ +package cmd + +import ( + "context" + "errors" + "flag" + "fmt" + "os" + "path/filepath" + "regexp" + "sort" + "strings" + + "github.com/AlecAivazis/survey/v2" + "github.com/go-git/go-git/v5" + "github.com/peterbourgon/ff/v3/ffcli" +) + +var ( + treeURL = "https://github.com/go-gitea/gitea/tree/%s" + versionRe = regexp.MustCompile(`v\d+\.\d+\.\d+`) +) + +func (h *Handler) Tag() *ffcli.Command { + fs := flag.NewFlagSet("tag", flag.ContinueOnError) + return &ffcli.Command{ + Name: "tag", + FlagSet: fs, + ShortUsage: "tag ", + ShortHelp: "tag makes a signed tag for `branch`", + Exec: func(ctx context.Context, args []string) error { + if err := h.checkInit(); err != nil { + return err + } + h.fetch(ctx) + + var branch string + if len(args) > 0 { + branch = args[0] + } + + if branch == "" { + var branches []string + remote, err := h.repo().Remote("upstream") + if err != nil { + return err + } + refs, err := remote.List(&git.ListOptions{}) + if err != nil { + return err + } + for _, ref := range refs { + if ref.Name().IsBranch() { + branches = append(branches, strings.TrimPrefix(ref.Name().String(), "refs/heads/")) + } + } + sort.Strings(branches) + if err := survey.AskOne(&survey.Select{ + Message: "Branch", + Options: branches, + }, &branch, survey.WithValidator(survey.Required)); err != nil { + return err + } + } + if !strings.HasPrefix(branch, "release") { + if !strings.HasPrefix(branch, "v") { + branch = fmt.Sprintf("v%s", branch) + } + branch = fmt.Sprintf("release/%s", branch) + } + + var version string + if err := survey.AskOne(&survey.Input{ + Message: "Version", + }, &version, survey.WithValidator(func(ans any) error { + if !versionRe.MatchString(fmt.Sprint(ans)) { + return errors.New("version isn't valid v$maj.$min.$") + } + return nil + })); err != nil { + return err + } + + workspaceName := strings.ReplaceAll(branch, "/", "-") + if err := h.Branch().ParseAndRun(ctx, []string{"--base", branch, workspaceName}); err != nil { + return err + } + + var changelog string + if err := survey.AskOne(&survey.Editor{ + Message: "Changelog", + FileName: "*.md", + }, &changelog, survey.WithValidator(survey.Required)); err != nil { + return err + } + + fi, err := os.Create(filepath.Join(h.Config.WorkspaceBranch(workspaceName), "release.notes")) + if err != nil { + return err + } + if _, err := fi.WriteString(changelog); err != nil { + return err + } + if err := fi.Close(); err != nil { + return err + } + run(ctx, h.Config.WorkspaceBranch(workspaceName), "git", "tag", "-s", "-F", "release.notes", version) + + fmt.Printf("cd %s && git push upstream %s \n", h.Config.WorkspaceBranch(workspaceName), version) + return nil + }, + } +}