From a49f79a06e6687510e19c4e166312ec95984e632 Mon Sep 17 00:00:00 2001 From: Frank Mayer Date: Sun, 5 Jan 2025 07:35:12 +0100 Subject: [PATCH] request --- internal/roast/info.go | 19 ++++++++++++ internal/roast/request.go | 61 ++++++++++++++++++++++++++++++++++++--- internal/roast/roast.go | 6 ++++ internal/util/textedit.go | 52 +++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 internal/util/textedit.go diff --git a/internal/roast/info.go b/internal/roast/info.go index 2896da9..1c46ea1 100644 --- a/internal/roast/info.go +++ b/internal/roast/info.go @@ -1,5 +1,10 @@ package roast +import ( + "os/exec" + "strings" +) + func (r *Roast) CurrentBranchName() (string, bool) { head, err := r.repo.Head() if err != nil { @@ -8,3 +13,17 @@ func (r *Roast) CurrentBranchName() (string, bool) { return head.Name().Short(), true } + +var gitusername string + +func GitUserName() string { + if len(gitusername) != 0 { + return gitusername + } + if out, err := exec.Command("git", "config", "user.name").Output(); err != nil { + return "" + } else { + gitusername = strings.TrimSpace(string(out)) + return gitusername + } +} diff --git a/internal/roast/request.go b/internal/roast/request.go index 1b1f322..f30cc0f 100644 --- a/internal/roast/request.go +++ b/internal/roast/request.go @@ -4,6 +4,14 @@ import ( "errors" "fmt" "git-roast/internal/log" + "git-roast/internal/util" + "net/url" + "os" + "os/exec" + "path/filepath" + "time" + + "github.com/go-git/go-git/v5" ) func (r *Roast) Request(from string, into string) error { @@ -19,13 +27,58 @@ func (r *Roast) Request(from string, into string) error { return errors.Join(fmt.Errorf("failed to get target branch %s", from), err) } - id := fmt.Sprintf( - "from_%s_into_%s", + id := url.PathEscape(fmt.Sprintf( + "%016x_from_%s_into_%s", + time.Now().Unix(), sourceBranch.Name, targetBranch.Name, - ) + )) - fmt.Println(id) + initialMessage, err := util.Textedit(fmt.Sprintf( + "%s is requesting merge into `%s` from `%s`\n", + GitUserName(), + into, + from, + )) + if err != nil { + return err + } + p := filepath.Join(r.dir, id) + if err := os.MkdirAll(p, 0700); err != nil { + return errors.Join(errors.New("failed to create directory for request"), err) + } + + successful := false + defer func() { + if !successful { + clean := exec.Command("git", "clean", "-xfd") + clean.Path = r.dir + _ = clean.Run() + log.Printf("action not successful, rollback...\n") + reset := exec.Command("git", "reset", "--hard") + reset.Path = r.dir + _ = reset.Run() + } + }() + + f, err := os.Create(filepath.Join(p, fmt.Sprintf( + "%016x_%s.md", + time.Now().Unix(), + GitUserName(), + ))) + if err != nil { + return errors.Join(errors.New("failed to create file for request"), err) + } + + if _, err := f.Write([]byte(initialMessage)); err != nil { + return errors.Join(errors.New("failed to write to file for request"), err) + } + + if err := r.repo.Push(&git.PushOptions{Atomic: true}); err != nil { + return errors.Join(errors.New("failed to push request"), err) + } + + successful = true return nil } diff --git a/internal/roast/roast.go b/internal/roast/roast.go index 5487b1a..61218d3 100644 --- a/internal/roast/roast.go +++ b/internal/roast/roast.go @@ -169,6 +169,12 @@ func Open() (*Roast, error) { return nil, errors.Join(fmt.Errorf("failed to open roast repo %s", p), err) } + pull := exec.Command("git", "pull", "--force") + pull.Dir = p + if err := pull.Run(); err != nil { + return nil, errors.Join(fmt.Errorf("failed to pull roast repo %s", p), err) + } + return &Roast{ repo: roastRepo, dir: p, diff --git a/internal/util/textedit.go b/internal/util/textedit.go new file mode 100644 index 0000000..476132d --- /dev/null +++ b/internal/util/textedit.go @@ -0,0 +1,52 @@ +package util + +import ( + "context" + "errors" + "io" + "os" + "os/exec" + "strings" + "time" +) + +func Textedit(text string) (string, error) { + f, err := os.CreateTemp("", "git-roast-*.md") + if err != nil { + return text, errors.Join(errors.New("failed to create initial message in request"), err) + } + fp := f.Name() + defer os.Remove(fp) + f.Close() + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute) + defer cancel() + if err := exec.CommandContext(ctx, editor(), fp).Run(); err != nil { + return text, errors.Join(errors.New("failed to run text editor"), err) + } + + f, err = os.OpenFile(fp, os.O_RDONLY|os.O_SYNC, 0) + if err != nil { + return text, errors.Join(errors.New("failed to open temp file"), err) + } + defer f.Close() + + newContent, err := io.ReadAll(f) + if err != nil { + return text, errors.Join(errors.New("failed to read from temp file"), err) + } + return string(newContent), nil +} + +func editor() string { + if gitCoreEditor, err := exec.Command("git", "config", "--global", "core.editor").Output(); err == nil { + return strings.TrimSpace(string(gitCoreEditor)) + } + if gitEditor, ok := os.LookupEnv("GIT_EDITOR"); ok { + return gitEditor + } + if editor, ok := os.LookupEnv("EDITOR"); ok { + return editor + } + + return "vim" +}