2013-05-29 22:58:46 +04:00
|
|
|
package commands
|
2013-04-11 19:33:43 +04:00
|
|
|
|
|
|
|
import (
|
2013-04-28 21:45:00 +04:00
|
|
|
"bufio"
|
2013-04-29 00:41:45 +04:00
|
|
|
"fmt"
|
2013-05-29 22:58:46 +04:00
|
|
|
"github.com/jingweno/gh/cmd"
|
|
|
|
"github.com/jingweno/gh/git"
|
|
|
|
"github.com/jingweno/gh/github"
|
|
|
|
"github.com/jingweno/gh/utils"
|
2013-12-07 23:40:15 +04:00
|
|
|
"io"
|
2013-04-24 14:00:45 +04:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
2013-12-06 22:50:19 +04:00
|
|
|
"reflect"
|
2013-04-24 14:00:45 +04:00
|
|
|
"regexp"
|
2013-04-28 21:45:00 +04:00
|
|
|
"strings"
|
2013-04-11 19:33:43 +04:00
|
|
|
)
|
|
|
|
|
2013-06-30 00:54:40 +04:00
|
|
|
var cmdPullRequest = &Command{
|
|
|
|
Run: pullRequest,
|
2013-12-08 21:35:11 +04:00
|
|
|
Usage: "pull-request [-f] [-m <MESSAGE>|-F <FILE>|-i <ISSUE>|<ISSUE-URL>] [-b <BASE>] [-h <HEAD>] ",
|
2013-04-11 19:33:43 +04:00
|
|
|
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
|
2013-12-08 21:35:11 +04:00
|
|
|
on the remote. To skip this check, use "-f".
|
2013-04-11 19:33:43 +04:00
|
|
|
|
2013-12-08 21:35:11 +04:00
|
|
|
Without <MESSAGE> or <FILE>, 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.
|
|
|
|
Pull request message can also be passed via stdin with "-F -".
|
2013-04-11 19:33:43 +04:00
|
|
|
|
2013-12-08 21:35:11 +04:00
|
|
|
If instead of normal <TITLE> an issue number is given with "-i", the pull
|
2013-04-11 19:33:43 +04:00
|
|
|
request will be attached to an existing GitHub issue. Alternatively, instead
|
|
|
|
of title you can paste a full URL to an issue on GitHub.
|
|
|
|
`,
|
|
|
|
}
|
|
|
|
|
2013-12-07 19:43:55 +04:00
|
|
|
var (
|
|
|
|
flagPullRequestBase,
|
|
|
|
flagPullRequestHead,
|
|
|
|
flagPullRequestIssue,
|
|
|
|
flagPullRequestMessage,
|
|
|
|
flagPullRequestFile string
|
|
|
|
flagPullRequestForce bool
|
|
|
|
)
|
2013-04-11 19:33:43 +04:00
|
|
|
|
|
|
|
func init() {
|
2013-12-07 04:51:11 +04:00
|
|
|
cmdPullRequest.Flag.StringVar(&flagPullRequestBase, "b", "", "BASE")
|
|
|
|
cmdPullRequest.Flag.StringVar(&flagPullRequestHead, "h", "", "HEAD")
|
2013-06-30 00:54:40 +04:00
|
|
|
cmdPullRequest.Flag.StringVar(&flagPullRequestIssue, "i", "", "ISSUE")
|
2013-12-06 22:50:19 +04:00
|
|
|
cmdPullRequest.Flag.StringVar(&flagPullRequestMessage, "m", "", "MESSAGE")
|
2013-12-07 19:43:55 +04:00
|
|
|
cmdPullRequest.Flag.BoolVar(&flagPullRequestForce, "f", false, "FORCE")
|
2013-12-07 04:51:11 +04:00
|
|
|
cmdPullRequest.Flag.StringVar(&flagPullRequestFile, "F", "", "FILE")
|
2013-12-07 19:43:55 +04:00
|
|
|
cmdPullRequest.Flag.StringVar(&flagPullRequestFile, "file", "", "FILE")
|
2013-04-11 19:33:43 +04:00
|
|
|
}
|
|
|
|
|
2013-07-06 00:45:22 +04:00
|
|
|
/*
|
|
|
|
# while on a topic branch called "feature":
|
|
|
|
$ gh pull-request
|
|
|
|
[ opens text editor to edit title & body for the request ]
|
|
|
|
[ opened pull request on GitHub for "YOUR_USER:feature" ]
|
|
|
|
|
|
|
|
# explicit pull base & head:
|
|
|
|
$ gh pull-request -b jingweno:master -h jingweno:feature
|
|
|
|
|
2013-12-06 22:50:19 +04:00
|
|
|
$ gh pull-request -m "title\n\nbody"
|
|
|
|
[ create pull request with title & body ]
|
|
|
|
|
2013-07-06 00:45:22 +04:00
|
|
|
$ gh pull-request -i 123
|
|
|
|
[ attached pull request to issue #123 ]
|
2013-12-06 22:50:19 +04:00
|
|
|
|
|
|
|
$ gh pull-request https://github.com/jingweno/gh/pull/123
|
|
|
|
[ attached pull request to issue #123 ]
|
2013-12-08 21:35:11 +04:00
|
|
|
|
|
|
|
$ gh pull-request -F FILE
|
|
|
|
[ create pull request with title & body from FILE ]
|
2013-07-06 00:45:22 +04:00
|
|
|
*/
|
2013-06-30 00:54:40 +04:00
|
|
|
func pullRequest(cmd *Command, args *Args) {
|
2013-12-06 22:50:19 +04:00
|
|
|
localRepo := github.LocalRepo()
|
|
|
|
|
|
|
|
currentBranch, err := localRepo.CurrentBranch()
|
2013-12-06 22:54:11 +04:00
|
|
|
utils.Check(err)
|
2013-12-06 22:50:19 +04:00
|
|
|
|
|
|
|
baseProject, err := localRepo.MainProject()
|
2013-12-06 22:54:11 +04:00
|
|
|
utils.Check(err)
|
2013-12-06 22:50:19 +04:00
|
|
|
|
|
|
|
headProject, err := localRepo.CurrentProject()
|
|
|
|
utils.Check(err)
|
|
|
|
|
2013-12-07 04:51:11 +04:00
|
|
|
var (
|
2013-12-07 19:43:55 +04:00
|
|
|
base, head string
|
|
|
|
force, explicitOwner bool
|
2013-12-07 04:51:11 +04:00
|
|
|
)
|
2013-12-08 12:33:48 +04:00
|
|
|
|
2013-12-07 19:43:55 +04:00
|
|
|
force = flagPullRequestForce
|
2013-12-08 12:33:48 +04:00
|
|
|
|
2013-12-06 22:50:19 +04:00
|
|
|
if flagPullRequestBase != "" {
|
2013-12-08 12:33:48 +04:00
|
|
|
baseProject, base = parsePullRequestProject(baseProject, flagPullRequestBase)
|
2013-12-06 22:50:19 +04:00
|
|
|
}
|
2013-12-07 04:51:11 +04:00
|
|
|
|
2013-12-06 22:50:19 +04:00
|
|
|
if flagPullRequestHead != "" {
|
2013-12-08 12:33:48 +04:00
|
|
|
headProject, head = parsePullRequestProject(headProject, flagPullRequestHead)
|
|
|
|
explicitOwner = strings.Contains(flagPullRequestHead, ":")
|
2013-12-06 22:50:19 +04:00
|
|
|
}
|
2013-12-07 04:51:11 +04:00
|
|
|
|
2013-07-02 22:56:45 +04:00
|
|
|
if args.ParamsSize() == 1 {
|
2013-12-06 22:50:19 +04:00
|
|
|
arg := args.RemoveParam(0)
|
2013-12-08 12:33:48 +04:00
|
|
|
flagPullRequestIssue = parsePullRequestIssueNumber(arg)
|
2013-06-02 05:16:18 +04:00
|
|
|
}
|
|
|
|
|
2013-12-06 22:50:19 +04:00
|
|
|
if base == "" {
|
|
|
|
masterBranch, err := localRepo.MasterBranch()
|
|
|
|
utils.Check(err)
|
|
|
|
base = masterBranch.ShortName()
|
|
|
|
}
|
|
|
|
|
2013-12-08 12:33:48 +04:00
|
|
|
trackedBranch, _ := currentBranch.Upstream()
|
2013-12-06 22:50:19 +04:00
|
|
|
if head == "" {
|
2013-12-08 12:33:48 +04:00
|
|
|
if trackedBranch != nil && trackedBranch.IsRemote() {
|
|
|
|
if reflect.DeepEqual(baseProject, headProject) && base == trackedBranch.ShortName() {
|
|
|
|
e := fmt.Errorf(`Aborted: head branch is the same as base ("%s")`, base)
|
|
|
|
e = fmt.Errorf("%s\n(use `-h <branch>` to specify an explicit pull request head)", e)
|
|
|
|
utils.Check(e)
|
2013-12-06 22:50:19 +04:00
|
|
|
}
|
2013-12-08 12:33:48 +04:00
|
|
|
} else {
|
|
|
|
// the current branch tracking another branch
|
|
|
|
// pretend there's no upstream at all
|
|
|
|
trackedBranch = nil
|
2013-12-06 22:50:19 +04:00
|
|
|
}
|
|
|
|
|
2013-12-08 12:33:48 +04:00
|
|
|
if trackedBranch == nil {
|
2013-12-06 22:50:19 +04:00
|
|
|
head = currentBranch.ShortName()
|
2013-12-08 12:33:48 +04:00
|
|
|
} else {
|
|
|
|
head = trackedBranch.ShortName()
|
2013-12-06 22:50:19 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-17 19:45:48 +04:00
|
|
|
client := github.NewClient(baseProject.Host)
|
2013-12-07 23:40:15 +04:00
|
|
|
|
2013-12-06 22:50:19 +04:00
|
|
|
// when no tracking, assume remote branch is published under active user's fork
|
2013-12-08 12:33:48 +04:00
|
|
|
if trackedBranch == nil && !explicitOwner && client.Credentials.User != headProject.Owner {
|
2013-12-10 09:02:52 +04:00
|
|
|
// disable this on gh
|
|
|
|
//headProject = github.NewProject("", headProject.Name, headProject.Host)
|
2013-12-06 22:50:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
var title, body string
|
2013-12-08 12:33:48 +04:00
|
|
|
|
2013-12-06 22:50:19 +04:00
|
|
|
if flagPullRequestMessage != "" {
|
|
|
|
title, body = readMsg(flagPullRequestMessage)
|
|
|
|
}
|
|
|
|
|
2013-12-07 04:51:11 +04:00
|
|
|
if flagPullRequestFile != "" {
|
|
|
|
var (
|
|
|
|
content []byte
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
if flagPullRequestFile == "-" {
|
|
|
|
content, err = ioutil.ReadAll(os.Stdin)
|
|
|
|
} else {
|
|
|
|
content, err = ioutil.ReadFile(flagPullRequestFile)
|
|
|
|
}
|
|
|
|
utils.Check(err)
|
|
|
|
title, body = readMsg(string(content))
|
|
|
|
}
|
|
|
|
|
2013-12-06 22:50:19 +04:00
|
|
|
fullBase := fmt.Sprintf("%s:%s", baseProject.Owner, base)
|
|
|
|
fullHead := fmt.Sprintf("%s:%s", headProject.Owner, head)
|
|
|
|
|
2013-12-19 22:19:38 +04:00
|
|
|
if !force && trackedBranch != nil {
|
|
|
|
remoteCommits, _ := git.RefList(trackedBranch.LongName(), "")
|
|
|
|
if len(remoteCommits) > 0 {
|
|
|
|
err = fmt.Errorf("Aborted: %d commits are not yet pushed to %s", len(remoteCommits), trackedBranch.LongName())
|
|
|
|
err = fmt.Errorf("%s\n(use `-f` to force submit a pull request anyway)", err)
|
|
|
|
utils.Check(err)
|
|
|
|
}
|
2013-12-07 19:43:55 +04:00
|
|
|
}
|
|
|
|
|
2013-06-02 06:09:17 +04:00
|
|
|
if title == "" && flagPullRequestIssue == "" {
|
2013-12-19 22:19:38 +04:00
|
|
|
commits, _ := git.RefList(base, head)
|
2013-12-07 19:43:55 +04:00
|
|
|
t, b, err := writePullRequestTitleAndBody(base, head, fullBase, fullHead, commits)
|
2013-11-07 02:18:30 +04:00
|
|
|
utils.Check(err)
|
|
|
|
title = t
|
|
|
|
body = b
|
2013-07-05 22:10:24 +04:00
|
|
|
}
|
2013-04-28 21:45:00 +04:00
|
|
|
|
2013-07-05 22:10:24 +04:00
|
|
|
if title == "" && flagPullRequestIssue == "" {
|
|
|
|
utils.Check(fmt.Errorf("Aborting due to empty pull request title"))
|
|
|
|
}
|
2013-05-28 21:13:55 +04:00
|
|
|
|
2013-07-06 00:45:22 +04:00
|
|
|
var pullRequestURL string
|
2013-07-05 22:10:24 +04:00
|
|
|
if args.Noop {
|
2013-12-06 22:50:19 +04:00
|
|
|
args.Before(fmt.Sprintf("Would request a pull request to %s from %s", fullBase, fullHead), "")
|
2013-07-06 00:45:22 +04:00
|
|
|
pullRequestURL = "PULL_REQUEST_URL"
|
2013-07-05 22:10:24 +04:00
|
|
|
} else {
|
|
|
|
if title != "" {
|
2013-12-17 19:45:48 +04:00
|
|
|
pr, err := client.CreatePullRequest(baseProject, base, fullHead, title, body)
|
2013-11-07 02:18:30 +04:00
|
|
|
utils.Check(err)
|
|
|
|
pullRequestURL = pr.HTMLURL
|
2013-07-05 22:10:24 +04:00
|
|
|
}
|
2013-04-28 21:45:00 +04:00
|
|
|
|
2013-07-05 22:10:24 +04:00
|
|
|
if flagPullRequestIssue != "" {
|
2013-12-17 19:45:48 +04:00
|
|
|
pr, err := client.CreatePullRequestForIssue(baseProject, base, fullHead, flagPullRequestIssue)
|
2013-11-07 02:18:30 +04:00
|
|
|
utils.Check(err)
|
|
|
|
pullRequestURL = pr.HTMLURL
|
2013-07-05 22:10:24 +04:00
|
|
|
}
|
|
|
|
}
|
2013-07-06 00:45:22 +04:00
|
|
|
|
|
|
|
args.Replace("echo", "", pullRequestURL)
|
2013-07-05 22:10:24 +04:00
|
|
|
}
|
2013-06-30 20:11:25 +04:00
|
|
|
|
2013-12-07 19:43:55 +04:00
|
|
|
func writePullRequestTitleAndBody(base, head, fullBase, fullHead string, commits []string) (title, body string, err error) {
|
2013-07-05 22:10:24 +04:00
|
|
|
messageFile, err := git.PullReqMsgFile()
|
|
|
|
if err != nil {
|
|
|
|
return
|
2013-06-02 05:16:18 +04:00
|
|
|
}
|
2013-12-06 22:50:19 +04:00
|
|
|
defer os.Remove(messageFile)
|
2013-05-24 09:41:06 +04:00
|
|
|
|
2013-12-07 19:43:55 +04:00
|
|
|
err = writePullRequestChanges(base, head, fullBase, fullHead, commits, messageFile)
|
2013-07-05 22:10:24 +04:00
|
|
|
if err != nil {
|
|
|
|
return
|
2013-04-28 21:45:00 +04:00
|
|
|
}
|
|
|
|
|
2013-11-26 19:14:47 +04:00
|
|
|
editor, err := git.Editor()
|
2013-07-05 22:10:24 +04:00
|
|
|
if err != nil {
|
|
|
|
return
|
2013-06-09 03:30:01 +04:00
|
|
|
}
|
2013-07-05 22:10:24 +04:00
|
|
|
|
2013-11-26 19:14:47 +04:00
|
|
|
err = editTitleAndBody(editor, messageFile)
|
2013-07-05 22:10:24 +04:00
|
|
|
if err != nil {
|
2013-12-06 22:50:19 +04:00
|
|
|
err = fmt.Errorf("error using text editor for pull request message")
|
2013-07-05 22:10:24 +04:00
|
|
|
return
|
2013-06-09 03:30:01 +04:00
|
|
|
}
|
|
|
|
|
2013-07-05 22:10:24 +04:00
|
|
|
title, body, err = readTitleAndBody(messageFile)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2013-04-29 06:21:16 +04:00
|
|
|
|
2013-07-05 22:10:24 +04:00
|
|
|
return
|
2013-04-28 21:45:00 +04:00
|
|
|
}
|
|
|
|
|
2013-12-07 19:43:55 +04:00
|
|
|
func writePullRequestChanges(base, head, fullBase, fullHead string, commits []string, messageFile string) error {
|
2013-12-02 20:51:45 +04:00
|
|
|
var defaultMsg, commitSummary string
|
|
|
|
if len(commits) == 1 {
|
2013-12-11 12:11:21 +04:00
|
|
|
msg, err := git.Show(commits[0])
|
2013-12-02 20:51:45 +04:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2013-12-11 12:11:21 +04:00
|
|
|
defaultMsg = fmt.Sprintf("%s\n", msg)
|
2013-12-02 20:51:45 +04:00
|
|
|
} else if len(commits) > 1 {
|
2013-12-06 22:50:19 +04:00
|
|
|
commitLogs, err := git.Log(base, head)
|
2013-12-02 20:51:45 +04:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(commitLogs) > 0 {
|
|
|
|
startRegexp := regexp.MustCompilePOSIX("^")
|
|
|
|
endRegexp := regexp.MustCompilePOSIX(" +$")
|
|
|
|
|
|
|
|
commitLogs = strings.TrimSpace(commitLogs)
|
|
|
|
commitLogs = startRegexp.ReplaceAllString(commitLogs, "# ")
|
|
|
|
commitLogs = endRegexp.ReplaceAllString(commitLogs, "")
|
|
|
|
commitSummary = `
|
2013-04-29 00:41:45 +04:00
|
|
|
#
|
|
|
|
# Changes:
|
|
|
|
#
|
2013-05-30 05:19:14 +04:00
|
|
|
%s`
|
2013-12-02 20:51:45 +04:00
|
|
|
commitSummary = fmt.Sprintf(commitSummary, commitLogs)
|
|
|
|
}
|
2013-05-24 22:54:01 +04:00
|
|
|
}
|
2013-04-29 00:41:45 +04:00
|
|
|
|
2013-12-02 20:51:45 +04:00
|
|
|
message := `%s
|
|
|
|
# Requesting a pull to %s from %s
|
|
|
|
#
|
|
|
|
# Write a message for this pull request. The first block
|
|
|
|
# of the text is the title and the rest is description.%s
|
|
|
|
`
|
2013-12-06 22:50:19 +04:00
|
|
|
message = fmt.Sprintf(message, defaultMsg, fullBase, fullHead, commitSummary)
|
2013-04-29 05:32:01 +04:00
|
|
|
|
|
|
|
return ioutil.WriteFile(messageFile, []byte(message), 0644)
|
|
|
|
}
|
|
|
|
|
2013-11-26 19:14:47 +04:00
|
|
|
func editTitleAndBody(editor, messageFile string) error {
|
|
|
|
editCmd := cmd.New(editor)
|
2013-05-28 21:13:55 +04:00
|
|
|
r := regexp.MustCompile("[mg]?vi[m]$")
|
2013-11-26 19:14:47 +04:00
|
|
|
if r.MatchString(editor) {
|
2013-04-29 05:47:08 +04:00
|
|
|
editCmd.WithArg("-c")
|
2013-05-28 22:07:08 +04:00
|
|
|
editCmd.WithArg("set ft=gitcommit tw=0 wrap lbr")
|
2013-04-24 14:00:45 +04:00
|
|
|
}
|
2013-04-29 05:47:08 +04:00
|
|
|
editCmd.WithArg(messageFile)
|
2013-04-24 14:00:45 +04:00
|
|
|
|
2013-05-28 23:42:11 +04:00
|
|
|
return editCmd.Exec()
|
2013-04-24 14:00:45 +04:00
|
|
|
}
|
|
|
|
|
2013-05-28 23:42:11 +04:00
|
|
|
func readTitleAndBody(messageFile string) (title, body string, err error) {
|
2013-04-28 21:45:00 +04:00
|
|
|
f, err := os.Open(messageFile)
|
|
|
|
defer f.Close()
|
2013-04-22 07:36:21 +04:00
|
|
|
if err != nil {
|
2013-04-28 21:45:00 +04:00
|
|
|
return "", "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
reader := bufio.NewReader(f)
|
2013-04-29 05:47:08 +04:00
|
|
|
|
2013-05-28 23:42:11 +04:00
|
|
|
return readTitleAndBodyFrom(reader)
|
2013-04-28 21:45:00 +04:00
|
|
|
}
|
|
|
|
|
2013-05-28 23:42:11 +04:00
|
|
|
func readTitleAndBodyFrom(reader *bufio.Reader) (title, body string, err error) {
|
2013-04-28 21:45:00 +04:00
|
|
|
r := regexp.MustCompile("\\S")
|
|
|
|
var titleParts, bodyParts []string
|
|
|
|
|
2013-07-13 20:59:45 +04:00
|
|
|
line, err := readLine(reader)
|
2013-04-28 21:45:00 +04:00
|
|
|
for err == nil {
|
|
|
|
if strings.HasPrefix(line, "#") {
|
|
|
|
break
|
|
|
|
}
|
2013-07-13 20:59:45 +04:00
|
|
|
|
2013-04-28 21:45:00 +04:00
|
|
|
if len(bodyParts) == 0 && r.MatchString(line) {
|
|
|
|
titleParts = append(titleParts, line)
|
|
|
|
} else {
|
|
|
|
bodyParts = append(bodyParts, line)
|
|
|
|
}
|
2013-07-13 20:59:45 +04:00
|
|
|
|
|
|
|
line, err = readLine(reader)
|
2013-04-28 21:45:00 +04:00
|
|
|
}
|
|
|
|
|
2013-12-07 23:40:15 +04:00
|
|
|
if err == io.EOF {
|
|
|
|
err = nil
|
|
|
|
}
|
|
|
|
|
2013-04-28 21:45:00 +04:00
|
|
|
title = strings.Join(titleParts, " ")
|
|
|
|
title = strings.TrimSpace(title)
|
|
|
|
|
|
|
|
body = strings.Join(bodyParts, "\n")
|
|
|
|
body = strings.TrimSpace(body)
|
|
|
|
|
2013-12-07 23:40:15 +04:00
|
|
|
return
|
2013-04-28 21:45:00 +04:00
|
|
|
}
|
|
|
|
|
2013-07-13 20:59:45 +04:00
|
|
|
func readLine(r *bufio.Reader) (string, error) {
|
2013-04-28 21:45:00 +04:00
|
|
|
var (
|
2013-06-11 08:49:45 +04:00
|
|
|
isPrefix = true
|
|
|
|
err error
|
2013-04-28 21:45:00 +04:00
|
|
|
line, ln []byte
|
|
|
|
)
|
2013-07-13 20:59:45 +04:00
|
|
|
|
2013-04-28 21:45:00 +04:00
|
|
|
for isPrefix && err == nil {
|
|
|
|
line, isPrefix, err = r.ReadLine()
|
|
|
|
ln = append(ln, line...)
|
2013-04-22 07:36:21 +04:00
|
|
|
}
|
2013-04-29 05:47:08 +04:00
|
|
|
|
2013-04-28 21:45:00 +04:00
|
|
|
return string(ln), err
|
2013-04-11 19:33:43 +04:00
|
|
|
}
|
2013-12-06 22:50:19 +04:00
|
|
|
|
|
|
|
func readMsg(msg string) (title, body string) {
|
|
|
|
split := strings.SplitN(msg, "\n\n", 2)
|
|
|
|
title = strings.TrimSpace(split[0])
|
|
|
|
if len(split) > 1 {
|
|
|
|
body = strings.TrimSpace(split[1])
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
2013-12-08 12:33:48 +04:00
|
|
|
|
|
|
|
func parsePullRequestProject(context *github.Project, s string) (p *github.Project, ref string) {
|
|
|
|
p = context
|
|
|
|
ref = s
|
|
|
|
|
|
|
|
if strings.Contains(s, ":") {
|
|
|
|
split := strings.SplitN(s, ":", 2)
|
|
|
|
ref = split[1]
|
|
|
|
var name string
|
|
|
|
if !strings.Contains(split[0], "/") {
|
|
|
|
name = context.Name
|
|
|
|
}
|
|
|
|
p = github.NewProject(split[0], name, context.Host)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func parsePullRequestIssueNumber(url string) string {
|
|
|
|
u, e := github.ParseURL(url)
|
|
|
|
if e != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
r := regexp.MustCompile(`^issues\/(\d+)`)
|
|
|
|
p := u.ProjectPath()
|
|
|
|
if r.MatchString(p) {
|
|
|
|
return r.FindStringSubmatch(p)[1]
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|