checkout.go 2.9 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 84
	branch := pullRequest.Head.Ref
	headRepo := pullRequest.Head.Repo
	if headRepo == nil {
		return fmt.Errorf("Error: that fork is not available anymore")
85
	}
86
	user := headRepo.Owner.Login
87

88
	if newBranchName == "" {
89
		newBranchName = fmt.Sprintf("%s-%s", user, branch)
J
Jingwen Owen Ou 已提交
90
	}
91

92 93 94
	repo, err := github.LocalRepo()
	utils.Check(err)

J
Jingwen Owen Ou 已提交
95
	_, err = repo.RemoteByName(user)
96 97 98 99 100
	if err == nil {
		args.Before("git", "remote", "set-branches", "--add", user, branch)
		remoteURL := fmt.Sprintf("+refs/heads/%s:refs/remotes/%s/%s", branch, user, branch)
		args.Before("git", "fetch", user, remoteURL)
	} else {
H
huydx 已提交
101
		u := url.Project.GitURL(headRepo.Name, user, headRepo.Private)
102
		args.Before("git", "remote", "add", "-f", "--no-tags", "-t", branch, user, u)
103
	}
J
Jingwen Owen Ou 已提交
104

105 106
	remoteName := fmt.Sprintf("%s/%s", user, branch)
	replaceCheckoutParam(args, checkoutURL, newBranchName, remoteName)
J
Jingwen Owen Ou 已提交
107

108
	return nil
J
Jingwen Owen Ou 已提交
109
}
110

111 112 113 114 115 116 117 118 119 120 121 122
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
}

123 124 125 126 127
func replaceCheckoutParam(args *Args, checkoutURL, branchName, remoteName string) {
	idx := args.IndexOfParam(checkoutURL)
	args.RemoveParam(idx)
	args.InsertParam(idx, "--track", "-B", branchName, remoteName)
}