checkout.go 3.0 KB
Newer Older
J
Jingwen Owen Ou 已提交
1 2
package commands

J
Jingwen Owen Ou 已提交
3
import (
J
Jingwen Owen Ou 已提交
4
	"fmt"
J
Jingwen Owen Ou 已提交
5 6
	"regexp"

J
Jingwen Owen Ou 已提交
7 8
	"github.com/github/hub/github"
	"github.com/github/hub/utils"
J
Jingwen Owen Ou 已提交
9 10
)

J
Jingwen Owen Ou 已提交
11 12 13
var cmdCheckout = &Command{
	Run:          checkout,
	GitExtension: true,
14 15 16 17 18 19 20
	Usage:        "checkout <PULLREQ-URL> [<BRANCH>]",
	Long: `Check out the head of a pull request as a local branch.

## Examples:
		$ hub checkout https://github.com/jingweno/gh/pull/73
		> git remote add -f --no-tags -t feature git://github:com/jingweno/gh.git
		> git checkout --track -B jingweno-feature jingweno/feature
M
Mislav Marohnić 已提交
21 22 23 24

## See also:

hub-merge(1), hub-am(1), hub(1), git-checkout(1)
25
`,
J
Jingwen Owen Ou 已提交
26 27
}

28 29 30 31
func init() {
	CmdRunner.Use(cmdCheckout)
}

J
Jingwen Owen Ou 已提交
32
func checkout(command *Command, args *Args) {
J
Jingwen Owen Ou 已提交
33
	if !args.IsParamsEmpty() {
J
Jingwen Owen Ou 已提交
34
		err := transformCheckoutArgs(args)
J
Jingwen Owen Ou 已提交
35
		utils.Check(err)
J
Jingwen Owen Ou 已提交
36 37 38
	}
}

J
Jingwen Owen Ou 已提交
39
func transformCheckoutArgs(args *Args) error {
40
	words := args.Words()
J
Jingwen Owen Ou 已提交
41

42 43 44
	if len(words) == 0 {
		return nil
	}
J
Jingwen Owen Ou 已提交
45

46 47 48 49
	checkoutURL := words[0]
	var newBranchName string
	if len(words) > 1 {
		newBranchName = words[1]
50
	}
J
Jingwen Owen Ou 已提交
51 52 53 54 55 56

	url, err := github.ParseURL(checkoutURL)
	if err != nil {
		// not a valid GitHub URL
		return nil
	}
57

58 59 60
	pullURLRegex := regexp.MustCompile("^pull/(\\d+)")
	projectPath := url.ProjectPath()
	if !pullURLRegex.MatchString(projectPath) {
J
Jingwen Owen Ou 已提交
61
		// not a valid PR URL
62 63
		return nil
	}
J
Jingwen Owen Ou 已提交
64

65 66 67 68 69
	err = sanitizeCheckoutFlags(args)
	if err != nil {
		return err
	}

70
	id := pullURLRegex.FindStringSubmatch(projectPath)[1]
J
Jingwen Owen Ou 已提交
71 72
	gh := github.NewClient(url.Project.Host)
	pullRequest, err := gh.PullRequest(url.Project, id)
73 74 75
	if err != nil {
		return err
	}
J
Jingwen Owen Ou 已提交
76

77 78 79
	if idx := args.IndexOfParam(newBranchName); idx >= 0 {
		args.RemoveParam(idx)
	}
J
Jingwen Owen Ou 已提交
80

81 82 83
	repo, err := github.LocalRepo()
	if err != nil {
		return err
84 85
	}

86 87 88
	remote, err := repo.RemoteForRepo(pullRequest.Base.Repo)
	if err != nil {
		return err
J
Jingwen Owen Ou 已提交
89
	}
90

91 92 93 94 95 96 97 98 99 100 101 102
	var refSpec string
	var newArgs []string

	if pullRequest.IsSameRepo() {
		if newBranchName == "" {
			newBranchName = pullRequest.Head.Ref
		}
		remoteBranch := fmt.Sprintf("%s/%s", remote.Name, pullRequest.Head.Ref)
		refSpec = fmt.Sprintf("+refs/heads/%s:refs/remotes/%s", pullRequest.Head.Ref, remoteBranch)
		newArgs = append(newArgs, "-b", newBranchName, "--track", remoteBranch)
	} else {
		if newBranchName == "" {
103 104 105 106 107
			if pullRequest.Head.Repo == nil {
				newBranchName = fmt.Sprintf("pr-%s", id)
			} else {
				newBranchName = fmt.Sprintf("%s-%s", pullRequest.Head.Repo.Owner.Login, pullRequest.Head.Ref)
			}
108 109 110
		}
		refSpec = fmt.Sprintf("pull/%s/head:%s", id, newBranchName)
		newArgs = append(newArgs, newBranchName)
111
	}
J
Jingwen Owen Ou 已提交
112

113 114
	args.Before("git", "fetch", remote.Name, refSpec)
	replaceCheckoutParam(args, checkoutURL, newArgs...)
115
	return nil
J
Jingwen Owen Ou 已提交
116
}
117

118 119 120 121 122 123 124 125 126 127 128 129
func sanitizeCheckoutFlags(args *Args) error {
	if i := args.IndexOfParam("-b"); i != -1 {
		return fmt.Errorf("Unsupported flag -b when checking out pull request")
	}

	if i := args.IndexOfParam("--orphan"); i != -1 {
		return fmt.Errorf("Unsupported flag --orphan when checking out pull request")
	}

	return nil
}

130
func replaceCheckoutParam(args *Args, checkoutURL string, replacement ...string) {
131 132
	idx := args.IndexOfParam(checkoutURL)
	args.RemoveParam(idx)
133
	args.InsertParam(idx, replacement...)
134
}