gist delete prompt with gist description
This commit is contained in:
parent
7d1d261c82
commit
9c65a32ef8
6 changed files with 78 additions and 49 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue