cli/command/pr_create.go
2019-10-30 12:01:54 -05:00

207 lines
4.2 KiB
Go

package command
import (
"fmt"
"github.com/AlecAivazis/survey/v2"
"github.com/github/gh-cli/api"
"github.com/github/gh-cli/context"
"github.com/github/gh-cli/git"
"github.com/github/gh-cli/utils"
"github.com/spf13/cobra"
"os"
"runtime"
)
var (
_draftF bool
_titleF string
_bodyF string
_baseF string
)
func prCreate(ctx context.Context) error {
ucc, err := git.UncommittedChangeCount()
if err != nil {
return fmt.Errorf(
"could not determine state of working directory: %v", err)
}
if ucc > 0 {
noun := "change"
if ucc > 1 {
noun = noun + "s"
}
fmt.Printf("%s %d uncommitted %s %s", utils.Red("!!!"),
ucc, noun, utils.Red("!!!"))
}
head, err := ctx.Branch()
if err != nil {
return fmt.Errorf("could not determine current branch: %s", err)
}
remote, err := guessRemote(ctx)
if err != nil {
return err
}
if err = git.Push(remote, fmt.Sprintf("HEAD:%s", head)); err != nil {
return fmt.Errorf("was not able to push to remote '%s': %s", remote, err)
}
interactive := _titleF == "" || _bodyF == ""
inProgress := struct {
Body string
Title string
}{}
if interactive {
confirmed := false
editor := determineEditor()
for !confirmed {
titleQuestion := &survey.Question{
Name: "title",
Prompt: &survey.Input{
Message: "PR Title",
Default: inProgress.Title,
},
}
bodyQuestion := &survey.Question{
Name: "body",
Prompt: &survey.Editor{
Message: fmt.Sprintf("PR Body (%s)", editor),
FileName: "*.md",
Default: inProgress.Body,
AppendDefault: true,
Editor: editor,
},
}
qs := []*survey.Question{}
if _titleF == "" {
qs = append(qs, titleQuestion)
}
if _bodyF == "" {
qs = append(qs, bodyQuestion)
}
err := survey.Ask(qs, &inProgress)
if err != nil {
return fmt.Errorf("could not prompt: %s", err)
}
confirmAnswers := struct {
Confirmation string
}{}
confirmQs := []*survey.Question{
{
Name: "confirmation",
Prompt: &survey.Select{
Message: "Submit?",
Options: []string{
"Yes",
"Edit",
"Cancel",
},
},
},
}
err = survey.Ask(confirmQs, &confirmAnswers)
if err != nil {
return fmt.Errorf("could not prompt: %s", err)
}
switch confirmAnswers.Confirmation {
case "Yes":
confirmed = true
case "Edit":
continue
case "Cancel":
fmt.Println(utils.Red("Discarding PR."))
return nil
}
}
}
title := _titleF
if title == "" {
title = inProgress.Title
}
body := _bodyF
if body == "" {
body = inProgress.Body
}
base := _baseF
if base == "" {
base = "master"
}
client, err := apiClientForContext(ctx)
if err != nil {
return fmt.Errorf("could not initialize api client: %s", err)
}
repo, err := ctx.BaseRepo()
if err != nil {
return fmt.Errorf("could not determine GitHub repo: %s", err)
}
payload, err := api.CreatePullRequest(client, repo, title, body, _draftF, base, head)
if err != nil {
return fmt.Errorf("failed to create PR: %s", err)
}
fmt.Println(payload)
return nil
}
func guessRemote(ctx context.Context) (string, error) {
remotes, err := ctx.Remotes()
if err != nil {
return "", fmt.Errorf("could not determine suitable remote: %s", err)
}
remote, err := remotes.FindByName("origin", "github")
if err != nil {
return "", fmt.Errorf("could not determine suitable remote: %s", err)
}
return remote.Name, nil
}
func determineEditor() string {
if runtime.GOOS == "windows" {
return "notepad"
}
if v := os.Getenv("VISUAL"); v != "" {
return v
}
if e := os.Getenv("EDITOR"); e != "" {
return e
}
return "nano"
}
var prCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a pull request",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := contextForCommand(cmd)
return prCreate(ctx)
},
}
func init() {
prCreateCmd.Flags().BoolVarP(&_draftF, "draft", "d", false,
"Mark PR as a draft")
prCreateCmd.Flags().StringVarP(&_titleF, "title", "t", "",
"Supply a title. Will prompt for one otherwise.")
prCreateCmd.Flags().StringVarP(&_bodyF, "body", "b", "",
"Supply a body. Will prompt for one otherwise.")
prCreateCmd.Flags().StringVarP(&_baseF, "base", "T", "",
"The branch into which you want your code merged")
}