github.com/trevoraustin/hub@v2.2.0-preview1.0.20141105230840-96d8bfc654cc+incompatible/commands/checkout.go (about)

     1  package commands
     2  
     3  import (
     4  	"fmt"
     5  	"regexp"
     6  
     7  	"github.com/github/hub/github"
     8  	"github.com/github/hub/utils"
     9  )
    10  
    11  var cmdCheckout = &Command{
    12  	Run:          checkout,
    13  	GitExtension: true,
    14  	Usage:        "checkout PULLREQ-URL [BRANCH]",
    15  	Short:        "Switch the active branch to another branch",
    16  	Long: `Checks out the head of the pull request as a local branch, to allow for
    17  reviewing, rebasing and otherwise cleaning up the commits in the pull
    18  request before merging. The name of the local branch can explicitly be
    19  set with BRANCH.
    20  `,
    21  }
    22  
    23  func init() {
    24  	CmdRunner.Use(cmdCheckout)
    25  }
    26  
    27  /**
    28    $ gh checkout https://github.com/jingweno/gh/pull/73
    29    > git remote add -f -t feature git://github:com/foo/gh.git
    30    > git checkout --track -B foo-feature foo/feature
    31  
    32    $ gh checkout https://github.com/jingweno/gh/pull/73 custom-branch-name
    33  **/
    34  func checkout(command *Command, args *Args) {
    35  	if !args.IsParamsEmpty() {
    36  		err := transformCheckoutArgs(args)
    37  		utils.Check(err)
    38  	}
    39  }
    40  
    41  func transformCheckoutArgs(args *Args) error {
    42  	words := args.Words()
    43  
    44  	if len(words) == 0 {
    45  		return nil
    46  	}
    47  
    48  	checkoutURL := words[0]
    49  	var newBranchName string
    50  	if len(words) > 1 {
    51  		newBranchName = words[1]
    52  	}
    53  
    54  	url, err := github.ParseURL(checkoutURL)
    55  	if err != nil {
    56  		// not a valid GitHub URL
    57  		return nil
    58  	}
    59  
    60  	pullURLRegex := regexp.MustCompile("^pull/(\\d+)")
    61  	projectPath := url.ProjectPath()
    62  	if !pullURLRegex.MatchString(projectPath) {
    63  		// not a valid PR URL
    64  		return nil
    65  	}
    66  
    67  	id := pullURLRegex.FindStringSubmatch(projectPath)[1]
    68  	gh := github.NewClient(url.Project.Host)
    69  	pullRequest, err := gh.PullRequest(url.Project, id)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	if idx := args.IndexOfParam(newBranchName); idx >= 0 {
    75  		args.RemoveParam(idx)
    76  	}
    77  
    78  	user, branch := parseUserBranchFromPR(pullRequest)
    79  	if pullRequest.Head.Repo == nil {
    80  		return fmt.Errorf("Error: %s's fork is not available anymore", user)
    81  	}
    82  
    83  	if newBranchName == "" {
    84  		newBranchName = fmt.Sprintf("%s-%s", user, branch)
    85  	}
    86  
    87  	repo, err := github.LocalRepo()
    88  	utils.Check(err)
    89  
    90  	_, err = repo.RemoteByName(user)
    91  	if err == nil {
    92  		args.Before("git", "remote", "set-branches", "--add", user, branch)
    93  		remoteURL := fmt.Sprintf("+refs/heads/%s:refs/remotes/%s/%s", branch, user, branch)
    94  		args.Before("git", "fetch", user, remoteURL)
    95  	} else {
    96  		u := url.Project.GitURL("", user, pullRequest.Head.Repo.Private)
    97  		args.Before("git", "remote", "add", "-f", "-t", branch, user, u)
    98  	}
    99  
   100  	idx := args.IndexOfParam(checkoutURL)
   101  	args.RemoveParam(idx)
   102  	args.InsertParam(idx, "--track", "-B", newBranchName, fmt.Sprintf("%s/%s", user, branch))
   103  
   104  	return nil
   105  }