Merge pull request #5510 from cli/gist-delete-check
Avoid crash when deleting gist with no owner
This commit is contained in:
commit
adc9abd5ee
2 changed files with 36 additions and 72 deletions
|
|
@ -2,6 +2,7 @@ package delete
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
|
@ -58,8 +59,6 @@ func deleteRun(opts *DeleteOptions) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
apiClient := api.NewClientFromHTTP(client)
|
|
||||||
|
|
||||||
cfg, err := opts.Config()
|
cfg, err := opts.Config()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -70,21 +69,11 @@ func deleteRun(opts *DeleteOptions) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
gist, err := shared.GetGist(client, host, gistID)
|
apiClient := api.NewClientFromHTTP(client)
|
||||||
if err != nil {
|
if err := deleteGist(apiClient, host, gistID); err != nil {
|
||||||
return err
|
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)
|
||||||
username, err := api.CurrentLoginName(apiClient, host)
|
}
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if username != gist.Owner.Login {
|
|
||||||
return errors.New("you do not own this gist")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = deleteGist(apiClient, host, gistID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -95,6 +84,10 @@ func deleteGist(apiClient *api.Client, hostname string, gistID string) error {
|
||||||
path := "gists/" + gistID
|
path := "gists/" + gistID
|
||||||
err := apiClient.REST(hostname, "DELETE", path, nil, nil)
|
err := apiClient.REST(hostname, "DELETE", path, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var httpErr api.HTTPError
|
||||||
|
if errors.As(err, &httpErr) && httpErr.StatusCode == 404 {
|
||||||
|
return shared.NotFoundErr
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/cli/cli/v2/internal/config"
|
"github.com/cli/cli/v2/internal/config"
|
||||||
"github.com/cli/cli/v2/pkg/cmd/gist/shared"
|
|
||||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||||
"github.com/cli/cli/v2/pkg/httpmock"
|
"github.com/cli/cli/v2/pkg/httpmock"
|
||||||
"github.com/cli/cli/v2/pkg/iostreams"
|
"github.com/cli/cli/v2/pkg/iostreams"
|
||||||
|
|
@ -57,87 +56,59 @@ func TestNewCmdDelete(t *testing.T) {
|
||||||
func Test_deleteRun(t *testing.T) {
|
func Test_deleteRun(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
opts *DeleteOptions
|
opts DeleteOptions
|
||||||
gist *shared.Gist
|
|
||||||
httpStubs func(*httpmock.Registry)
|
httpStubs func(*httpmock.Registry)
|
||||||
nontty bool
|
|
||||||
wantErr bool
|
wantErr bool
|
||||||
|
wantStdout string
|
||||||
wantStderr string
|
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",
|
name: "successfully delete",
|
||||||
gist: &shared.Gist{
|
opts: DeleteOptions{
|
||||||
ID: "1234",
|
Selector: "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) {
|
httpStubs: func(reg *httpmock.Registry) {
|
||||||
reg.Register(httpmock.REST("DELETE", "gists/1234"),
|
reg.Register(httpmock.REST("DELETE", "gists/1234"),
|
||||||
httpmock.StringResponse("{}"))
|
httpmock.StatusStringResponse(200, "{}"))
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
|
wantStdout: "",
|
||||||
|
wantStderr: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not found",
|
||||||
|
opts: DeleteOptions{
|
||||||
|
Selector: "1234",
|
||||||
|
},
|
||||||
|
httpStubs: func(reg *httpmock.Registry) {
|
||||||
|
reg.Register(httpmock.REST("DELETE", "gists/1234"),
|
||||||
|
httpmock.StatusStringResponse(404, "{}"))
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
wantStdout: "",
|
||||||
|
wantStderr: "",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
reg := &httpmock.Registry{}
|
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 {
|
if tt.httpStubs != nil {
|
||||||
tt.httpStubs(reg)
|
tt.httpStubs(reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.opts == nil {
|
|
||||||
tt.opts = &DeleteOptions{}
|
|
||||||
}
|
|
||||||
|
|
||||||
tt.opts.HttpClient = func() (*http.Client, error) {
|
tt.opts.HttpClient = func() (*http.Client, error) {
|
||||||
return &http.Client{Transport: reg}, nil
|
return &http.Client{Transport: reg}, nil
|
||||||
}
|
}
|
||||||
tt.opts.Config = func() (config.Config, error) {
|
tt.opts.Config = func() (config.Config, error) {
|
||||||
return config.NewBlankConfig(), nil
|
return config.NewBlankConfig(), nil
|
||||||
}
|
}
|
||||||
io, _, _, _ := iostreams.Test()
|
ios, _, _, _ := iostreams.Test()
|
||||||
io.SetStdoutTTY(!tt.nontty)
|
ios.SetStdoutTTY(false)
|
||||||
io.SetStdinTTY(!tt.nontty)
|
ios.SetStdinTTY(false)
|
||||||
tt.opts.IO = io
|
tt.opts.IO = ios
|
||||||
tt.opts.Selector = "1234"
|
|
||||||
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
err := deleteRun(tt.opts)
|
err := deleteRun(&tt.opts)
|
||||||
reg.Verify(t)
|
reg.Verify(t)
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue