Skip to content

Commit d6e84a7

Browse files
committed
switch to recover instead of resubmit
1 parent 1d408eb commit d6e84a7

8 files changed

Lines changed: 188 additions & 131 deletions

File tree

pkg/cmd/issue/create/create.go

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ type CreateOptions struct {
2626

2727
RepoOverride string
2828
WebMode bool
29-
JSONFill bool
30-
JSONInput string
29+
RecoverFile string
3130

3231
Title string
3332
Body string
@@ -64,22 +63,17 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
6463
titleProvided := cmd.Flags().Changed("title")
6564
bodyProvided := cmd.Flags().Changed("body")
6665
opts.RepoOverride, _ = cmd.Flags().GetString("repo")
67-
opts.JSONFill = cmd.Flags().Changed("json")
66+
67+
if !opts.IO.CanPrompt() && opts.RecoverFile != "" {
68+
return &cmdutil.FlagError{Err: errors.New("--recover only supported when running interactively")}
69+
}
6870

6971
opts.Interactive = !(titleProvided && bodyProvided)
7072

7173
if opts.Interactive && !opts.IO.CanPrompt() {
7274
return &cmdutil.FlagError{Err: errors.New("must provide --title and --body when not running interactively")}
7375
}
7476

75-
if opts.JSONFill {
76-
opts.Interactive = false
77-
78-
if opts.WebMode {
79-
return errors.New("--web and --json are mutually exclusive")
80-
}
81-
}
82-
8377
if runF != nil {
8478
return runF(opts)
8579
}
@@ -94,7 +88,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
9488
cmd.Flags().StringSliceVarP(&opts.Labels, "label", "l", nil, "Add labels by `name`")
9589
cmd.Flags().StringSliceVarP(&opts.Projects, "project", "p", nil, "Add the issue to projects by `name`")
9690
cmd.Flags().StringVarP(&opts.Milestone, "milestone", "m", "", "Add the issue to a milestone by `name`")
97-
cmd.Flags().StringVarP(&opts.JSONInput, "json", "j", "", "Use JSON to populate and submit issue")
91+
cmd.Flags().StringVarP(&opts.RecoverFile, "recover", "e", "", "Recover input from a failed run of create")
9892

9993
return cmd
10094
}
@@ -130,6 +124,14 @@ func createRun(opts *CreateOptions) (err error) {
130124
Body: opts.Body,
131125
}
132126

127+
if opts.RecoverFile != "" {
128+
err = prShared.FillFromJSON(opts.IO, opts.RecoverFile, &tb)
129+
if err != nil {
130+
err = fmt.Errorf("failed to recover input: %w", err)
131+
return
132+
}
133+
}
134+
133135
if opts.WebMode {
134136
openURL := ghrepo.GenerateRepoURL(baseRepo, "issues/new")
135137
if opts.Title != "" || opts.Body != "" {
@@ -170,19 +172,21 @@ func createRun(opts *CreateOptions) (err error) {
170172

171173
defer prShared.PreserveInput(opts.IO, &tb, &err)()
172174

173-
if tb.Title == "" {
175+
if opts.Title == "" {
174176
err = prShared.TitleSurvey(&tb)
175177
if err != nil {
176178
return
177179
}
178180
}
179181

180-
if tb.Body == "" {
182+
if opts.Body == "" {
181183
templateContent := ""
182184

183-
templateContent, err = prShared.TemplateSurvey(templateFiles, legacyTemplate, tb)
184-
if err != nil {
185-
return
185+
if opts.RecoverFile == "" {
186+
templateContent, err = prShared.TemplateSurvey(templateFiles, legacyTemplate, tb)
187+
if err != nil {
188+
return
189+
}
186190
}
187191

188192
err = prShared.BodySurvey(&tb, templateContent, editorCommand)
@@ -218,13 +222,6 @@ func createRun(opts *CreateOptions) (err error) {
218222
fmt.Fprintln(opts.IO.ErrOut, "Discarding.")
219223
return
220224
}
221-
} else if opts.JSONFill {
222-
err = prShared.FillFromJSON(opts.IO, opts.JSONInput, &tb)
223-
if err != nil {
224-
return
225-
}
226-
227-
action = prShared.SubmitAction
228225
} else {
229226
if tb.Title == "" {
230227
err = fmt.Errorf("title can't be blank")

pkg/cmd/issue/create/create_test.go

Lines changed: 63 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ package create
33
import (
44
"bytes"
55
"encoding/json"
6+
"fmt"
67
"io/ioutil"
78
"net/http"
9+
"os"
810
"os/exec"
911
"reflect"
1012
"strings"
@@ -13,6 +15,7 @@ import (
1315
"github.com/cli/cli/internal/config"
1416
"github.com/cli/cli/internal/ghrepo"
1517
"github.com/cli/cli/internal/run"
18+
prShared "github.com/cli/cli/pkg/cmd/pr/shared"
1619
"github.com/cli/cli/pkg/cmdutil"
1720
"github.com/cli/cli/pkg/httpmock"
1821
"github.com/cli/cli/pkg/iostreams"
@@ -126,7 +129,7 @@ func TestIssueCreate(t *testing.T) {
126129
eq(t, output.String(), "https://github.com/OWNER/REPO/issues/12\n")
127130
}
128131

129-
func TestIssueCreate_JSON(t *testing.T) {
132+
func TestIssueCreate_recover(t *testing.T) {
130133
http := &httpmock.Registry{}
131134
defer http.Verify(t)
132135

@@ -136,32 +139,72 @@ func TestIssueCreate_JSON(t *testing.T) {
136139
"hasIssuesEnabled": true
137140
} } }
138141
`))
139-
http.StubResponse(200, bytes.NewBufferString(`
142+
http.Register(
143+
httpmock.GraphQL(`query RepositoryResolveMetadataIDs\b`),
144+
httpmock.StringResponse(`
145+
{ "data": {
146+
"u000": { "login": "MonaLisa", "id": "MONAID" },
147+
"repository": {
148+
"l000": { "name": "bug", "id": "BUGID" },
149+
"l001": { "name": "TODO", "id": "TODOID" }
150+
}
151+
} }
152+
`))
153+
http.Register(
154+
httpmock.GraphQL(`mutation IssueCreate\b`),
155+
httpmock.GraphQLMutation(`
140156
{ "data": { "createIssue": { "issue": {
141157
"URL": "https://github.com/OWNER/REPO/issues/12"
142158
} } } }
143-
`))
159+
`, func(inputs map[string]interface{}) {
160+
eq(t, inputs["title"], "recovered title")
161+
eq(t, inputs["body"], "recovered body")
162+
eq(t, inputs["labelIds"], []interface{}{"BUGID", "TODOID"})
163+
}))
144164

145-
output, err := runCommand(http, true, `-j'{"title":"cool", "body":"issue"}'`)
146-
if err != nil {
147-
t.Errorf("error running command `issue create`: %v", err)
165+
as, teardown := prompt.InitAskStubber()
166+
defer teardown()
167+
168+
as.Stub([]*prompt.QuestionStub{
169+
{
170+
Name: "Title",
171+
Default: true,
172+
},
173+
})
174+
as.Stub([]*prompt.QuestionStub{
175+
{
176+
Name: "Body",
177+
Default: true,
178+
},
179+
})
180+
as.Stub([]*prompt.QuestionStub{
181+
{
182+
Name: "confirmation",
183+
Value: 0,
184+
},
185+
})
186+
187+
tmpfile, err := ioutil.TempFile(os.TempDir(), "testrecover*")
188+
assert.NoError(t, err)
189+
190+
state := prShared.IssueMetadataState{
191+
Title: "recovered title",
192+
Body: "recovered body",
193+
Labels: []string{"bug", "TODO"},
148194
}
149195

150-
bodyBytes, _ := ioutil.ReadAll(http.Requests[1].Body)
151-
reqBody := struct {
152-
Variables struct {
153-
Input struct {
154-
RepositoryID string
155-
Title string
156-
Body string
157-
}
158-
}
159-
}{}
160-
_ = json.Unmarshal(bodyBytes, &reqBody)
196+
data, err := json.Marshal(state)
197+
assert.NoError(t, err)
161198

162-
eq(t, reqBody.Variables.Input.RepositoryID, "REPOID")
163-
eq(t, reqBody.Variables.Input.Title, "cool")
164-
eq(t, reqBody.Variables.Input.Body, "issue")
199+
_, err = tmpfile.Write(data)
200+
assert.NoError(t, err)
201+
202+
args := fmt.Sprintf("-e '%s'", tmpfile.Name())
203+
204+
output, err := runCommandWithRootDirOverridden(http, true, args, "")
205+
if err != nil {
206+
t.Errorf("error running command `issue create`: %v", err)
207+
}
165208

166209
eq(t, output.String(), "https://github.com/OWNER/REPO/issues/12\n")
167210
}

pkg/cmd/pr/create/create.go

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,9 @@ type CreateOptions struct {
3838
RootDirOverride string
3939
RepoOverride string
4040

41-
Autofill bool
42-
WebMode bool
43-
JSONFill bool
44-
JSONInput string
41+
Autofill bool
42+
WebMode bool
43+
RecoverFile string
4544

4645
IsDraft bool
4746
Title string
@@ -101,12 +100,15 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
101100
`),
102101
Args: cmdutil.NoArgsQuoteReminder,
103102
RunE: func(cmd *cobra.Command, args []string) error {
104-
opts.JSONFill = cmd.Flags().Changed("json")
105103
opts.TitleProvided = cmd.Flags().Changed("title")
106104
opts.BodyProvided = cmd.Flags().Changed("body")
107105
opts.RepoOverride, _ = cmd.Flags().GetString("repo")
108106

109-
if !opts.IO.CanPrompt() && !opts.JSONFill && !opts.WebMode && !opts.TitleProvided && !opts.Autofill {
107+
if !opts.IO.CanPrompt() && opts.RecoverFile != "" {
108+
return &cmdutil.FlagError{Err: errors.New("--recover only supported when running interactively")}
109+
}
110+
111+
if !opts.IO.CanPrompt() && !opts.WebMode && !opts.TitleProvided && !opts.Autofill {
110112
return &cmdutil.FlagError{Err: errors.New("--title or --fill required when not running interactively")}
111113
}
112114

@@ -117,10 +119,6 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
117119
return errors.New("the --reviewer flag is not supported with --web")
118120
}
119121

120-
if opts.JSONFill && opts.WebMode {
121-
return errors.New("--web and --json are mutually exclusive")
122-
}
123-
124122
if runF != nil {
125123
return runF(opts)
126124
}
@@ -141,7 +139,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
141139
fl.StringSliceVarP(&opts.Labels, "label", "l", nil, "Add labels by `name`")
142140
fl.StringSliceVarP(&opts.Projects, "project", "p", nil, "Add the pull request to projects by `name`")
143141
fl.StringVarP(&opts.Milestone, "milestone", "m", "", "Add the pull request to a milestone by `name`")
144-
fl.StringVarP(&opts.JSONInput, "json", "j", "", "Use JSON to populate and submit PR")
142+
fl.StringVarP(&opts.RecoverFile, "recover", "e", "", "Recover input from a failed run of create")
145143

146144
return cmd
147145
}
@@ -212,18 +210,11 @@ func createRun(opts *CreateOptions) (err error) {
212210
return submitPR(*opts, *ctx, *state)
213211
}
214212

215-
if opts.JSONFill {
216-
err = shared.FillFromJSON(opts.IO, opts.JSONInput, state)
213+
if opts.RecoverFile != "" {
214+
err = shared.FillFromJSON(opts.IO, opts.RecoverFile, state)
217215
if err != nil {
218-
return fmt.Errorf("could not use JSON input: %w", err)
216+
return fmt.Errorf("failed to recover input: %w", err)
219217
}
220-
221-
err = handlePush(*opts, *ctx)
222-
if err != nil {
223-
return
224-
}
225-
226-
return submitPR(*opts, *ctx, *state)
227218
}
228219

229220
if !opts.TitleProvided {
@@ -242,11 +233,13 @@ func createRun(opts *CreateOptions) (err error) {
242233

243234
templateContent := ""
244235
if !opts.BodyProvided {
245-
templateFiles, legacyTemplate := shared.FindTemplates(opts.RootDirOverride, "PULL_REQUEST_TEMPLATE")
236+
if opts.RecoverFile == "" {
237+
templateFiles, legacyTemplate := shared.FindTemplates(opts.RootDirOverride, "PULL_REQUEST_TEMPLATE")
246238

247-
templateContent, err = shared.TemplateSurvey(templateFiles, legacyTemplate, *state)
248-
if err != nil {
249-
return
239+
templateContent, err = shared.TemplateSurvey(templateFiles, legacyTemplate, *state)
240+
if err != nil {
241+
return
242+
}
250243
}
251244

252245
err = shared.BodySurvey(state, templateContent, editorCommand)

0 commit comments

Comments
 (0)