未验证 提交 9fc6bc85 编写于 作者: M Mislav Marohnić 提交者: GitHub

Merge pull request #1660 from github/commentchar-auto

Support for `commentchar=auto`, always respect `--edit`
......@@ -357,43 +357,39 @@ func createIssue(cmd *Command, args *Args) {
gh := github.NewClient(project.Host)
var title string
var body string
var editor *github.Editor
messageBuilder := &github.MessageBuilder{
Filename: "ISSUE_EDITMSG",
Title: "issue",
}
messageBuilder.AddCommentedSection(fmt.Sprintf(`Creating an issue for %s
Write a message for this issue. The first block of
text is the title and the rest is the description.`, project))
if cmd.FlagPassed("message") {
title, body = readMsg(flagIssueMessage)
messageBuilder.Message = flagIssueMessage
messageBuilder.Edit = flagIssueEdit
} else if cmd.FlagPassed("file") {
title, body, editor, err = readMsgFromFile(flagIssueFile, flagIssueEdit, "ISSUE", "issue")
messageBuilder.Message, err = msgFromFile(flagIssueFile)
utils.Check(err)
messageBuilder.Edit = flagIssueEdit
} else {
cs := git.CommentChar()
message := strings.Replace(fmt.Sprintf(`
# Creating an issue for %s
#
# Write a message for this issue. The first block of
# text is the title and the rest is the description.
`, project), "#", cs, -1)
messageBuilder.Edit = true
workdir, _ := git.WorkdirName()
if workdir != "" {
template, err := github.ReadTemplate(github.IssueTemplate, workdir)
utils.Check(err)
if template != "" {
message = template + "\n" + message
messageBuilder.Message = template
}
}
editor, err := github.NewEditor("ISSUE", "issue", message)
utils.Check(err)
title, body, err = editor.EditTitleAndBody()
utils.Check(err)
}
if editor != nil {
defer editor.DeleteFile()
}
title, body, err := messageBuilder.Extract()
utils.Check(err)
if title == "" {
utils.Check(fmt.Errorf("Aborting creation due to empty issue title"))
......@@ -425,4 +421,6 @@ func createIssue(cmd *Command, args *Args) {
printBrowseOrCopy(args, issue.HtmlUrl, flagIssueBrowse, flagIssueCopy)
}
messageBuilder.Cleanup()
}
......@@ -202,8 +202,10 @@ func pullRequest(cmd *Command, args *Args) {
}
}
var editor *github.Editor
var title, body string
messageBuilder := &github.MessageBuilder{
Filename: "PULLREQ_EDITMSG",
Title: "pull request",
}
baseTracking := base
headTracking := head
......@@ -223,27 +225,56 @@ func pullRequest(cmd *Command, args *Args) {
utils.Check(fmt.Errorf("Can't find remote for %s", head))
}
messageBuilder.AddCommentedSection(fmt.Sprintf(`Requesting a pull to %s from %s
Write a message for this pull request. The first block
of text is the title and the rest is the description.`, fullBase, fullHead))
if cmd.FlagPassed("message") {
title, body = readMsg(flagPullRequestMessage)
messageBuilder.Message = flagPullRequestMessage
messageBuilder.Edit = flagPullRequestEdit
} else if cmd.FlagPassed("file") {
title, body, editor, err = readMsgFromFile(flagPullRequestFile, flagPullRequestEdit, "PULLREQ", "pull request")
messageBuilder.Message, err = msgFromFile(flagPullRequestFile)
utils.Check(err)
messageBuilder.Edit = flagPullRequestEdit
} else if flagPullRequestIssue == "" {
messageBuilder.Edit = true
headForMessage := headTracking
if flagPullRequestPush {
headForMessage = head
}
message, err := createPullRequestMessage(baseTracking, headForMessage, fullBase, fullHead)
utils.Check(err)
message := ""
commitLogs := ""
editor, err = github.NewEditor("PULLREQ", "pull request", message)
utils.Check(err)
commits, _ := git.RefList(baseTracking, headForMessage)
if len(commits) == 1 {
message, err = git.Show(commits[0])
utils.Check(err)
} else if len(commits) > 1 {
commitLogs, err = git.Log(baseTracking, headForMessage)
utils.Check(err)
}
title, body, err = editor.EditTitleAndBody()
utils.Check(err)
if commitLogs != "" {
messageBuilder.AddCommentedSection("\nChanges:\n\n" + strings.TrimSpace(commitLogs))
}
workdir, _ := git.WorkdirName()
if workdir != "" {
template, _ := github.ReadTemplate(github.PullRequestTemplate, workdir)
if template != "" {
message = message + "\n\n" + template
}
}
messageBuilder.Message = message
}
title, body, err := messageBuilder.Extract()
utils.Check(err)
if title == "" && flagPullRequestIssue == "" {
utils.Check(fmt.Errorf("Aborting due to empty pull request title"))
}
......@@ -311,8 +342,8 @@ func pullRequest(cmd *Command, args *Args) {
}
}
if err == nil && editor != nil {
defer editor.DeleteFile()
if err == nil {
defer messageBuilder.Cleanup()
}
utils.Check(err)
......@@ -361,49 +392,6 @@ func pullRequest(cmd *Command, args *Args) {
printBrowseOrCopy(args, pullRequestURL, flagPullRequestBrowse, flagPullRequestCopy)
}
func createPullRequestMessage(base, head, fullBase, fullHead string) (string, error) {
var (
defaultMsg string
commitLogs string
err error
)
commits, _ := git.RefList(base, head)
if len(commits) == 1 {
defaultMsg, err = git.Show(commits[0])
if err != nil {
return "", err
}
} else if len(commits) > 1 {
commitLogs, err = git.Log(base, head)
if err != nil {
return "", err
}
}
workdir, _ := git.WorkdirName()
if workdir != "" {
template, err := github.ReadTemplate(github.PullRequestTemplate, workdir)
if err != nil {
return "", err
} else if template != "" {
if defaultMsg == "" {
defaultMsg = "\n\n" + template
} else {
parts := strings.SplitN(defaultMsg, "\n\n", 2)
defaultMsg = parts[0] + "\n\n" + template
if len(parts) > 1 && parts[1] != "" {
defaultMsg = defaultMsg + "\n\n" + parts[1]
}
}
}
}
cs := git.CommentChar()
return renderPullRequestTpl(defaultMsg, cs, fullBase, fullHead, commitLogs)
}
func parsePullRequestProject(context *github.Project, s string) (p *github.Project, ref string) {
p = context
ref = s
......
package commands
import (
"bytes"
"fmt"
"regexp"
"strings"
"text/template"
)
const pullRequestTmpl = `{{if .InitMsg}}{{.InitMsg}}
{{end}}
{{.CS}} Requesting a pull to {{.Base}} from {{.Head}}
{{.CS}}
{{.CS}} Write a message for this pull request. The first block
{{.CS}} of text is the title and the rest is the description.{{if .HasCommitLogs}}
{{.CS}}
{{.CS}} Changes:
{{.CS}}
{{.FormattedCommitLogs}}{{end}}`
type pullRequestMsg struct {
InitMsg string
CS string
Base string
Head string
CommitLogs string
}
func (p *pullRequestMsg) HasCommitLogs() bool {
return len(p.CommitLogs) > 0
}
func (p *pullRequestMsg) FormattedCommitLogs() string {
startRegexp := regexp.MustCompilePOSIX("^")
endRegexp := regexp.MustCompilePOSIX(" +$")
commitLogs := strings.TrimSpace(p.CommitLogs)
commitLogs = startRegexp.ReplaceAllString(commitLogs, fmt.Sprintf("%s ", p.CS))
commitLogs = endRegexp.ReplaceAllString(commitLogs, "")
return commitLogs
}
func renderPullRequestTpl(initMsg, cs, base, head string, commitLogs string) (string, error) {
t, err := template.New("pullRequestTmpl").Parse(pullRequestTmpl)
if err != nil {
return "", err
}
msg := &pullRequestMsg{
InitMsg: initMsg,
CS: cs,
Base: base,
Head: head,
CommitLogs: commitLogs,
}
var b bytes.Buffer
err = t.Execute(&b, msg)
return b.String(), err
}
package commands
import (
"testing"
"github.com/bmizerany/assert"
)
func TestRenderPullRequestTpl(t *testing.T) {
msg, err := renderPullRequestTpl("init", "#", "base", "head", "one\ntwo")
assert.Equal(t, nil, err)
expMsg := `init
# Requesting a pull to base from head
#
# Write a message for this pull request. The first block
# of text is the title and the rest is the description.
#
# Changes:
#
# one
# two`
assert.Equal(t, expMsg, msg)
}
......@@ -7,7 +7,6 @@ import (
"path/filepath"
"strings"
"github.com/github/hub/git"
"github.com/github/hub/github"
"github.com/github/hub/ui"
"github.com/github/hub/utils"
......@@ -297,27 +296,30 @@ func createRelease(cmd *Command, args *Args) {
gh := github.NewClient(project.Host)
var title string
var body string
var editor *github.Editor
messageBuilder := &github.MessageBuilder{
Filename: "RELEASE_EDITMSG",
Title: "release",
}
messageBuilder.AddCommentedSection(fmt.Sprintf(`Creating release %s for %s
Write a message for this release. The first block of
text is the title and the rest is the description.`, tagName, project))
if cmd.FlagPassed("message") {
title, body = readMsg(flagReleaseMessage)
messageBuilder.Message = flagReleaseMessage
messageBuilder.Edit = flagReleaseEdit
} else if cmd.FlagPassed("file") {
title, body, editor, err = readMsgFromFile(flagReleaseFile, flagReleaseEdit, "RELEASE", "release")
messageBuilder.Message, err = msgFromFile(flagReleaseFile)
utils.Check(err)
messageBuilder.Edit = flagReleaseEdit
} else {
cs := git.CommentChar()
message, err := renderReleaseTpl("Creating", cs, tagName, project.String(), flagReleaseCommitish)
utils.Check(err)
editor, err := github.NewEditor("RELEASE", "release", message)
utils.Check(err)
title, body, err = editor.EditTitleAndBody()
utils.Check(err)
messageBuilder.Edit = true
}
title, body, err := messageBuilder.Extract()
utils.Check(err)
if title == "" {
utils.Check(fmt.Errorf("Aborting release due to empty release title"))
}
......@@ -343,9 +345,7 @@ func createRelease(cmd *Command, args *Args) {
printBrowseOrCopy(args, release.HtmlUrl, flagReleaseBrowse, flagReleaseCopy)
}
if editor != nil {
editor.DeleteFile()
}
messageBuilder.Cleanup()
uploadAssets(gh, release, flagReleaseAssets, args)
}
......@@ -369,11 +369,9 @@ func editRelease(cmd *Command, args *Args) {
utils.Check(err)
params := map[string]interface{}{}
commitish := release.TargetCommitish
if cmd.FlagPassed("commitish") {
params["target_commitish"] = flagReleaseCommitish
commitish = flagReleaseCommitish
}
if cmd.FlagPassed("draft") {
......@@ -384,34 +382,33 @@ func editRelease(cmd *Command, args *Args) {
params["prerelease"] = flagReleasePrerelease
}
var title string
var body string
var editor *github.Editor
messageBuilder := &github.MessageBuilder{
Filename: "RELEASE_EDITMSG",
Title: "release",
}
messageBuilder.AddCommentedSection(fmt.Sprintf(`Editing release %s for %s
Write a message for this release. The first block of
text is the title and the rest is the description.`, tagName, project))
if cmd.FlagPassed("message") {
title, body = readMsg(flagReleaseMessage)
messageBuilder.Message = flagReleaseMessage
messageBuilder.Edit = flagReleaseEdit
} else if cmd.FlagPassed("file") {
title, body, editor, err = readMsgFromFile(flagReleaseFile, flagReleaseEdit, "RELEASE", "release")
messageBuilder.Message, err = msgFromFile(flagReleaseFile)
utils.Check(err)
if title == "" {
utils.Check(fmt.Errorf("Aborting editing due to empty release title"))
}
messageBuilder.Edit = flagReleaseEdit
} else {
cs := git.CommentChar()
message, err := renderReleaseTpl("Editing", cs, tagName, project.String(), commitish)
utils.Check(err)
message = fmt.Sprintf("%s\n\n%s\n%s", release.Name, release.Body, message)
editor, err := github.NewEditor("RELEASE", "release", message)
utils.Check(err)
messageBuilder.Edit = true
messageBuilder.Message = fmt.Sprintf("%s\n\n%s", release.Name, release.Body)
}
title, body, err = editor.EditTitleAndBody()
utils.Check(err)
title, body, err := messageBuilder.Extract()
utils.Check(err)
if title == "" {
utils.Check(fmt.Errorf("Aborting editing due to empty release title"))
}
if title == "" && !cmd.FlagPassed("message") {
utils.Check(fmt.Errorf("Aborting editing due to empty release title"))
}
if title != "" {
......@@ -429,9 +426,7 @@ func editRelease(cmd *Command, args *Args) {
utils.Check(err)
}
if editor != nil {
editor.DeleteFile()
}
messageBuilder.Cleanup()
}
uploadAssets(gh, release, flagReleaseAssets, args)
......
package commands
import (
"bytes"
"text/template"
)
const releaseTmpl = `
{{.CS}} {{.Operation}} release {{.TagName}} for {{.ProjectName}}{{if .BranchName}} from {{.BranchName}}{{end}}
{{.CS}}
{{.CS}} Write a message for this release. The first block of
{{.CS}} text is the title and the rest is the description.`
type releaseMsg struct {
Operation string
CS string
TagName string
ProjectName string
BranchName string
}
func renderReleaseTpl(operation, cs, tagName, projectName, branchName string) (string, error) {
t, err := template.New("releaseTmpl").Parse(releaseTmpl)
if err != nil {
return "", err
}
msg := &releaseMsg{
Operation: operation,
CS: cs,
TagName: tagName,
ProjectName: projectName,
BranchName: branchName,
}
var b bytes.Buffer
err = t.Execute(&b, msg)
return b.String(), err
}
package commands
import (
"testing"
"github.com/bmizerany/assert"
)
func TestRenderReleaseTpl(t *testing.T) {
msg, err := renderReleaseTpl("Creating", "#", "1.0", "github/hub", "master")
assert.Equal(t, nil, err)
expMsg := `
# Creating release 1.0 for github/hub from master
#
# Write a message for this release. The first block of
# text is the title and the rest is the description.`
assert.Equal(t, expMsg, msg)
}
......@@ -90,25 +90,6 @@ func isEmptyDir(path string) bool {
return match == nil
}
func readMsgFromFile(filename string, edit bool, editorPrefix, editorTopic string) (title, body string, editor *github.Editor, err error) {
message, err := msgFromFile(filename)
if err != nil {
return
}
if edit {
editor, err = github.NewEditor(editorPrefix, editorTopic, message)
if err != nil {
return
}
title, body, err = editor.EditTitleAndBody()
return
} else {
title, body = readMsg(message)
return
}
}
func msgFromFile(filename string) (string, error) {
var content []byte
var err error
......@@ -125,16 +106,6 @@ func msgFromFile(filename string) (string, error) {
return strings.Replace(string(content), "\r\n", "\n", -1), nil
}
func readMsg(message string) (title, body string) {
parts := strings.SplitN(message, "\n\n", 2)
title = strings.TrimSpace(strings.Replace(parts[0], "\n", " ", -1))
if len(parts) > 1 {
body = strings.TrimSpace(parts[1])
}
return
}
func printBrowseOrCopy(args *Args, msg string, openBrowser bool, performCopy bool) {
if performCopy {
if err := clipboard.WriteAll(msg); err != nil {
......
......@@ -8,24 +8,6 @@ import (
"github.com/bmizerany/assert"
)
func TestReadMsg(t *testing.T) {
title, body := readMsg("")
assert.Equal(t, "", title)
assert.Equal(t, "", body)
title, body = readMsg("my pull title")
assert.Equal(t, "my pull title", title)
assert.Equal(t, "", body)
title, body = readMsg("my pull title\n\nmy description\n\nanother line")
assert.Equal(t, "my pull title", title)
assert.Equal(t, "my description\n\nanother line", body)
title, body = readMsg("my pull\ntitle\n\nmy description\n\nanother line")
assert.Equal(t, "my pull title", title)
assert.Equal(t, "my description\n\nanother line", body)
}
func TestDirIsNotEmpty(t *testing.T) {
dir := createTempDir(t)
defer os.RemoveAll(dir)
......
......@@ -317,6 +317,30 @@ Feature: hub issue
https://github.com/github/hub/issues/1337\n
"""
Scenario: Editing empty issue message
Given the git commit editor is "vim"
And the text editor adds:
"""
hello
my nice issue
"""
Given the GitHub API server:
"""
post('/repos/github/hub/issues') {
assert :title => "hello",
:body => "my nice issue"
status 201
json :html_url => "https://github.com/github/hub/issues/1337"
}
"""
When I successfully run `hub issue create -m '' --edit`
Then the output should contain exactly:
"""
https://github.com/github/hub/issues/1337\n
"""
Scenario: Issue template
Given the git commit editor is "vim"
And the text editor adds:
......
......@@ -101,11 +101,11 @@ Feature: hub pull-request
halt 400 if request.content_charset != 'utf-8'
assert :title => 'Commit title',
:body => <<BODY.chomp
Commit body
This is the pull request template
Another line of template
Commit body
BODY
status 201
json :html_url => "the://url"
......
......@@ -192,13 +192,26 @@ func (r *Range) IsAncestor() bool {
return cmd.Success()
}
func CommentChar() string {
func CommentChar(text string) (string, error) {
char, err := Config("core.commentchar")
if err != nil {
char = "#"
return "#", nil
} else if char == "auto" {
lines := strings.Split(text, "\n")
commentCharCandidates := strings.Split("#;@!$%^&|:", "")
candidateLoop:
for _, candidate := range commentCharCandidates {
for _, line := range lines {
if strings.HasPrefix(line, candidate) {
continue candidateLoop
}
}
return candidate, nil
}
return "", fmt.Errorf("unable to select a comment character that is not used in the current message")
} else {
return char, nil
}
return char
}
func Show(sha string) (string, error) {
......
......@@ -154,3 +154,33 @@ func TestRemotes(t *testing.T) {
}
}
}
func TestCommentChar(t *testing.T) {
repo := fixtures.SetupTestRepo()
defer repo.TearDown()
char, err := CommentChar("")
assert.Equal(t, nil, err)
assert.Equal(t, "#", char)
SetGlobalConfig("core.commentchar", ";")
char, err = CommentChar("")
assert.Equal(t, nil, err)
assert.Equal(t, ";", char)
SetGlobalConfig("core.commentchar", "auto")
char, err = CommentChar("")
assert.Equal(t, nil, err)
assert.Equal(t, "#", char)
char, err = CommentChar("hello\n#nice\nworld")
assert.Equal(t, nil, err)
assert.Equal(t, ";", char)
char, err = CommentChar("hello\n#nice\n;world")
assert.Equal(t, nil, err)
assert.Equal(t, "@", char)
char, err = CommentChar("#\n;\n@\n!\n$\n%\n^\n&\n|\n:")
assert.Equal(t, "unable to select a comment character that is not used in the current message", err.Error())
}
......@@ -85,15 +85,7 @@ const crashReportTmpl = "Crash report - %v\n\n" +
"Error (%s): `%v`\n\n" +
"Stack:\n\n```\n%s\n```\n\n" +
"Runtime:\n\n```\n%s\n```\n\n" +
"Version:\n\n```\n%s\n```\n" +
`
# Creating crash report:
#
# This information will be posted as a new issue under github/hub.
# We're NOT including any information about the command that you were executing,
# but knowing a little bit more about it would really help us to solve this problem.
# Feel free to modify the title and the description for this issue.
`
"Version:\n\n```\n%s\n```\n"
func reportTitleAndBody(reportedError error, stack string) (title, body string, err error) {
errType := reflect.TypeOf(reportedError).String()
......@@ -108,14 +100,26 @@ func reportTitleAndBody(reportedError error, stack string) (title, body string,
fullVersion,
)
editor, err := NewEditor("CRASH_REPORT", "crash report", message)
if err != nil {
return "", "", err
messageBuilder := &MessageBuilder{
Filename: "CRASH_REPORT",
Title: "crash report",
Message: message,
Edit: true,
}
messageBuilder.AddCommentedSection(`Creating crash report:
This information will be posted as a new issue under github/hub.
We're NOT including any information about the command that you were executing,
but knowing a little bit more about it would really help us to solve this problem.
Feel free to modify the title and the description for this issue.`)
defer editor.DeleteFile()
title, body, err = messageBuilder.Extract()
if err != nil {
return
}
defer messageBuilder.Cleanup()
return editor.EditTitleAndBody()
return
}
func runtimeInfo() string {
......
......@@ -4,7 +4,6 @@ import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
......@@ -15,18 +14,22 @@ import (
"github.com/github/hub/git"
)
func NewEditor(filePrefix, topic, message string) (editor *Editor, err error) {
messageFile, err := getMessageFile(filePrefix)
func NewEditor(filename, topic, message string) (editor *Editor, err error) {
gitDir, err := git.Dir()
if err != nil {
return
}
messageFile := filepath.Join(gitDir, filename)
program, err := git.Editor()
if err != nil {
return
}
cs := git.CommentChar()
cs, err := git.CommentChar(message)
if err != nil {
return
}
editor = &Editor{
Program: program,
......@@ -49,24 +52,40 @@ type Editor struct {
openEditor func(program, file string) error
}
func (e *Editor) AddCommentedSection(text string) {
startRegexp := regexp.MustCompilePOSIX("^")
endRegexp := regexp.MustCompilePOSIX(" +$")
commentedText := startRegexp.ReplaceAllString(text, e.CS+" ")
commentedText = endRegexp.ReplaceAllString(commentedText, "")
e.Message = e.Message + "\n" + commentedText
}
func (e *Editor) DeleteFile() error {
return os.Remove(e.File)
}
func (e *Editor) EditTitleAndBody() (title, body string, err error) {
content, err := e.openAndEdit()
func (e *Editor) EditContent() (content string, err error) {
b, err := e.openAndEdit()
if err != nil {
return
}
content = bytes.TrimSpace(content)
reader := bytes.NewReader(content)
title, body, err = readTitleAndBody(reader, e.CS)
b = bytes.TrimSpace(b)
reader := bytes.NewReader(b)
scanner := bufio.NewScanner(reader)
unquotedLines := []string{}
if err != nil || title == "" {
defer e.DeleteFile()
for scanner.Scan() {
line := scanner.Text()
if e.CS == "" || !strings.HasPrefix(line, e.CS) {
unquotedLines = append(unquotedLines, line)
}
}
if err = scanner.Err(); err != nil {
return
}
content = strings.Join(unquotedLines, "\n")
return
}
......@@ -89,8 +108,7 @@ func (e *Editor) openAndEdit() (content []byte, err error) {
}
func (e *Editor) writeContent() (err error) {
// only write message if file doesn't exist
if !e.isFileExist() && e.Message != "" {
if !e.isFileExist() {
err = ioutil.WriteFile(e.File, []byte(e.Message), 0644)
if err != nil {
return
......@@ -122,43 +140,3 @@ func openTextEditor(program, file string) error {
return editCmd.Spawn()
}
func readTitleAndBody(reader io.Reader, cs string) (title, body string, err error) {
var titleParts, bodyParts []string
r := regexp.MustCompile("\\S")
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, cs) {
continue
}
if len(bodyParts) == 0 && r.MatchString(line) {
titleParts = append(titleParts, line)
} else {
bodyParts = append(bodyParts, line)
}
}
if err = scanner.Err(); err != nil {
return
}
title = strings.Join(titleParts, " ")
title = strings.TrimSpace(title)
body = strings.Join(bodyParts, "\n")
body = strings.TrimSpace(body)
return
}
func getMessageFile(about string) (string, error) {
gitDir, err := git.Dir()
if err != nil {
return "", err
}
return filepath.Join(gitDir, fmt.Sprintf("%s_EDITMSG", about)), nil
}
package github
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strings"
"testing"
"github.com/bmizerany/assert"
......@@ -78,90 +76,3 @@ func TestEditor_openAndEdit_writeFileIfNotExist(t *testing.T) {
assert.Equal(t, nil, err)
assert.Equal(t, "hello", string(content))
}
func TestEditor_EditTitleAndBodyEmptyTitle(t *testing.T) {
tempFile, _ := ioutil.TempFile("", "PULLREQ")
tempFile.Close()
editor := Editor{
Program: "memory",
File: tempFile.Name(),
CS: "#",
openEditor: func(program string, file string) error {
assert.Equal(t, "memory", program)
assert.Equal(t, tempFile.Name(), file)
return ioutil.WriteFile(file, []byte(""), 0644)
},
}
title, body, err := editor.EditTitleAndBody()
assert.Equal(t, nil, err)
assert.Equal(t, "", title)
assert.Equal(t, "", body)
_, err = os.Stat(tempFile.Name())
assert.T(t, os.IsNotExist(err))
}
func TestEditor_EditTitleAndBody(t *testing.T) {
tempFile, _ := ioutil.TempFile("", "PULLREQ")
tempFile.Close()
editor := Editor{
Program: "memory",
File: tempFile.Name(),
CS: "#",
openEditor: func(program string, file string) error {
assert.Equal(t, "memory", program)
assert.Equal(t, tempFile.Name(), file)
message := `A title
A title continues
A body
A body continues
# comment
`
return ioutil.WriteFile(file, []byte(message), 0644)
},
}
title, body, err := editor.EditTitleAndBody()
assert.Equal(t, nil, err)
assert.Equal(t, "A title A title continues", title)
assert.Equal(t, "A body\nA body continues", body)
}
func TestReadTitleAndBody(t *testing.T) {
message := `A title
A title continues
A body
A body continues
# comment
`
r := strings.NewReader(message)
reader := bufio.NewReader(r)
title, body, err := readTitleAndBody(reader, "#")
assert.Equal(t, nil, err)
assert.Equal(t, "A title A title continues", title)
assert.Equal(t, "A body\nA body continues", body)
message = `# Dat title
/ This line is commented out.
Dem body.
`
r = strings.NewReader(message)
reader = bufio.NewReader(r)
title, body, err = readTitleAndBody(reader, "/")
assert.Equal(t, nil, err)
assert.Equal(t, "# Dat title", title)
assert.Equal(t, "Dem body.", body)
}
func TestGetMessageFile(t *testing.T) {
gitPullReqMsgFile, _ := getMessageFile("PULLREQ")
assert.T(t, strings.Contains(gitPullReqMsgFile, "PULLREQ_EDITMSG"))
}
package github
import (
"regexp"
"strings"
)
type MessageBuilder struct {
Title string
Filename string
Message string
Edit bool
commentedSections []string
editor *Editor
}
func (b *MessageBuilder) AddCommentedSection(section string) {
b.commentedSections = append(b.commentedSections, section)
}
func (b *MessageBuilder) Extract() (title, body string, err error) {
content := b.Message
if b.Edit {
b.editor, err = NewEditor(b.Filename, b.Title, content)
if err != nil {
return
}
for _, section := range b.commentedSections {
b.editor.AddCommentedSection(section)
}
content, err = b.editor.EditContent()
if err != nil {
return
}
} else {
nl := regexp.MustCompile(`\r?\n`)
content = nl.ReplaceAllString(content, "\n")
}
parts := strings.SplitN(content, "\n\n", 2)
if len(parts) >= 1 {
title = strings.TrimSpace(strings.Replace(parts[0], "\n", " ", -1))
}
if len(parts) >= 2 {
body = strings.TrimSpace(parts[1])
}
if title == "" {
defer b.Cleanup()
}
return
}
func (b *MessageBuilder) Cleanup() {
if b.editor != nil {
b.editor.DeleteFile()
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册