Prototype issue create
This commit is contained in:
parent
5d2ecf12ca
commit
401aef283f
3 changed files with 154 additions and 0 deletions
|
|
@ -32,6 +32,7 @@ type IssuesPayload struct {
|
|||
type Issue struct {
|
||||
Number int
|
||||
Title string
|
||||
URL string
|
||||
}
|
||||
|
||||
func Issues(client *Client, ghRepo Repo, currentUsername string) (*IssuesPayload, error) {
|
||||
|
|
|
|||
70
api/queries_issue.go
Normal file
70
api/queries_issue.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package api
|
||||
|
||||
import "fmt"
|
||||
|
||||
func IssueCreate(client *Client, ghRepo Repo, params map[string]interface{}) (*Issue, error) {
|
||||
repoId, err := GitHubRepoId(client, ghRepo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
query := `
|
||||
mutation CreateIssue($input: CreateIssueInput!) {
|
||||
createIssue(input: $input) {
|
||||
issue {
|
||||
url
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
inputParams := map[string]interface{}{
|
||||
"repositoryId": repoId,
|
||||
}
|
||||
for key, val := range params {
|
||||
inputParams[key] = val
|
||||
}
|
||||
variables := map[string]interface{}{
|
||||
"input": inputParams,
|
||||
}
|
||||
|
||||
result := struct {
|
||||
CreateIssue struct {
|
||||
Issue Issue
|
||||
}
|
||||
}{}
|
||||
|
||||
err = client.GraphQL(query, variables, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result.CreateIssue.Issue, nil
|
||||
}
|
||||
|
||||
func GitHubRepoId(client *Client, ghRepo Repo) (string, error) {
|
||||
owner := ghRepo.RepoOwner()
|
||||
repo := ghRepo.RepoName()
|
||||
|
||||
query := `
|
||||
query FindRepoID($owner:String!, $name:String!) {
|
||||
repository(owner:$owner, name:$name) {
|
||||
id
|
||||
}
|
||||
}`
|
||||
variables := map[string]interface{}{
|
||||
"owner": owner,
|
||||
"name": repo,
|
||||
}
|
||||
|
||||
result := struct {
|
||||
Repository struct {
|
||||
Id string
|
||||
}
|
||||
}{}
|
||||
err := client.GraphQL(query, variables, &result)
|
||||
if err != nil || result.Repository.Id == "" {
|
||||
return "", fmt.Errorf("failed to determine GH repo ID: %s", err)
|
||||
}
|
||||
|
||||
return result.Repository.Id, nil
|
||||
}
|
||||
|
|
@ -2,11 +2,15 @@ package command
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/github/gh-cli/api"
|
||||
"github.com/github/gh-cli/utils"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
@ -24,6 +28,9 @@ func init() {
|
|||
RunE: issueView,
|
||||
},
|
||||
)
|
||||
issueCmd.AddCommand(issueCreateCmd)
|
||||
issueCreateCmd.Flags().StringArrayP("message", "m", nil, "set title and body")
|
||||
issueCreateCmd.Flags().BoolP("web", "w", false, "open the web browser to create an issue")
|
||||
}
|
||||
|
||||
var issueCmd = &cobra.Command{
|
||||
|
|
@ -31,6 +38,11 @@ var issueCmd = &cobra.Command{
|
|||
Short: "Work with GitHub issues",
|
||||
Long: `Helps you work with issues.`,
|
||||
}
|
||||
var issueCreateCmd = &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create a new issue",
|
||||
RunE: issueCreate,
|
||||
}
|
||||
|
||||
func issueList(cmd *cobra.Command, args []string) error {
|
||||
cmd.SilenceUsage = true
|
||||
|
|
@ -106,6 +118,77 @@ func issueView(cmd *cobra.Command, args []string) error {
|
|||
return utils.OpenInBrowser(openURL)
|
||||
}
|
||||
|
||||
func issueCreate(cmd *cobra.Command, args []string) error {
|
||||
ctx := contextForCommand(cmd)
|
||||
|
||||
baseRepo, err := ctx.BaseRepo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isWeb, err := cmd.Flags().GetBool("web"); err == nil && isWeb {
|
||||
// TODO: move URL generation into GitHubRepository
|
||||
openURL := fmt.Sprintf("https://github.com/%s/%s/issues/new", baseRepo.RepoOwner(), baseRepo.RepoName())
|
||||
// TODO: figure out how to stub this in tests
|
||||
if stat, err := os.Stat(".github/ISSUE_TEMPLATE"); err == nil && stat.IsDir() {
|
||||
openURL += "/choose"
|
||||
}
|
||||
return utils.OpenInBrowser(openURL)
|
||||
}
|
||||
|
||||
var title string
|
||||
var body string
|
||||
|
||||
message, err := cmd.Flags().GetStringArray("message")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
apiClient, err := apiClientForContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(message) > 0 {
|
||||
title = message[0]
|
||||
body = strings.Join(message[1:], "\n\n")
|
||||
} else {
|
||||
// TODO: open the text editor for issue title & body
|
||||
input := os.Stdin
|
||||
if terminal.IsTerminal(int(input.Fd())) {
|
||||
cmd.Println("Enter the issue title and body; press Enter + Ctrl-D when done:")
|
||||
}
|
||||
inputBytes, err := ioutil.ReadAll(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parts := strings.SplitN(string(inputBytes), "\n\n", 2)
|
||||
if len(parts) > 0 {
|
||||
title = parts[0]
|
||||
}
|
||||
if len(parts) > 1 {
|
||||
body = parts[1]
|
||||
}
|
||||
}
|
||||
|
||||
if title == "" {
|
||||
return fmt.Errorf("aborting due to empty title")
|
||||
}
|
||||
params := map[string]interface{}{
|
||||
"title": title,
|
||||
"body": body,
|
||||
}
|
||||
|
||||
newIssue, err := api.IssueCreate(apiClient, baseRepo, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintln(cmd.OutOrStdout(), newIssue.URL)
|
||||
return nil
|
||||
}
|
||||
|
||||
func printIssues(issues ...api.Issue) {
|
||||
for _, issue := range issues {
|
||||
fmt.Printf(" #%d %s\n", issue.Number, truncateTitle(issue.Title, 70))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue