This changes the FetchRelease implementation to look up draft releases directly using by its pending tag name, as opposed to resorting to the Releases list API which is backed by Elastic Search and thus suffers replication lag after the creation of a draft release. Bonus: all release lookup functions now accept a context for cancellation.
227 lines
5.1 KiB
Go
227 lines
5.1 KiB
Go
package delete
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/MakeNowJust/heredoc"
|
|
"github.com/cli/cli/v2/internal/ghrepo"
|
|
"github.com/cli/cli/v2/internal/prompter"
|
|
"github.com/cli/cli/v2/pkg/cmd/release/shared"
|
|
"github.com/cli/cli/v2/pkg/cmdutil"
|
|
"github.com/cli/cli/v2/pkg/httpmock"
|
|
"github.com/cli/cli/v2/pkg/iostreams"
|
|
"github.com/google/shlex"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func Test_NewCmdDelete(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
args string
|
|
isTTY bool
|
|
want DeleteOptions
|
|
wantErr string
|
|
}{
|
|
{
|
|
name: "version argument",
|
|
args: "v1.2.3",
|
|
isTTY: true,
|
|
want: DeleteOptions{
|
|
TagName: "v1.2.3",
|
|
SkipConfirm: false,
|
|
CleanupTag: false,
|
|
},
|
|
},
|
|
{
|
|
name: "skip confirm",
|
|
args: "v1.2.3 -y",
|
|
isTTY: true,
|
|
want: DeleteOptions{
|
|
TagName: "v1.2.3",
|
|
SkipConfirm: true,
|
|
CleanupTag: false,
|
|
},
|
|
},
|
|
{
|
|
name: "cleanup tag",
|
|
args: "v1.2.3 --cleanup-tag",
|
|
isTTY: true,
|
|
want: DeleteOptions{
|
|
TagName: "v1.2.3",
|
|
SkipConfirm: false,
|
|
CleanupTag: true,
|
|
},
|
|
},
|
|
{
|
|
name: "no arguments",
|
|
args: "",
|
|
isTTY: true,
|
|
wantErr: "accepts 1 arg(s), received 0",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ios, _, _, _ := iostreams.Test()
|
|
ios.SetStdoutTTY(tt.isTTY)
|
|
ios.SetStdinTTY(tt.isTTY)
|
|
ios.SetStderrTTY(tt.isTTY)
|
|
|
|
f := &cmdutil.Factory{
|
|
IOStreams: ios,
|
|
}
|
|
|
|
var opts *DeleteOptions
|
|
cmd := NewCmdDelete(f, func(o *DeleteOptions) error {
|
|
opts = o
|
|
return nil
|
|
})
|
|
cmd.PersistentFlags().StringP("repo", "R", "", "")
|
|
|
|
argv, err := shlex.Split(tt.args)
|
|
require.NoError(t, err)
|
|
cmd.SetArgs(argv)
|
|
|
|
cmd.SetIn(&bytes.Buffer{})
|
|
cmd.SetOut(io.Discard)
|
|
cmd.SetErr(io.Discard)
|
|
|
|
_, err = cmd.ExecuteC()
|
|
if tt.wantErr != "" {
|
|
require.EqualError(t, err, tt.wantErr)
|
|
return
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, tt.want.TagName, opts.TagName)
|
|
assert.Equal(t, tt.want.SkipConfirm, opts.SkipConfirm)
|
|
assert.Equal(t, tt.want.CleanupTag, opts.CleanupTag)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_deleteRun(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
isTTY bool
|
|
opts DeleteOptions
|
|
prompterStubs func(*prompter.PrompterMock)
|
|
wantErr string
|
|
wantStdout string
|
|
wantStderr string
|
|
}{
|
|
{
|
|
name: "interactive confirm",
|
|
isTTY: true,
|
|
opts: DeleteOptions{
|
|
TagName: "v1.2.3",
|
|
},
|
|
wantStdout: "",
|
|
wantStderr: "✓ Deleted release v1.2.3\n! Note that the v1.2.3 git tag still remains in the repository\n",
|
|
prompterStubs: func(pm *prompter.PrompterMock) {
|
|
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
|
if p == "Delete release v1.2.3 in OWNER/REPO?" {
|
|
return true, nil
|
|
}
|
|
return false, prompter.NoSuchPromptErr(p)
|
|
}
|
|
},
|
|
},
|
|
{
|
|
name: "skipping confirmation",
|
|
isTTY: true,
|
|
opts: DeleteOptions{
|
|
TagName: "v1.2.3",
|
|
SkipConfirm: true,
|
|
CleanupTag: false,
|
|
},
|
|
wantStdout: ``,
|
|
wantStderr: heredoc.Doc(`
|
|
✓ Deleted release v1.2.3
|
|
! Note that the v1.2.3 git tag still remains in the repository
|
|
`),
|
|
},
|
|
{
|
|
name: "non-interactive",
|
|
isTTY: false,
|
|
opts: DeleteOptions{
|
|
TagName: "v1.2.3",
|
|
SkipConfirm: false,
|
|
CleanupTag: false,
|
|
},
|
|
wantStdout: ``,
|
|
wantStderr: ``,
|
|
},
|
|
{
|
|
name: "cleanup-tag & skipping confirmation",
|
|
isTTY: true,
|
|
opts: DeleteOptions{
|
|
TagName: "v1.2.3",
|
|
SkipConfirm: true,
|
|
CleanupTag: true,
|
|
},
|
|
wantStdout: ``,
|
|
wantStderr: heredoc.Doc(`
|
|
✓ Deleted release and tag v1.2.3
|
|
`),
|
|
},
|
|
{
|
|
name: "cleanup-tag",
|
|
isTTY: false,
|
|
opts: DeleteOptions{
|
|
TagName: "v1.2.3",
|
|
SkipConfirm: false,
|
|
CleanupTag: true,
|
|
},
|
|
wantStdout: ``,
|
|
wantStderr: ``,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ios, _, stdout, stderr := iostreams.Test()
|
|
ios.SetStdoutTTY(tt.isTTY)
|
|
ios.SetStdinTTY(tt.isTTY)
|
|
ios.SetStderrTTY(tt.isTTY)
|
|
|
|
pm := &prompter.PrompterMock{}
|
|
if tt.prompterStubs != nil {
|
|
tt.prompterStubs(pm)
|
|
}
|
|
|
|
fakeHTTP := &httpmock.Registry{}
|
|
shared.StubFetchRelease(t, fakeHTTP, "OWNER", "REPO", tt.opts.TagName, `{
|
|
"tag_name": "v1.2.3",
|
|
"draft": false,
|
|
"url": "https://api.github.com/repos/OWNER/REPO/releases/23456"
|
|
}`)
|
|
|
|
fakeHTTP.Register(httpmock.REST("DELETE", "repos/OWNER/REPO/releases/23456"), httpmock.StatusStringResponse(204, ""))
|
|
fakeHTTP.Register(httpmock.REST("DELETE", "repos/OWNER/REPO/git/refs/tags/v1.2.3"), httpmock.StatusStringResponse(204, ""))
|
|
|
|
tt.opts.IO = ios
|
|
tt.opts.Prompter = pm
|
|
tt.opts.HttpClient = func() (*http.Client, error) {
|
|
return &http.Client{Transport: fakeHTTP}, nil
|
|
}
|
|
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
|
|
return ghrepo.FromFullName("OWNER/REPO")
|
|
}
|
|
|
|
err := deleteRun(&tt.opts)
|
|
if tt.wantErr != "" {
|
|
require.EqualError(t, err, tt.wantErr)
|
|
return
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, tt.wantStdout, stdout.String())
|
|
assert.Equal(t, tt.wantStderr, stderr.String())
|
|
})
|
|
}
|
|
}
|