From 9c65a32ef86343786ec1fa4ef81de0fce412ff1b Mon Sep 17 00:00:00 2001 From: danochoa Date: Wed, 8 Jan 2025 17:56:02 -0600 Subject: [PATCH] gist delete prompt with gist description --- pkg/cmd/gist/delete/delete.go | 39 ++++++++++++++++-------------- pkg/cmd/gist/delete/delete_test.go | 29 ++++++++++++++++++++-- pkg/cmd/gist/edit/edit.go | 5 ++-- pkg/cmd/gist/shared/shared.go | 19 +++++++-------- pkg/cmd/gist/shared/shared_test.go | 30 +++++++++++------------ pkg/cmd/gist/view/view.go | 5 ++-- 6 files changed, 78 insertions(+), 49 deletions(-) diff --git a/pkg/cmd/gist/delete/delete.go b/pkg/cmd/gist/delete/delete.go index a2b552a3a..c39538d4a 100644 --- a/pkg/cmd/gist/delete/delete.go +++ b/pkg/cmd/gist/delete/delete.go @@ -76,15 +76,6 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co } func deleteRun(opts *DeleteOptions) error { - gistID := opts.Selector - - if strings.Contains(gistID, "/") { - id, err := shared.GistIDFromURL(gistID) - if err != nil { - return err - } - gistID = id - } client, err := opts.HttpClient() if err != nil { return err @@ -97,16 +88,28 @@ func deleteRun(opts *DeleteOptions) error { host, _ := cfg.Authentication().DefaultHost() - cs := opts.IO.ColorScheme() - if gistID == "" { - gistID, err = shared.PromptGists(opts.Prompter, client, host, cs) + gistID := opts.Selector + if strings.Contains(gistID, "/") { + id, err := shared.GistIDFromURL(gistID) if err != nil { return err } + gistID = id + } + + cs := opts.IO.ColorScheme() + var gist *shared.Gist + if gistID == "" { + gist, err = shared.PromptGists(opts.Prompter, client, host, cs) + } else { + gist, err = shared.GetGist(client, host, gistID) + } + if err != nil { + return err } if !opts.Confirmed { - confirmed, err := opts.Prompter.Confirm(fmt.Sprintf("Delete \"%s\" gist?", gistID), false) + confirmed, err := opts.Prompter.Confirm(fmt.Sprintf("Delete \"%s\" gist?", gist.Description), false) if err != nil { return err } @@ -116,9 +119,9 @@ func deleteRun(opts *DeleteOptions) error { } apiClient := api.NewClientFromHTTP(client) - if err := deleteGist(apiClient, host, gistID, opts); err != nil { + if err := deleteGist(apiClient, host, gist, opts); err != nil { if errors.Is(err, shared.NotFoundErr) { - return fmt.Errorf("unable to delete gist %s: either the gist is not found or it is not owned by you", gistID) + return fmt.Errorf("unable to delete gist %s: either the gist is not found or it is not owned by you", gist.Description) } return err } @@ -126,8 +129,8 @@ func deleteRun(opts *DeleteOptions) error { return nil } -func deleteGist(apiClient *api.Client, hostname string, gistID string, opts *DeleteOptions) error { - path := "gists/" + gistID +func deleteGist(apiClient *api.Client, hostname string, gist *shared.Gist, opts *DeleteOptions) error { + path := "gists/" + gist.ID err := apiClient.REST(hostname, "DELETE", path, nil, nil) if err != nil { var httpErr api.HTTPError @@ -141,7 +144,7 @@ func deleteGist(apiClient *api.Client, hostname string, gistID string, opts *Del fmt.Fprintf(opts.IO.Out, "%s Gist \"%s\" deleted\n", cs.SuccessIcon(), - gistID) + gist.Description) } return nil } diff --git a/pkg/cmd/gist/delete/delete_test.go b/pkg/cmd/gist/delete/delete_test.go index 237e3f768..010f65d5e 100644 --- a/pkg/cmd/gist/delete/delete_test.go +++ b/pkg/cmd/gist/delete/delete_test.go @@ -10,6 +10,7 @@ import ( "github.com/cli/cli/v2/internal/config" "github.com/cli/cli/v2/internal/gh" "github.com/cli/cli/v2/internal/prompter" + "github.com/cli/cli/v2/pkg/cmd/gist/shared" "github.com/cli/cli/v2/pkg/cmdutil" "github.com/cli/cli/v2/pkg/httpmock" "github.com/cli/cli/v2/pkg/iostreams" @@ -131,6 +132,8 @@ func Test_deleteRun(t *testing.T) { Selector: "1234", }, httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("GET", "gists/1234"), + httpmock.JSONResponse(shared.Gist{ID: "1234", Description: "1234"})) reg.Register(httpmock.REST("DELETE", "gists/1234"), httpmock.StatusStringResponse(200, "{}")) }, @@ -159,6 +162,8 @@ func Test_deleteRun(t *testing.T) { Confirmed: true, }, httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("GET", "gists/1234"), + httpmock.JSONResponse(shared.Gist{ID: "1234", Description: "1234"})) reg.Register(httpmock.REST("DELETE", "gists/1234"), httpmock.StatusStringResponse(200, "{}")) }, @@ -186,6 +191,24 @@ func Test_deleteRun(t *testing.T) { opts: &DeleteOptions{ Selector: "1234", }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("GET", "gists/1234"), + httpmock.JSONResponse(shared.Gist{ID: "1234", Description: "1234"})) + }, + cancel: true, + wantErr: true, + wantStdout: "", + wantStderr: "", + }, + { + name: "cancel delete with url", + opts: &DeleteOptions{ + Selector: "https://gist.github.com/myrepo/1234", + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("GET", "gists/1234"), + httpmock.JSONResponse(shared.Gist{ID: "1234", Description: "1234"})) + }, cancel: true, wantErr: true, wantStdout: "", @@ -207,6 +230,8 @@ func Test_deleteRun(t *testing.T) { Selector: "1234", }, httpStubs: func(reg *httpmock.Registry) { + reg.Register(httpmock.REST("GET", "gists/1234"), + httpmock.JSONResponse(shared.Gist{ID: "1234", Description: "1234"})) reg.Register(httpmock.REST("DELETE", "gists/1234"), httpmock.StatusStringResponse(404, "{}")) }, @@ -237,7 +262,7 @@ func Test_deleteRun(t *testing.T) { { "name": "1234", "files": [{ "name": "cool.txt" }], - "description": "", + "description": "1234", "updatedAt": "%s", "isPublic": true } @@ -246,7 +271,7 @@ func Test_deleteRun(t *testing.T) { )), ) - pm.RegisterSelect("Select a gist", []string{"cool.txt about 6 hours ago"}, func(_, _ string, opts []string) (int, error) { + pm.RegisterSelect("Select a gist", []string{"cool.txt 1234 about 6 hours ago"}, func(_, _ string, opts []string) (int, error) { return 0, nil }) } diff --git a/pkg/cmd/gist/edit/edit.go b/pkg/cmd/gist/edit/edit.go index d777e9581..1e9b61825 100644 --- a/pkg/cmd/gist/edit/edit.go +++ b/pkg/cmd/gist/edit/edit.go @@ -108,15 +108,16 @@ func editRun(opts *EditOptions) error { if gistID == "" { cs := opts.IO.ColorScheme() if gistID == "" { - gistID, err = shared.PromptGists(opts.Prompter, client, host, cs) + gist, err := shared.PromptGists(opts.Prompter, client, host, cs) if err != nil { return err } - if gistID == "" { + if gist.ID == "" { fmt.Fprintln(opts.IO.Out, "No gists found.") return nil } + gistID = gist.ID } } diff --git a/pkg/cmd/gist/shared/shared.go b/pkg/cmd/gist/shared/shared.go index ee6dcf1e3..fa528698f 100644 --- a/pkg/cmd/gist/shared/shared.go +++ b/pkg/cmd/gist/shared/shared.go @@ -202,21 +202,20 @@ func IsBinaryContents(contents []byte) bool { return isBinary } -func PromptGists(prompter prompter.Prompter, client *http.Client, host string, cs *iostreams.ColorScheme) (gistID string, err error) { +func PromptGists(prompter prompter.Prompter, client *http.Client, host string, cs *iostreams.ColorScheme) (gist *Gist, err error) { gists, err := ListGists(client, host, 10, nil, false, "all") if err != nil { - return "", err + return &Gist{}, err } if len(gists) == 0 { - return "", nil + return &Gist{}, nil } - var opts []string - var gistIDs = make([]string, len(gists)) + // var opts []string + var opts = make([]string, len(gists)) for i, gist := range gists { - gistIDs[i] = gist.ID description := "" gistName := "" @@ -234,15 +233,15 @@ func PromptGists(prompter prompter.Prompter, client *http.Client, host string, c gistTime := text.FuzzyAgo(time.Now(), gist.UpdatedAt) // TODO: support dynamic maxWidth description = text.Truncate(100, text.RemoveExcessiveWhitespace(description)) - opt := fmt.Sprintf("%s %s %s", cs.Bold(gistName), description, cs.Gray(gistTime)) - opts = append(opts, opt) + opts[i] = fmt.Sprintf("%s %s %s", cs.Bold(gistName), description, cs.Gray(gistTime)) + // opts = append(opts, opt) } result, err := prompter.Select("Select a gist", "", opts) if err != nil { - return "", err + return &Gist{}, err } - return gistIDs[result], nil + return &gists[result], nil } diff --git a/pkg/cmd/gist/shared/shared_test.go b/pkg/cmd/gist/shared/shared_test.go index 4d185ff7d..15b14a939 100644 --- a/pkg/cmd/gist/shared/shared_test.go +++ b/pkg/cmd/gist/shared/shared_test.go @@ -93,12 +93,15 @@ func TestIsBinaryContents(t *testing.T) { } func TestPromptGists(t *testing.T) { + sixHours, _ := time.ParseDuration("6h") + sixHoursAgo := time.Now().Add(-sixHours) + sixHoursAgoFormatted := sixHoursAgo.Format(time.RFC3339Nano) + tests := []struct { name string prompterStubs func(pm *prompter.MockPrompter) response string - wantOut string - gist *Gist + wantOut Gist wantErr bool }{ { @@ -112,21 +115,21 @@ func TestPromptGists(t *testing.T) { }, response: `{ "data": { "viewer": { "gists": { "nodes": [ { - "name": "gistid1", + "name": "1234", "files": [{ "name": "cool.txt" }], "description": "", "updatedAt": "%[1]v", "isPublic": true }, { - "name": "gistid2", + "name": "5678", "files": [{ "name": "gistfile0.txt" }], "description": "", "updatedAt": "%[1]v", "isPublic": true } ] } } } }`, - wantOut: "gistid1", + wantOut: Gist{ID: "1234", Files: map[string]*GistFile{"cool.txt": {Filename: "cool.txt"}}, UpdatedAt: sixHoursAgo, Public: true}, }, { name: "multiple files, select second gist", @@ -139,26 +142,26 @@ func TestPromptGists(t *testing.T) { }, response: `{ "data": { "viewer": { "gists": { "nodes": [ { - "name": "gistid1", + "name": "1234", "files": [{ "name": "cool.txt" }], "description": "", "updatedAt": "%[1]v", "isPublic": true }, { - "name": "gistid2", + "name": "5678", "files": [{ "name": "gistfile0.txt" }], "description": "", "updatedAt": "%[1]v", "isPublic": true } ] } } } }`, - wantOut: "gistid2", + wantOut: Gist{ID: "5678", Files: map[string]*GistFile{"gistfile0.txt": {Filename: "gistfile0.txt"}}, UpdatedAt: sixHoursAgo, Public: true}, }, { name: "no files", response: `{ "data": { "viewer": { "gists": { "nodes": [] } } } }`, - wantOut: "", + wantOut: Gist{}, }, } @@ -166,15 +169,12 @@ func TestPromptGists(t *testing.T) { for _, tt := range tests { reg := &httpmock.Registry{} - const query = `query GistList\b` - sixHours, _ := time.ParseDuration("6h") - sixHoursAgo := time.Now().Add(-sixHours) reg.Register( httpmock.GraphQL(query), httpmock.StringResponse(fmt.Sprintf( tt.response, - sixHoursAgo.Format(time.RFC3339), + sixHoursAgoFormatted, )), ) client := &http.Client{Transport: reg} @@ -185,9 +185,9 @@ func TestPromptGists(t *testing.T) { tt.prompterStubs(mockPrompter) } - gistID, err := PromptGists(mockPrompter, client, "github.com", ios.ColorScheme()) + gist, err := PromptGists(mockPrompter, client, "github.com", ios.ColorScheme()) assert.NoError(t, err) - assert.Equal(t, tt.wantOut, gistID) + assert.Equal(t, tt.wantOut.ID, gist.ID) reg.Verify(t) }) } diff --git a/pkg/cmd/gist/view/view.go b/pkg/cmd/gist/view/view.go index 2a19f5958..adfe77f6f 100644 --- a/pkg/cmd/gist/view/view.go +++ b/pkg/cmd/gist/view/view.go @@ -89,15 +89,16 @@ func viewRun(opts *ViewOptions) error { cs := opts.IO.ColorScheme() if gistID == "" { - gistID, err = shared.PromptGists(opts.Prompter, client, hostname, cs) + gist, err := shared.PromptGists(opts.Prompter, client, hostname, cs) if err != nil { return err } - if gistID == "" { + if gist.ID == "" { fmt.Fprintln(opts.IO.Out, "No gists found.") return nil } + gistID = gist.ID } if opts.Web {