github.com/abhinav/git-pr@v0.6.1-0.20171029234004-54218d68c11b/cmd/git-pr/land.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"log"
     7  
     8  	"github.com/abhinav/git-pr/cli"
     9  	"github.com/abhinav/git-pr/editor"
    10  	"github.com/abhinav/git-pr/service"
    11  
    12  	"github.com/google/go-github/github"
    13  	"github.com/jessevdk/go-flags"
    14  )
    15  
    16  type landCmd struct {
    17  	Editor string `long:"editor" env:"EDITOR" default:"vi" value-name:"EDITOR" description:"Editor to use for interactively editing commit messages."`
    18  	Args   struct {
    19  		Branch string `positional-arg-name:"BRANCH" description:"Name of the branch to land. Defaults to the branch in the current directory."`
    20  	} `positional-args:"yes"`
    21  
    22  	getConfig configBuilder
    23  	getEditor func(string) (editor.Editor, error)
    24  }
    25  
    26  func newLandCommand(cbuild cli.ConfigBuilder) flags.Commander {
    27  	return &landCmd{
    28  		getConfig: newConfigBuilder(cbuild),
    29  		getEditor: editor.Pick,
    30  	}
    31  }
    32  
    33  func (l *landCmd) Execute([]string) error {
    34  	ctx := context.Background()
    35  
    36  	cfg, err := l.getConfig()
    37  	if err != nil {
    38  		return err
    39  	}
    40  
    41  	editor, err := l.getEditor(l.Editor)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	req := service.LandRequest{Editor: editor}
    47  
    48  	// TODO: accept other inputs for the PR to land
    49  	branch := l.Args.Branch
    50  	if branch == "" {
    51  		out, err := cfg.Git().CurrentBranch()
    52  		if err != nil {
    53  			return err
    54  		}
    55  		branch = out
    56  		req.LocalBranch = out
    57  	}
    58  
    59  	prs, err := cfg.GitHub().ListPullRequestsByHead(ctx, "", branch)
    60  	if err != nil {
    61  		return err
    62  	}
    63  	switch len(prs) {
    64  	case 0:
    65  		return fmt.Errorf("Could not find PRs with head %q", branch)
    66  	case 1:
    67  		req.PullRequest = prs[0]
    68  	default:
    69  		return errTooManyPRsWithHead{Head: branch, Pulls: prs}
    70  	}
    71  
    72  	log.Println("Landing", *req.PullRequest.HTMLURL)
    73  	res, err := cfg.Service.Land(ctx, &req)
    74  	if err != nil {
    75  		return fmt.Errorf("failed to land %v: %v", *req.PullRequest.HTMLURL, err)
    76  	}
    77  
    78  	if len(res.BranchesNotUpdated) > 0 {
    79  		log.Println("The following local branches were not updated because " +
    80  			"they did not match the corresponding remotes")
    81  		for _, br := range res.BranchesNotUpdated {
    82  			log.Println(" -", br)
    83  		}
    84  	}
    85  	return nil
    86  }
    87  
    88  type errTooManyPRsWithHead struct {
    89  	Head  string
    90  	Pulls []*github.PullRequest
    91  }
    92  
    93  func (e errTooManyPRsWithHead) Error() string {
    94  	msg := fmt.Sprintf("Too many PRs found with head %q:", e.Head)
    95  	for _, pull := range e.Pulls {
    96  		msg += fmt.Sprintf("\n -  %v", *pull.HTMLURL)
    97  	}
    98  	// TODO: when we support this:
    99  	// msg += fmt.Sprintf("\nPlease provide the PR number instead.")
   100  	return msg
   101  }