Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
b2d41bceb1 | |||
a49f79a06e |
@ -1,5 +1,10 @@
|
|||||||
package roast
|
package roast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
func (r *Roast) CurrentBranchName() (string, bool) {
|
func (r *Roast) CurrentBranchName() (string, bool) {
|
||||||
head, err := r.repo.Head()
|
head, err := r.repo.Head()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -8,3 +13,17 @@ func (r *Roast) CurrentBranchName() (string, bool) {
|
|||||||
|
|
||||||
return head.Name().Short(), true
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git-roast/internal/log"
|
"git-roast/internal/log"
|
||||||
|
"git-roast/internal/util"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *Roast) Request(from string, into string) error {
|
func (r *Roast) Request(from string, into string) error {
|
||||||
@ -13,19 +19,72 @@ func (r *Roast) Request(from string, into string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Join(fmt.Errorf("failed to get source branch %s", from), err)
|
return errors.Join(fmt.Errorf("failed to get source branch %s", from), err)
|
||||||
}
|
}
|
||||||
|
log.Debugf("branch %s found\n", sourceBranch.Name)
|
||||||
|
|
||||||
targetBranch, err := r.repo.Branch(into)
|
targetBranch, err := r.repo.Branch(into)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Join(fmt.Errorf("failed to get target branch %s", from), err)
|
return errors.Join(fmt.Errorf("failed to get target branch %s", from), err)
|
||||||
}
|
}
|
||||||
|
log.Debugf("branch %s found\n", targetBranch.Name)
|
||||||
|
|
||||||
id := fmt.Sprintf(
|
id := url.PathEscape(fmt.Sprintf(
|
||||||
"from_%s_into_%s",
|
"%016x_from_%s_into_%s",
|
||||||
|
time.Now().Unix(),
|
||||||
sourceBranch.Name,
|
sourceBranch.Name,
|
||||||
targetBranch.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.AddAll(); err != nil {
|
||||||
|
return errors.Join(errors.New("failed to add changes before commit"), err)
|
||||||
|
}
|
||||||
|
if err := r.Commit(id); err != nil {
|
||||||
|
return errors.Join(errors.New("failed to commit changes before push request"), err)
|
||||||
|
}
|
||||||
|
if err := r.Push(); err != nil {
|
||||||
|
return errors.Join(errors.New("failed to push request"), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
successful = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -169,8 +169,55 @@ func Open() (*Roast, error) {
|
|||||||
return nil, errors.Join(fmt.Errorf("failed to open roast repo %s", p), err)
|
return nil, errors.Join(fmt.Errorf("failed to open roast repo %s", p), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Roast{
|
r := &Roast{
|
||||||
repo: roastRepo,
|
repo: roastRepo,
|
||||||
dir: p,
|
dir: p,
|
||||||
}, nil
|
}
|
||||||
|
|
||||||
|
return r, r.Pull()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Roast) Pull() error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
log.Debugf("git pull --force\n")
|
||||||
|
pullCmd := exec.CommandContext(ctx, "git", "pull", "--force")
|
||||||
|
pullCmd.Dir = r.dir
|
||||||
|
pullCmd.Stdin = os.Stdin
|
||||||
|
pullCmd.Stdout = os.Stdout
|
||||||
|
pullCmd.Stderr = os.Stderr
|
||||||
|
return pullCmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Roast) AddAll() error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
log.Debugf("git add .\n")
|
||||||
|
addCmd := exec.CommandContext(ctx, "git", "add", ".")
|
||||||
|
addCmd.Dir = r.dir
|
||||||
|
return addCmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Roast) Commit(m string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
log.Debugf("git commit\n")
|
||||||
|
commitCmd := exec.CommandContext(ctx, "git", "commit", "-m", m)
|
||||||
|
commitCmd.Dir = r.dir
|
||||||
|
commitCmd.Stdin = os.Stdin
|
||||||
|
commitCmd.Stdout = os.Stdout
|
||||||
|
commitCmd.Stderr = os.Stderr
|
||||||
|
return commitCmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Roast) Push() error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
log.Debugf("git push --atomic\n")
|
||||||
|
pushCmd := exec.CommandContext(ctx, "git", "push", "--atomic")
|
||||||
|
pushCmd.Dir = r.dir
|
||||||
|
pushCmd.Stdin = os.Stdin
|
||||||
|
pushCmd.Stdout = os.Stdout
|
||||||
|
pushCmd.Stderr = os.Stderr
|
||||||
|
return pushCmd.Run()
|
||||||
}
|
}
|
||||||
|
60
internal/util/textedit.go
Normal file
60
internal/util/textedit.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"git-roast/internal/log"
|
||||||
|
"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.Write([]byte(text))
|
||||||
|
f.Close()
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
ed := editor()
|
||||||
|
log.Debugf("editing message using %s\n", ed)
|
||||||
|
edCmd := exec.CommandContext(ctx, ed, fp)
|
||||||
|
edCmd.Stderr = os.Stderr
|
||||||
|
edCmd.Stdout = os.Stdout
|
||||||
|
edCmd.Stdin = os.Stdin
|
||||||
|
if err := edCmd.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"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user