161 lines
3.4 KiB
Go
161 lines
3.4 KiB
Go
package command
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
|
|
"github.com/github/gh-cli/api"
|
|
"github.com/github/gh-cli/context"
|
|
"github.com/github/gh-cli/git"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
func prCreate(cmd *cobra.Command, _ []string) error {
|
|
ctx := contextForCommand(cmd)
|
|
|
|
ucc, err := git.UncommittedChangeCount()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if ucc > 0 {
|
|
noun := "change"
|
|
if ucc > 1 {
|
|
// TODO: use pluralize helper
|
|
noun = noun + "s"
|
|
}
|
|
|
|
cmd.Printf("Warning: %d uncommitted %s\n", ucc, noun)
|
|
}
|
|
|
|
head, err := ctx.Branch()
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not determine current branch")
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
title, err := cmd.Flags().GetString("title")
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not parse title")
|
|
}
|
|
body, err := cmd.Flags().GetString("body")
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not parse body")
|
|
}
|
|
|
|
interactive := title == "" || body == ""
|
|
|
|
if interactive {
|
|
tb, err := titleBodySurvey(cmd, title, body)
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not collect title and/or body")
|
|
}
|
|
|
|
if tb == nil {
|
|
// editing was canceled, we can just leave
|
|
return nil
|
|
}
|
|
|
|
if title == "" {
|
|
title = tb.Title
|
|
}
|
|
if body == "" {
|
|
body = tb.Body
|
|
}
|
|
}
|
|
|
|
base, err := cmd.Flags().GetString("base")
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not parse base")
|
|
}
|
|
if base == "" {
|
|
// TODO: use default branch for the repo
|
|
base = "master"
|
|
}
|
|
|
|
client, err := apiClientForContext(ctx)
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not initialize api client")
|
|
}
|
|
|
|
repo, err := ctx.BaseRepo()
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not determine GitHub repo")
|
|
}
|
|
|
|
isDraft, err := cmd.Flags().GetBool("draft")
|
|
if err != nil {
|
|
return errors.Wrap(err, "could not parse draft")
|
|
}
|
|
|
|
params := map[string]interface{}{
|
|
"title": title,
|
|
"body": body,
|
|
"draft": isDraft,
|
|
"baseRefName": base,
|
|
"headRefName": head,
|
|
}
|
|
|
|
pr, err := api.CreatePullRequest(client, repo, params)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to create PR")
|
|
}
|
|
|
|
fmt.Fprintln(cmd.OutOrStdout(), pr.URL)
|
|
return nil
|
|
}
|
|
|
|
func guessRemote(ctx context.Context) (string, error) {
|
|
remotes, err := ctx.Remotes()
|
|
if err != nil {
|
|
return "", errors.Wrap(err, "could not read git remotes")
|
|
}
|
|
|
|
// TODO: consolidate logic with fsContext.BaseRepo
|
|
// TODO: check if the GH repo that the remote points to is writeable
|
|
remote, err := remotes.FindByName("upstream", "github", "origin", "*")
|
|
if err != nil {
|
|
return "", errors.Wrap(err, "could not determine suitable remote")
|
|
}
|
|
|
|
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: prCreate,
|
|
}
|
|
|
|
func init() {
|
|
prCreateCmd.Flags().BoolP("draft", "d", false,
|
|
"Mark PR as a draft")
|
|
prCreateCmd.Flags().StringP("title", "t", "",
|
|
"Supply a title. Will prompt for one otherwise.")
|
|
prCreateCmd.Flags().StringP("body", "b", "",
|
|
"Supply a body. Will prompt for one otherwise.")
|
|
prCreateCmd.Flags().StringP("base", "T", "",
|
|
"The branch into which you want your code merged")
|
|
}
|