pull_request.go 4.6 KB
Newer Older
1
package commands
J
Jingwen Owen Ou 已提交
2 3

import (
4
	"bufio"
J
Jingwen Owen Ou 已提交
5
	"fmt"
6 7 8 9
	"github.com/jingweno/gh/cmd"
	"github.com/jingweno/gh/git"
	"github.com/jingweno/gh/github"
	"github.com/jingweno/gh/utils"
J
Jingwen Owen Ou 已提交
10
	"io/ioutil"
J
Jingwen Owen Ou 已提交
11
	"log"
J
Jingwen Owen Ou 已提交
12 13
	"os"
	"regexp"
14
	"strings"
J
Jingwen Owen Ou 已提交
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
)

var cmdPullRequest = &Command{
	Run:   pullRequest,
	Usage: "pull-request [-f] [TITLE|-i ISSUE] [-b BASE] [-h HEAD]",
	Short: "Open a pull request on GitHub",
	Long: `Opens a pull request on GitHub for the project that the "origin" remote
points to. The default head of the pull request is the current branch.
Both base and head of the pull request can be explicitly given in one of
the following formats: "branch", "owner:branch", "owner/repo:branch".
This command will abort operation if it detects that the current topic
branch has local commits that are not yet pushed to its upstream branch
on the remote. To skip this check, use -f.

If TITLE is omitted, a text editor will open in which title and body of
the pull request can be entered in the same manner as git commit message.

If instead of normal TITLE an issue number is given with -i, the pull
request will be attached to an existing GitHub issue. Alternatively, instead
of title you can paste a full URL to an issue on GitHub.
`,
}

J
Jingwen Owen Ou 已提交
38
var flagPullRequestBase, flagPullRequestHead, flagPullRequestIssue string
J
Jingwen Owen Ou 已提交
39 40

func init() {
41
	cmdPullRequest.Flag.StringVar(&flagPullRequestBase, "b", "master", "BASE")
42
	cmdPullRequest.Flag.StringVar(&flagPullRequestHead, "h", "", "HEAD")
J
Jingwen Owen Ou 已提交
43
	cmdPullRequest.Flag.StringVar(&flagPullRequestIssue, "i", "", "ISSUE")
J
Jingwen Owen Ou 已提交
44 45 46
}

func pullRequest(cmd *Command, args []string) {
47 48 49 50 51
	var title, body string
	if len(args) == 1 {
		title = args[0]
	}

J
Jingwen Owen Ou 已提交
52
	repo := NewRepo(flagPullRequestBase, flagPullRequestHead)
J
Jingwen Owen Ou 已提交
53
	if title == "" && flagPullRequestIssue == "" {
54 55
		messageFile, err := git.PullReqMsgFile()
		utils.Check(err)
56

57 58
		err = writePullRequestChanges(repo, messageFile)
		utils.Check(err)
J
Jingwen Owen Ou 已提交
59

60 61
		editorPath, err := git.EditorPath()
		utils.Check(err)
62

63 64 65 66 67 68
		err = editTitleAndBody(editorPath, messageFile)
		utils.Check(err)

		title, body, err = readTitleAndBody(messageFile)
		utils.Check(err)
	}
69

J
Jingwen Owen Ou 已提交
70 71
	if title == "" && flagPullRequestIssue == "" {
		log.Fatal("Aborting due to empty pull request title or unspecified issue number")
72 73
	}

J
Jingwen Owen Ou 已提交
74
	params := github.PullRequestParams{title, body, repo.Base, repo.Head, flagPullRequestIssue}
J
Jingwen Owen Ou 已提交
75
	gh := github.New()
J
Jingwen Owen Ou 已提交
76
	pullRequestResponse, err := gh.CreatePullRequest(params)
77
	utils.Check(err)
J
Jingwen Owen Ou 已提交
78 79

	fmt.Println(pullRequestResponse.HtmlUrl)
80 81
}

82
func writePullRequestChanges(repo *Repo, messageFile string) error {
J
Jingwen Owen Ou 已提交
83 84 85 86
	message := `
# Requesting a pull to %s from %s
#
# Write a message for this pull reuqest. The first block
87 88 89 90 91
# of the text is the title and the rest is description.%s
`
	startRegexp := regexp.MustCompilePOSIX("^")
	endRegexp := regexp.MustCompilePOSIX(" +$")

J
Jingwen Owen Ou 已提交
92
	commitLogs, _ := git.Log(repo.Base, repo.Head)
93 94 95 96 97 98
	var changesMsg string
	if len(commitLogs) > 0 {
		commitLogs = strings.TrimSpace(commitLogs)
		commitLogs = startRegexp.ReplaceAllString(commitLogs, "# ")
		commitLogs = endRegexp.ReplaceAllString(commitLogs, "")
		changesMsg = `
J
Jingwen Owen Ou 已提交
99 100 101
#
# Changes:
#
J
Jingwen Owen Ou 已提交
102
%s`
103 104
		changesMsg = fmt.Sprintf(changesMsg, commitLogs)
	}
J
Jingwen Owen Ou 已提交
105

106
	message = fmt.Sprintf(message, repo.FullBase(), repo.FullHead(), changesMsg)
J
Jingwen Owen Ou 已提交
107 108 109 110

	return ioutil.WriteFile(messageFile, []byte(message), 0644)
}

J
Jingwen Owen Ou 已提交
111
func editTitleAndBody(editorPath, messageFile string) error {
112
	editCmd := cmd.New(editorPath)
J
Jingwen Owen Ou 已提交
113 114
	r := regexp.MustCompile("[mg]?vi[m]$")
	if r.MatchString(editorPath) {
J
Jingwen Owen Ou 已提交
115
		editCmd.WithArg("-c")
J
Jingwen Owen Ou 已提交
116
		editCmd.WithArg("set ft=gitcommit tw=0 wrap lbr")
J
Jingwen Owen Ou 已提交
117
	}
J
Jingwen Owen Ou 已提交
118
	editCmd.WithArg(messageFile)
J
Jingwen Owen Ou 已提交
119

J
Jingwen Owen Ou 已提交
120
	return editCmd.Exec()
J
Jingwen Owen Ou 已提交
121 122
}

J
Jingwen Owen Ou 已提交
123
func readTitleAndBody(messageFile string) (title, body string, err error) {
124 125
	f, err := os.Open(messageFile)
	defer f.Close()
J
Jingwen Owen Ou 已提交
126
	if err != nil {
127 128 129 130
		return "", "", err
	}

	reader := bufio.NewReader(f)
J
Jingwen Owen Ou 已提交
131

J
Jingwen Owen Ou 已提交
132
	return readTitleAndBodyFrom(reader)
133 134
}

J
Jingwen Owen Ou 已提交
135
func readTitleAndBodyFrom(reader *bufio.Reader) (title, body string, err error) {
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
	r := regexp.MustCompile("\\S")
	var titleParts, bodyParts []string

	line, err := readln(reader)
	for err == nil {
		if strings.HasPrefix(line, "#") {
			break
		}
		if len(bodyParts) == 0 && r.MatchString(line) {
			titleParts = append(titleParts, line)
		} else {
			bodyParts = append(bodyParts, line)
		}
		line, err = readln(reader)
	}

	title = strings.Join(titleParts, " ")
	title = strings.TrimSpace(title)

	body = strings.Join(bodyParts, "\n")
	body = strings.TrimSpace(body)

	return title, body, nil
}

func readln(r *bufio.Reader) (string, error) {
	var (
		isPrefix bool  = true
		err      error = nil
		line, ln []byte
	)
	for isPrefix && err == nil {
		line, isPrefix, err = r.ReadLine()
		ln = append(ln, line...)
J
Jingwen Owen Ou 已提交
170
	}
J
Jingwen Owen Ou 已提交
171

172
	return string(ln), err
J
Jingwen Owen Ou 已提交
173
}