2017-02-10 15:56:13 +03:00
|
|
|
package commands
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2017-02-26 22:17:01 +03:00
|
|
|
"os"
|
2017-02-10 15:56:13 +03:00
|
|
|
"strconv"
|
2018-06-07 12:37:01 +03:00
|
|
|
"strings"
|
2017-02-10 15:56:13 +03:00
|
|
|
|
|
|
|
"github.com/github/hub/github"
|
2018-01-30 03:23:16 +03:00
|
|
|
"github.com/github/hub/ui"
|
2017-02-10 15:56:13 +03:00
|
|
|
"github.com/github/hub/utils"
|
|
|
|
)
|
|
|
|
|
2017-02-26 12:42:07 +03:00
|
|
|
var (
|
2017-02-26 22:25:46 +03:00
|
|
|
cmdPr = &Command{
|
2018-01-30 03:23:16 +03:00
|
|
|
Run: printHelp,
|
|
|
|
Usage: `
|
2018-05-29 20:20:26 +03:00
|
|
|
pr list [-s <STATE>] [-h <HEAD>] [-b <BASE>] [-o <SORT_KEY> [-^]] [-f <FORMAT>] [-L <LIMIT>]
|
2018-01-30 03:23:16 +03:00
|
|
|
pr checkout <PR-NUMBER> [<BRANCH>]
|
|
|
|
`,
|
|
|
|
Long: `Manage GitHub pull requests for the current project.
|
2017-02-10 15:56:13 +03:00
|
|
|
|
2018-01-30 03:23:16 +03:00
|
|
|
## Commands:
|
|
|
|
|
|
|
|
* _list_:
|
|
|
|
List pull requests in the current project.
|
|
|
|
|
|
|
|
* _checkout_:
|
|
|
|
Check out the head of a pull request in a new branch.
|
|
|
|
|
|
|
|
## Options:
|
|
|
|
|
2018-12-18 19:49:09 +03:00
|
|
|
-s, --state=<STATE>
|
2018-12-17 18:53:39 +03:00
|
|
|
Filter pull requests by <STATE>. Supported values are: "open" (default),
|
|
|
|
"closed", "merged", or "all".
|
2018-05-29 20:20:26 +03:00
|
|
|
|
2018-12-18 19:53:50 +03:00
|
|
|
-h, --head=<BRANCH>
|
|
|
|
Show pull requests started from the specified head <BRANCH>. The
|
|
|
|
"OWNER:BRANCH" format must be used for pull requests from forks.
|
2018-05-29 20:20:26 +03:00
|
|
|
|
2018-12-18 19:49:09 +03:00
|
|
|
-b, --base=<BRANCH>
|
2018-12-18 19:53:50 +03:00
|
|
|
Show pull requests based off the specified <BRANCH>.
|
2018-01-30 03:23:16 +03:00
|
|
|
|
2018-12-18 19:49:09 +03:00
|
|
|
-f, --format=<FORMAT>
|
2018-01-30 03:23:16 +03:00
|
|
|
Pretty print the list of pull requests using format <FORMAT> (default:
|
2018-12-18 20:07:48 +03:00
|
|
|
"%sC%>(8)%i%Creset %t% l%n"). See the "PRETTY FORMATS" section of
|
|
|
|
git-log(1) for some additional details on how placeholders are used in
|
2018-01-30 03:23:16 +03:00
|
|
|
format. The available placeholders are:
|
|
|
|
|
|
|
|
%I: pull request number
|
|
|
|
|
|
|
|
%i: pull request number prefixed with "#"
|
|
|
|
|
|
|
|
%U: the URL of this pull request
|
|
|
|
|
2018-12-17 18:53:39 +03:00
|
|
|
%S: state ("open" or "closed")
|
2018-01-30 03:23:16 +03:00
|
|
|
|
|
|
|
%sC: set color to red or green, depending on pull request state.
|
|
|
|
|
|
|
|
%t: title
|
|
|
|
|
|
|
|
%l: colored labels
|
|
|
|
|
|
|
|
%L: raw, comma-separated labels
|
|
|
|
|
|
|
|
%b: body
|
|
|
|
|
2018-01-31 00:18:25 +03:00
|
|
|
%B: base branch
|
|
|
|
|
2018-12-17 19:25:05 +03:00
|
|
|
%sB: base commit SHA
|
|
|
|
|
2018-01-31 00:18:25 +03:00
|
|
|
%H: head branch
|
|
|
|
|
2018-12-17 19:25:05 +03:00
|
|
|
%sH: head commit SHA
|
|
|
|
|
|
|
|
%sm: merge commit SHA
|
|
|
|
|
2018-01-30 03:23:16 +03:00
|
|
|
%au: login name of author
|
|
|
|
|
|
|
|
%as: comma-separated list of assignees
|
|
|
|
|
2018-10-30 01:18:18 +03:00
|
|
|
%rs: comma-separated list of requested reviewers
|
|
|
|
|
2018-01-30 03:23:16 +03:00
|
|
|
%Mn: milestone number
|
|
|
|
|
|
|
|
%Mt: milestone title
|
|
|
|
|
|
|
|
%NC: number of comments
|
|
|
|
|
|
|
|
%Nc: number of comments wrapped in parentheses, or blank string if zero.
|
|
|
|
|
|
|
|
%cD: created date-only (no time of day)
|
|
|
|
|
|
|
|
%cr: created date, relative
|
|
|
|
|
|
|
|
%ct: created date, UNIX timestamp
|
|
|
|
|
|
|
|
%cI: created date, ISO 8601 format
|
|
|
|
|
|
|
|
%uD: updated date-only (no time of day)
|
|
|
|
|
|
|
|
%ur: updated date, relative
|
|
|
|
|
|
|
|
%ut: updated date, UNIX timestamp
|
|
|
|
|
|
|
|
%uI: updated date, ISO 8601 format
|
|
|
|
|
2018-12-17 18:41:35 +03:00
|
|
|
%mD: merged date-only (no time of day)
|
|
|
|
|
|
|
|
%mr: merged date, relative
|
|
|
|
|
|
|
|
%mt: merged date, UNIX timestamp
|
|
|
|
|
|
|
|
%mI: merged date, ISO 8601 format
|
|
|
|
|
2018-12-18 19:49:09 +03:00
|
|
|
-o, --sort=<SORT_KEY>
|
2018-01-30 03:23:16 +03:00
|
|
|
Sort displayed issues by "created" (default), "updated", "popularity", or "long-running".
|
|
|
|
|
|
|
|
-^ --sort-ascending
|
|
|
|
Sort by ascending dates instead of descending.
|
|
|
|
|
2018-12-18 19:49:09 +03:00
|
|
|
-L, --limit=<LIMIT>
|
2018-01-30 03:23:16 +03:00
|
|
|
Display only the first <LIMIT> issues.
|
2017-02-10 15:56:13 +03:00
|
|
|
|
|
|
|
## See also:
|
|
|
|
|
2018-01-30 03:23:16 +03:00
|
|
|
hub-issue(1), hub-pull-request(1), hub(1)
|
|
|
|
`,
|
2017-02-26 12:42:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
cmdCheckoutPr = &Command{
|
|
|
|
Key: "checkout",
|
2017-02-26 15:42:35 +03:00
|
|
|
Run: checkoutPr,
|
2017-02-26 12:42:07 +03:00
|
|
|
}
|
2018-01-30 03:23:16 +03:00
|
|
|
|
|
|
|
cmdListPulls = &Command{
|
|
|
|
Key: "list",
|
|
|
|
Run: listPulls,
|
|
|
|
}
|
|
|
|
|
|
|
|
flagPullRequestState,
|
|
|
|
flagPullRequestFormat,
|
|
|
|
flagPullRequestSort string
|
|
|
|
|
|
|
|
flagPullRequestSortAscending bool
|
|
|
|
|
|
|
|
flagPullRequestLimit int
|
2017-02-26 12:42:07 +03:00
|
|
|
)
|
2017-02-10 15:56:13 +03:00
|
|
|
|
|
|
|
func init() {
|
2018-01-30 03:23:16 +03:00
|
|
|
cmdListPulls.Flag.StringVarP(&flagPullRequestState, "state", "s", "", "STATE")
|
|
|
|
cmdListPulls.Flag.StringVarP(&flagPullRequestBase, "base", "b", "", "BASE")
|
|
|
|
cmdListPulls.Flag.StringVarP(&flagPullRequestHead, "head", "h", "", "HEAD")
|
|
|
|
cmdListPulls.Flag.StringVarP(&flagPullRequestFormat, "format", "f", "%sC%>(8)%i%Creset %t% l%n", "FORMAT")
|
|
|
|
cmdListPulls.Flag.StringVarP(&flagPullRequestSort, "sort", "o", "created", "SORT_KEY")
|
|
|
|
cmdListPulls.Flag.BoolVarP(&flagPullRequestSortAscending, "sort-ascending", "^", false, "SORT_KEY")
|
|
|
|
cmdListPulls.Flag.IntVarP(&flagPullRequestLimit, "limit", "L", -1, "LIMIT")
|
|
|
|
|
|
|
|
cmdPr.Use(cmdListPulls)
|
2017-02-26 15:42:35 +03:00
|
|
|
cmdPr.Use(cmdCheckoutPr)
|
2017-02-26 12:13:22 +03:00
|
|
|
CmdRunner.Use(cmdPr)
|
2017-02-10 15:56:13 +03:00
|
|
|
}
|
|
|
|
|
2017-02-26 22:17:01 +03:00
|
|
|
func printHelp(command *Command, args *Args) {
|
|
|
|
fmt.Print(command.HelpText())
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2018-01-30 03:23:16 +03:00
|
|
|
func listPulls(cmd *Command, args *Args) {
|
|
|
|
localRepo, err := github.LocalRepo()
|
|
|
|
utils.Check(err)
|
|
|
|
|
|
|
|
project, err := localRepo.MainProject()
|
|
|
|
utils.Check(err)
|
|
|
|
|
|
|
|
gh := github.NewClient(project.Host)
|
|
|
|
|
|
|
|
args.NoForward()
|
|
|
|
if args.Noop {
|
|
|
|
ui.Printf("Would request list of pull requests for %s\n", project)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-07 12:37:01 +03:00
|
|
|
if flagPullRequestHead != "" && !strings.Contains(flagPullRequestHead, ":") {
|
|
|
|
flagPullRequestHead = fmt.Sprintf("%s:%s", project.Owner, flagPullRequestHead)
|
|
|
|
}
|
|
|
|
|
2018-01-30 03:23:16 +03:00
|
|
|
flagFilters := map[string]string{
|
|
|
|
"state": flagPullRequestState,
|
|
|
|
"head": flagPullRequestHead,
|
|
|
|
"base": flagPullRequestBase,
|
|
|
|
"sort": flagPullRequestSort,
|
|
|
|
}
|
|
|
|
filters := map[string]interface{}{}
|
|
|
|
for flag, filter := range flagFilters {
|
|
|
|
if cmd.FlagPassed(flag) {
|
|
|
|
filters[flag] = filter
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if flagPullRequestSortAscending {
|
|
|
|
filters["direction"] = "asc"
|
2018-10-26 15:06:15 +03:00
|
|
|
} else {
|
|
|
|
filters["direction"] = "desc"
|
2018-01-30 03:23:16 +03:00
|
|
|
}
|
|
|
|
|
2018-12-17 18:53:39 +03:00
|
|
|
onlyMerged := false
|
|
|
|
if filters["state"] == "merged" {
|
|
|
|
filters["state"] = "closed"
|
|
|
|
onlyMerged = true
|
|
|
|
}
|
|
|
|
|
|
|
|
pulls, err := gh.FetchPullRequests(project, filters, flagPullRequestLimit, func(pr *github.PullRequest) bool {
|
|
|
|
return !(onlyMerged && pr.MergedAt.IsZero())
|
|
|
|
})
|
2018-01-30 03:23:16 +03:00
|
|
|
utils.Check(err)
|
|
|
|
|
|
|
|
colorize := ui.IsTerminal(os.Stdout)
|
|
|
|
for _, pr := range pulls {
|
|
|
|
ui.Printf(formatPullRequest(pr, flagPullRequestFormat, colorize))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-26 15:42:35 +03:00
|
|
|
func checkoutPr(command *Command, args *Args) {
|
2017-04-08 23:14:22 +03:00
|
|
|
words := args.Words()
|
|
|
|
var newBranchName string
|
|
|
|
|
|
|
|
if len(words) == 0 {
|
|
|
|
utils.Check(fmt.Errorf("Error: No pull request number given"))
|
|
|
|
} else if len(words) > 1 {
|
|
|
|
newBranchName = words[1]
|
2017-02-10 15:56:13 +03:00
|
|
|
}
|
|
|
|
|
2017-04-08 23:14:22 +03:00
|
|
|
prNumberString := words[0]
|
2017-02-10 15:56:13 +03:00
|
|
|
_, err := strconv.Atoi(prNumberString)
|
|
|
|
utils.Check(err)
|
|
|
|
|
|
|
|
// Figure out the PR URL
|
|
|
|
localRepo, err := github.LocalRepo()
|
|
|
|
utils.Check(err)
|
|
|
|
baseProject, err := localRepo.MainProject()
|
|
|
|
utils.Check(err)
|
|
|
|
host, err := github.CurrentConfig().PromptForHost(baseProject.Host)
|
|
|
|
utils.Check(err)
|
|
|
|
client := github.NewClientWithHost(host)
|
|
|
|
pr, err := client.PullRequest(baseProject, prNumberString)
|
|
|
|
utils.Check(err)
|
|
|
|
|
2017-04-08 23:14:22 +03:00
|
|
|
newArgs, err := transformCheckoutArgs(args, pr, newBranchName)
|
2017-02-10 15:56:13 +03:00
|
|
|
utils.Check(err)
|
2017-04-07 15:29:02 +03:00
|
|
|
|
2017-04-08 23:14:22 +03:00
|
|
|
args.Replace(args.Executable, "checkout", newArgs...)
|
2017-02-10 15:56:13 +03:00
|
|
|
}
|
2018-01-30 03:23:16 +03:00
|
|
|
|
|
|
|
func formatPullRequest(pr github.PullRequest, format string, colorize bool) string {
|
|
|
|
placeholders := formatIssuePlaceholders(github.Issue(pr), colorize)
|
2018-12-17 18:41:35 +03:00
|
|
|
for key, value := range formatPullRequestPlaceholders(pr) {
|
|
|
|
placeholders[key] = value
|
|
|
|
}
|
2018-01-30 03:23:16 +03:00
|
|
|
return ui.Expand(format, placeholders, colorize)
|
|
|
|
}
|