Add a command to delete a gist (#2265)
* Add a command to delete a gist * minor cleanup Co-authored-by: vilmibm <vilmibm@github.com>
This commit is contained in:
parent
116d5815b5
commit
99574f85a3
3 changed files with 246 additions and 0 deletions
88
pkg/cmd/gist/delete/delete.go
Normal file
88
pkg/cmd/gist/delete/delete.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package delete
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cli/cli/api"
|
||||
"github.com/cli/cli/internal/ghinstance"
|
||||
"github.com/cli/cli/pkg/cmd/gist/shared"
|
||||
"github.com/cli/cli/pkg/cmdutil"
|
||||
"github.com/cli/cli/pkg/iostreams"
|
||||
"github.com/spf13/cobra"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DeleteOptions struct {
|
||||
IO *iostreams.IOStreams
|
||||
HttpClient func() (*http.Client, error)
|
||||
|
||||
Selector string
|
||||
}
|
||||
|
||||
func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Command {
|
||||
opts := DeleteOptions{
|
||||
IO: f.IOStreams,
|
||||
HttpClient: f.HttpClient,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "delete {<gist ID> | <gist URL>}",
|
||||
Short: "Delete a gist",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
opts.Selector = args[0]
|
||||
if runF != nil {
|
||||
return runF(&opts)
|
||||
}
|
||||
return deleteRun(&opts)
|
||||
},
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
apiClient := api.NewClientFromHTTP(client)
|
||||
|
||||
gist, err := shared.GetGist(client, ghinstance.OverridableDefault(), gistID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
username, err := api.CurrentLoginName(apiClient, ghinstance.OverridableDefault())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if username != gist.Owner.Login {
|
||||
return fmt.Errorf("You do not own this gist.")
|
||||
}
|
||||
|
||||
err = deleteGist(apiClient, ghinstance.OverridableDefault(), gistID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteGist(apiClient *api.Client, hostname string, gistID string) error {
|
||||
path := "gists/" + gistID
|
||||
err := apiClient.REST(hostname, "DELETE", path, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
156
pkg/cmd/gist/delete/delete_test.go
Normal file
156
pkg/cmd/gist/delete/delete_test.go
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
package delete
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/cli/cli/pkg/cmd/gist/shared"
|
||||
"github.com/cli/cli/pkg/cmdutil"
|
||||
"github.com/cli/cli/pkg/httpmock"
|
||||
"github.com/cli/cli/pkg/iostreams"
|
||||
"github.com/cli/cli/pkg/prompt"
|
||||
"github.com/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewCmdDelete(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cli string
|
||||
wants DeleteOptions
|
||||
}{
|
||||
{
|
||||
name: "valid selector",
|
||||
cli: "123",
|
||||
wants: DeleteOptions{
|
||||
Selector: "123",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
f := &cmdutil.Factory{}
|
||||
|
||||
argv, err := shlex.Split(tt.cli)
|
||||
assert.NoError(t, err)
|
||||
var gotOpts *DeleteOptions
|
||||
cmd := NewCmdDelete(f, func(opts *DeleteOptions) error {
|
||||
gotOpts = opts
|
||||
return nil
|
||||
})
|
||||
|
||||
cmd.SetArgs(argv)
|
||||
cmd.SetIn(&bytes.Buffer{})
|
||||
cmd.SetOut(&bytes.Buffer{})
|
||||
cmd.SetErr(&bytes.Buffer{})
|
||||
|
||||
_, err = cmd.ExecuteC()
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.wants.Selector, gotOpts.Selector)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_deleteRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
opts *DeleteOptions
|
||||
gist *shared.Gist
|
||||
httpStubs func(*httpmock.Registry)
|
||||
askStubs func(*prompt.AskStubber)
|
||||
nontty bool
|
||||
wantErr bool
|
||||
wantStderr string
|
||||
wantParams map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "no such gist",
|
||||
wantErr: true,
|
||||
}, {
|
||||
name: "another user's gist",
|
||||
gist: &shared.Gist{
|
||||
ID: "1234",
|
||||
Files: map[string]*shared.GistFile{
|
||||
"cicada.txt": {
|
||||
Filename: "cicada.txt",
|
||||
Content: "bwhiizzzbwhuiiizzzz",
|
||||
Type: "text/plain",
|
||||
},
|
||||
},
|
||||
Owner: &shared.GistOwner{Login: "octocat2"},
|
||||
},
|
||||
wantErr: true,
|
||||
wantStderr: "You do not own this gist.",
|
||||
}, {
|
||||
name: "successfully delete",
|
||||
gist: &shared.Gist{
|
||||
ID: "1234",
|
||||
Files: map[string]*shared.GistFile{
|
||||
"cicada.txt": {
|
||||
Filename: "cicada.txt",
|
||||
Content: "bwhiizzzbwhuiiizzzz",
|
||||
Type: "text/plain",
|
||||
},
|
||||
},
|
||||
Owner: &shared.GistOwner{Login: "octocat"},
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(httpmock.REST("DELETE", "gists/1234"),
|
||||
httpmock.StatusStringResponse(200, "{}"))
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
reg := &httpmock.Registry{}
|
||||
if tt.gist == nil {
|
||||
reg.Register(httpmock.REST("GET", "gists/1234"),
|
||||
httpmock.StatusStringResponse(404, "Not Found"))
|
||||
} else {
|
||||
reg.Register(httpmock.REST("GET", "gists/1234"),
|
||||
httpmock.JSONResponse(tt.gist))
|
||||
reg.Register(httpmock.GraphQL(`query UserCurrent\b`),
|
||||
httpmock.StringResponse(`{"data":{"viewer":{"login":"octocat"}}}`))
|
||||
}
|
||||
|
||||
if tt.httpStubs != nil {
|
||||
tt.httpStubs(reg)
|
||||
}
|
||||
|
||||
as, teardown := prompt.InitAskStubber()
|
||||
defer teardown()
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
}
|
||||
|
||||
if tt.opts == nil {
|
||||
tt.opts = &DeleteOptions{}
|
||||
}
|
||||
|
||||
tt.opts.HttpClient = func() (*http.Client, error) {
|
||||
return &http.Client{Transport: reg}, nil
|
||||
}
|
||||
io, _, _, _ := iostreams.Test()
|
||||
io.SetStdoutTTY(!tt.nontty)
|
||||
io.SetStdinTTY(!tt.nontty)
|
||||
tt.opts.IO = io
|
||||
tt.opts.Selector = "1234"
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := deleteRun(tt.opts)
|
||||
reg.Verify(t)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
if tt.wantStderr != "" {
|
||||
assert.EqualError(t, err, tt.wantStderr)
|
||||
}
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package gist
|
|||
import (
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
gistCreateCmd "github.com/cli/cli/pkg/cmd/gist/create"
|
||||
gistDeleteCmd "github.com/cli/cli/pkg/cmd/gist/delete"
|
||||
gistEditCmd "github.com/cli/cli/pkg/cmd/gist/edit"
|
||||
gistListCmd "github.com/cli/cli/pkg/cmd/gist/list"
|
||||
gistViewCmd "github.com/cli/cli/pkg/cmd/gist/view"
|
||||
|
|
@ -29,6 +30,7 @@ func NewCmdGist(f *cmdutil.Factory) *cobra.Command {
|
|||
cmd.AddCommand(gistListCmd.NewCmdList(f, nil))
|
||||
cmd.AddCommand(gistViewCmd.NewCmdView(f, nil))
|
||||
cmd.AddCommand(gistEditCmd.NewCmdEdit(f, nil))
|
||||
cmd.AddCommand(gistDeleteCmd.NewCmdDelete(f, nil))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue