|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
const defaultCommitFileMsgTpl = `%s
|
|
|
|
|
|
|
|
# Please enter the commit message for your commit. Lines starting
|
|
|
|
# with '#' will be ignored, and an empty message aborts the commit.`
|
|
|
|
|
|
|
|
func tmpFileMsg(tpl string, args ...interface{}) (string, error) {
|
|
|
|
editor := os.Getenv("EDITOR")
|
|
|
|
if editor == "" {
|
|
|
|
return "", errors.New("EDITOR not set, please set it or use -msg in order to create your commit message")
|
|
|
|
} else if _, err := os.Stat(editor); err != nil {
|
|
|
|
return "", fmt.Errorf("could not stat EDITOR %q: %w", editor, err)
|
|
|
|
}
|
|
|
|
|
normalize how git commits are interacted with, including changing VerifyComit -> VerifyCommits
---
type: change
message: |-
normalize how git commits are interacted with, including changing VerifyComit -> VerifyCommits
This commit attempts to normalize git commit interactions in order to reduce
the amount of manual `GitRepo.CommitObject`, `GitRepo.TreeObject`,
`Commit.UnmarshalText`, and `Commit.Interface` calls are done, by creating a
single structure (`GitCommit`) which holds the output of those calls, and is
only created by a single method (`GetGitCommit`), which is then used by a bunch
of other methods to expand its functionality, including implementing a range
request which can be used by verify and the pre-receive hook (though it's only
used by the hook, currently).
change_hash: AMae4PL6+jrxhn2KEGHejstcdT37Gw/jjkl/UuovHcgd
credentials:
- type: pgp_signature
pub_key_id: 95C46FA6A41148AC
body: iQIzBAABAgAdFiEEJ6tQKp6olvZKJ0lwlcRvpqQRSKwFAl5uhvoACgkQlcRvpqQRSKzJrhAAqi2LEQVTyVktfsOBv/CZmefclLLqWTChVoeIZt2EAGDDGygmrx88hI0SEAviOzPMn0kiZFDeY5k7ICJMhJ9RVDU9WjH7fbOboMJW19rVhx6Ke/M2ERtrT0OFLRmFVJVDM0P8SEheQvR3HE/iiypBICVCtp+meHEq9mOJWZlZnoCqMaulAy/Nnq4N1VD0yPPlr16+yxMqedKHcgKbcH8K61ltNAjXDT+tCWwCq1huA5MVSuTm5EwqIeKPN6JKgwATv8Ku2GhYZWHSGUwecP1J3x2XTDPeChCQVDpC232Pxwk8z/D36F3J/XOfkdl0QYQ077xL1IJfYOnuuHir47CokDf3G0XCQnJ/+X4pZdtP387rc045o/2bhUi2U4eJ5HgS7Hvyi6EApT0Czv7SeJePTvdnRUYse8ZYuIwYXj5GWWxnbKQzLpyjcHdQc2a3B3RN84zXqqAOS6ObFrFPZQIfz2rfQojZN8kvcmUvYhJXSaT65XmqFjyJ4n6grrEnK/N+MfbnpzyF/yvlzxWPqGFQOQj9meosbTAdgZbmdwYqa5r1ee8DmlkzNJJxze96h503a733yciN8Ef4hGZNlRV6YFegkK/cCgKaA4NCEALKb1t0Uri5gnPldXk4HsPF+23GANbE7mjytY8ra3fhXG4VhaFt/WsLg3Bu7djQ0H74y+g=
account: mediocregopher
4 years ago
|
|
|
tmpf, err := ioutil.TempFile("", "dehub.*.txt")
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("could not open temp file: %w", err)
|
|
|
|
}
|
|
|
|
tmpfName := tmpf.Name()
|
|
|
|
defer os.Remove(tmpfName)
|
|
|
|
|
|
|
|
tmpBody := bytes.NewBufferString(fmt.Sprintf(tpl, args...))
|
|
|
|
|
|
|
|
_, err = io.Copy(tmpf, tmpBody)
|
|
|
|
tmpf.Close()
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("could not write helper message to temp file %q: %w", tmpfName, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd := exec.Command(editor, tmpfName)
|
|
|
|
cmd.Stdin = os.Stdin
|
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
if err := cmd.Run(); err != nil {
|
|
|
|
return "", fmt.Errorf("error running '%s %q': %w", editor, tmpfName, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
body, err := ioutil.ReadFile(tmpfName)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("error retrieving message body from %q: %w", tmpfName, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
bodyFiltered := new(bytes.Buffer)
|
|
|
|
bodyBR := bufio.NewReader(bytes.NewBuffer(body))
|
|
|
|
for {
|
|
|
|
line, err := bodyBR.ReadString('\n')
|
|
|
|
if errors.Is(err, io.EOF) {
|
|
|
|
break
|
|
|
|
} else if err != nil {
|
|
|
|
return "", fmt.Errorf("error reading from buffered body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !strings.HasPrefix(strings.TrimSpace(line), "#") {
|
|
|
|
bodyFiltered.WriteString(line)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return strings.TrimSpace(bodyFiltered.String()), nil
|
|
|
|
}
|