Merge pull request #7116 from cli/even-more-prompts
New prompt testing utility
This commit is contained in:
commit
661d962112
6 changed files with 451 additions and 298 deletions
|
|
@ -13,7 +13,7 @@ import (
|
|||
//go:generate moq -rm -out prompter_mock.go . Prompter
|
||||
type Prompter interface {
|
||||
Select(string, string, []string) (int, error)
|
||||
MultiSelect(string, string, []string) (int, error)
|
||||
MultiSelect(string, string, []string) ([]string, error)
|
||||
Input(string, string) (string, error)
|
||||
InputHostname() (string, error)
|
||||
Password(string) (string, error)
|
||||
|
|
@ -72,7 +72,7 @@ func (p *surveyPrompter) Select(message, defaultValue string, options []string)
|
|||
return
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) MultiSelect(message, defaultValue string, options []string) (result int, err error) {
|
||||
func (p *surveyPrompter) MultiSelect(message, defaultValue string, options []string) (result []string, err error) {
|
||||
q := &survey.MultiSelect{
|
||||
Message: message,
|
||||
Options: options,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ var _ Prompter = &PrompterMock{}
|
|||
// MarkdownEditorFunc: func(s1 string, s2 string, b bool) (string, error) {
|
||||
// panic("mock out the MarkdownEditor method")
|
||||
// },
|
||||
// MultiSelectFunc: func(s1 string, s2 string, strings []string) (int, error) {
|
||||
// MultiSelectFunc: func(s1 string, s2 string, strings []string) ([]string, error) {
|
||||
// panic("mock out the MultiSelect method")
|
||||
// },
|
||||
// PasswordFunc: func(s string) (string, error) {
|
||||
|
|
@ -70,7 +70,7 @@ type PrompterMock struct {
|
|||
MarkdownEditorFunc func(s1 string, s2 string, b bool) (string, error)
|
||||
|
||||
// MultiSelectFunc mocks the MultiSelect method.
|
||||
MultiSelectFunc func(s1 string, s2 string, strings []string) (int, error)
|
||||
MultiSelectFunc func(s1 string, s2 string, strings []string) ([]string, error)
|
||||
|
||||
// PasswordFunc mocks the Password method.
|
||||
PasswordFunc func(s string) (string, error)
|
||||
|
|
@ -348,7 +348,7 @@ func (mock *PrompterMock) MarkdownEditorCalls() []struct {
|
|||
}
|
||||
|
||||
// MultiSelect calls MultiSelectFunc.
|
||||
func (mock *PrompterMock) MultiSelect(s1 string, s2 string, strings []string) (int, error) {
|
||||
func (mock *PrompterMock) MultiSelect(s1 string, s2 string, strings []string) ([]string, error) {
|
||||
if mock.MultiSelectFunc == nil {
|
||||
panic("PrompterMock.MultiSelectFunc: method is nil but Prompter.MultiSelect was just called")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package prompter
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -29,3 +30,258 @@ func NoSuchAnswerErr(answer string) error {
|
|||
func NoSuchPromptErr(prompt string) error {
|
||||
return fmt.Errorf("no such prompt '%s'", prompt)
|
||||
}
|
||||
|
||||
type SelectStub struct {
|
||||
Prompt string
|
||||
ExpectedOpts []string
|
||||
Fn func(string, string, []string) (int, error)
|
||||
}
|
||||
|
||||
type InputStub struct {
|
||||
Prompt string
|
||||
Fn func(string, string) (string, error)
|
||||
}
|
||||
|
||||
type ConfirmStub struct {
|
||||
Prompt string
|
||||
Fn func(string, bool) (bool, error)
|
||||
}
|
||||
|
||||
type MultiSelectStub struct {
|
||||
Prompt string
|
||||
ExpectedOpts []string
|
||||
Fn func(string, string, []string) ([]string, error)
|
||||
}
|
||||
|
||||
type InputHostnameStub struct {
|
||||
Fn func() (string, error)
|
||||
}
|
||||
|
||||
type PasswordStub struct {
|
||||
Prompt string
|
||||
Fn func(string) (string, error)
|
||||
}
|
||||
|
||||
type AuthTokenStub struct {
|
||||
Fn func() (string, error)
|
||||
}
|
||||
|
||||
type ConfirmDeletionStub struct {
|
||||
Prompt string
|
||||
Fn func(string) error
|
||||
}
|
||||
|
||||
type MockPrompter struct {
|
||||
PrompterMock
|
||||
t *testing.T
|
||||
SelectStubs []SelectStub
|
||||
InputStubs []InputStub
|
||||
ConfirmStubs []ConfirmStub
|
||||
MultiSelectStubs []MultiSelectStub
|
||||
InputHostnameStubs []InputHostnameStub
|
||||
PasswordStubs []PasswordStub
|
||||
AuthTokenStubs []AuthTokenStub
|
||||
ConfirmDeletionStubs []ConfirmDeletionStub
|
||||
}
|
||||
|
||||
// TODO thread safety
|
||||
|
||||
func NewMockPrompter(t *testing.T) *MockPrompter {
|
||||
m := &MockPrompter{
|
||||
t: t,
|
||||
SelectStubs: []SelectStub{},
|
||||
InputStubs: []InputStub{},
|
||||
ConfirmStubs: []ConfirmStub{},
|
||||
MultiSelectStubs: []MultiSelectStub{},
|
||||
InputHostnameStubs: []InputHostnameStub{},
|
||||
PasswordStubs: []PasswordStub{},
|
||||
AuthTokenStubs: []AuthTokenStub{},
|
||||
ConfirmDeletionStubs: []ConfirmDeletionStub{},
|
||||
}
|
||||
|
||||
t.Cleanup(m.Verify)
|
||||
|
||||
m.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
var s SelectStub
|
||||
|
||||
if len(m.SelectStubs) > 0 {
|
||||
s = m.SelectStubs[0]
|
||||
m.SelectStubs = m.SelectStubs[1:len(m.SelectStubs)]
|
||||
} else {
|
||||
return -1, NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
if s.Prompt != p {
|
||||
return -1, NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
AssertOptions(m.t, s.ExpectedOpts, opts)
|
||||
|
||||
return s.Fn(p, d, opts)
|
||||
}
|
||||
|
||||
m.MultiSelectFunc = func(p, d string, opts []string) ([]string, error) {
|
||||
var s MultiSelectStub
|
||||
if len(m.SelectStubs) > 0 {
|
||||
s = m.MultiSelectStubs[0]
|
||||
m.SelectStubs = m.SelectStubs[1:len(m.SelectStubs)]
|
||||
} else {
|
||||
return []string{}, NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
if s.Prompt != p {
|
||||
return []string{}, NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
AssertOptions(m.t, s.ExpectedOpts, opts)
|
||||
|
||||
return s.Fn(p, d, opts)
|
||||
}
|
||||
|
||||
m.InputFunc = func(p, d string) (string, error) {
|
||||
var s InputStub
|
||||
|
||||
if len(m.InputStubs) > 0 {
|
||||
s = m.InputStubs[0]
|
||||
m.InputStubs = m.InputStubs[1:len(m.InputStubs)]
|
||||
} else {
|
||||
return "", NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
if s.Prompt != p {
|
||||
return "", NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
return s.Fn(p, d)
|
||||
}
|
||||
|
||||
m.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
var s ConfirmStub
|
||||
|
||||
if len(m.ConfirmStubs) > 0 {
|
||||
s = m.ConfirmStubs[0]
|
||||
m.ConfirmStubs = m.ConfirmStubs[1:len(m.ConfirmStubs)]
|
||||
} else {
|
||||
return false, NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
if s.Prompt != p {
|
||||
return false, NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
return s.Fn(p, d)
|
||||
}
|
||||
|
||||
m.InputHostnameFunc = func() (string, error) {
|
||||
var s InputHostnameStub
|
||||
|
||||
if len(m.InputHostnameStubs) > 0 {
|
||||
s = m.InputHostnameStubs[0]
|
||||
m.InputHostnameStubs = m.InputHostnameStubs[1:len(m.InputHostnameStubs)]
|
||||
} else {
|
||||
return "", NoSuchPromptErr("InputHostname")
|
||||
}
|
||||
|
||||
return s.Fn()
|
||||
}
|
||||
|
||||
m.PasswordFunc = func(p string) (string, error) {
|
||||
var s PasswordStub
|
||||
|
||||
if len(m.PasswordStubs) > 0 {
|
||||
s = m.PasswordStubs[0]
|
||||
m.PasswordStubs = m.PasswordStubs[1:len(m.PasswordStubs)]
|
||||
} else {
|
||||
return "", NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
if s.Prompt != p {
|
||||
return "", NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
return s.Fn(p)
|
||||
}
|
||||
|
||||
m.AuthTokenFunc = func() (string, error) {
|
||||
var s AuthTokenStub
|
||||
|
||||
if len(m.AuthTokenStubs) > 0 {
|
||||
s = m.AuthTokenStubs[0]
|
||||
m.AuthTokenStubs = m.AuthTokenStubs[1:len(m.AuthTokenStubs)]
|
||||
} else {
|
||||
return "", NoSuchPromptErr("AuthToken")
|
||||
}
|
||||
|
||||
return s.Fn()
|
||||
}
|
||||
|
||||
m.ConfirmDeletionFunc = func(p string) error {
|
||||
var s ConfirmDeletionStub
|
||||
|
||||
if len(m.ConfirmDeletionStubs) > 0 {
|
||||
s = m.ConfirmDeletionStubs[0]
|
||||
m.ConfirmDeletionStubs = m.ConfirmDeletionStubs[1:len(m.ConfirmDeletionStubs)]
|
||||
} else {
|
||||
return NoSuchPromptErr("ConfirmDeletion")
|
||||
}
|
||||
|
||||
return s.Fn(p)
|
||||
}
|
||||
|
||||
// TODO MarkdownEditor(string, string, bool) (string, error)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *MockPrompter) RegisterSelect(prompt string, opts []string, stub func(_, _ string, _ []string) (int, error)) {
|
||||
m.SelectStubs = append(m.SelectStubs, SelectStub{
|
||||
Prompt: prompt,
|
||||
ExpectedOpts: opts,
|
||||
Fn: stub})
|
||||
}
|
||||
|
||||
func (m *MockPrompter) RegisterMultiSelect(prompt string, opts []string, stub func(_, _ string, _ []string) ([]string, error)) {
|
||||
m.MultiSelectStubs = append(m.MultiSelectStubs, MultiSelectStub{
|
||||
Prompt: prompt,
|
||||
ExpectedOpts: opts,
|
||||
Fn: stub})
|
||||
}
|
||||
|
||||
func (m *MockPrompter) RegisterInput(prompt string, stub func(_, _ string) (string, error)) {
|
||||
m.InputStubs = append(m.InputStubs, InputStub{Prompt: prompt, Fn: stub})
|
||||
}
|
||||
|
||||
func (m *MockPrompter) RegisterConfirm(prompt string, stub func(_ string, _ bool) (bool, error)) {
|
||||
m.ConfirmStubs = append(m.ConfirmStubs, ConfirmStub{Prompt: prompt, Fn: stub})
|
||||
}
|
||||
|
||||
func (m *MockPrompter) RegisterInputHostname(stub func() (string, error)) {
|
||||
m.InputHostnameStubs = append(m.InputHostnameStubs, InputHostnameStub{Fn: stub})
|
||||
}
|
||||
|
||||
func (m *MockPrompter) RegisterPassword(prompt string, stub func(string) (string, error)) {
|
||||
m.PasswordStubs = append(m.PasswordStubs, PasswordStub{Fn: stub})
|
||||
}
|
||||
|
||||
func (m *MockPrompter) RegisterConfirmDeletion(prompt string, stub func(string) error) {
|
||||
m.ConfirmDeletionStubs = append(m.ConfirmDeletionStubs, ConfirmDeletionStub{Prompt: prompt, Fn: stub})
|
||||
}
|
||||
|
||||
func (m *MockPrompter) Verify() {
|
||||
errs := []string{}
|
||||
if len(m.SelectStubs) > 0 {
|
||||
errs = append(errs, "Select")
|
||||
}
|
||||
if len(m.InputStubs) > 0 {
|
||||
errs = append(errs, "Input")
|
||||
}
|
||||
if len(m.ConfirmStubs) > 0 {
|
||||
errs = append(errs, "Confirm")
|
||||
}
|
||||
// TODO other prompt types
|
||||
|
||||
if len(errs) > 0 {
|
||||
m.t.Helper()
|
||||
m.t.Errorf("%d unmatched calls to %s", len(errs), strings.Join(errs, ","))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -926,7 +926,7 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
httpStubs func(*httpmock.Registry)
|
||||
prompterStubs func(*testing.T, *prompter.PrompterMock)
|
||||
prompterStubs func(*testing.T, *prompter.MockPrompter)
|
||||
runStubs func(*run.CommandStubber)
|
||||
opts *CreateOptions
|
||||
wantParams map[string]interface{}
|
||||
|
|
@ -936,37 +936,28 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
{
|
||||
name: "create a release from existing tag",
|
||||
opts: &CreateOptions{},
|
||||
prompterStubs: func(t *testing.T, pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
switch p {
|
||||
case "Choose a tag":
|
||||
prompter.AssertOptions(t, []string{"v1.2.3", "v1.2.2", "v1.0.0", "v0.1.2", "Create a new tag"}, opts)
|
||||
prompterStubs: func(t *testing.T, pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Choose a tag",
|
||||
[]string{"v1.2.3", "v1.2.2", "v1.0.0", "v0.1.2", "Create a new tag"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "v1.2.3")
|
||||
case "Release notes":
|
||||
prompter.AssertOptions(t, []string{"Write my own", "Write using generated notes as template", "Leave blank"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Release notes",
|
||||
[]string{"Write my own", "Write using generated notes as template", "Leave blank"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Leave blank")
|
||||
case "Submit?":
|
||||
prompter.AssertOptions(t, []string{"Publish release", "Save as draft", "Cancel"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Submit?",
|
||||
[]string{"Publish release", "Save as draft", "Cancel"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Publish release")
|
||||
default:
|
||||
return -1, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.InputFunc = func(p, d string) (string, error) {
|
||||
if p == "Title (optional)" {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
return "", prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
switch p {
|
||||
case "Is this a prerelease?":
|
||||
return false, nil
|
||||
default:
|
||||
return false, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
})
|
||||
pm.RegisterInput("Title (optional)", func(_, d string) (string, error) {
|
||||
return d, nil
|
||||
})
|
||||
pm.RegisterConfirm("Is this a prerelease?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git tag --list`, 1, "")
|
||||
|
|
@ -991,40 +982,31 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
{
|
||||
name: "create a release from new tag",
|
||||
opts: &CreateOptions{},
|
||||
prompterStubs: func(t *testing.T, pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
switch p {
|
||||
case "Choose a tag":
|
||||
prompter.AssertOptions(t, []string{"v1.2.2", "v1.0.0", "v0.1.2", "Create a new tag"}, opts)
|
||||
prompterStubs: func(t *testing.T, pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Choose a tag",
|
||||
[]string{"v1.2.2", "v1.0.0", "v0.1.2", "Create a new tag"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Create a new tag")
|
||||
case "Release notes":
|
||||
prompter.AssertOptions(t, []string{"Write my own", "Write using generated notes as template", "Leave blank"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Release notes",
|
||||
[]string{"Write my own", "Write using generated notes as template", "Leave blank"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Leave blank")
|
||||
case "Submit?":
|
||||
prompter.AssertOptions(t, []string{"Publish release", "Save as draft", "Cancel"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Submit?",
|
||||
[]string{"Publish release", "Save as draft", "Cancel"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Publish release")
|
||||
default:
|
||||
return -1, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.InputFunc = func(p, d string) (string, error) {
|
||||
switch p {
|
||||
case "Tag name":
|
||||
return "v1.2.3", nil
|
||||
case "Title (optional)":
|
||||
return d, nil
|
||||
default:
|
||||
return "", prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
switch p {
|
||||
case "Is this a prerelease?":
|
||||
return false, nil
|
||||
default:
|
||||
return false, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
})
|
||||
pm.RegisterInput("Tag name", func(_, d string) (string, error) {
|
||||
return "v1.2.3", nil
|
||||
})
|
||||
pm.RegisterInput("Title (optional)", func(_, d string) (string, error) {
|
||||
return d, nil
|
||||
})
|
||||
pm.RegisterConfirm("Is this a prerelease?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git tag --list`, 1, "")
|
||||
|
|
@ -1051,35 +1033,23 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
opts: &CreateOptions{
|
||||
TagName: "v1.2.3",
|
||||
},
|
||||
prompterStubs: func(t *testing.T, pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
switch p {
|
||||
case "Release notes":
|
||||
prompter.AssertOptions(t, []string{"Write my own", "Write using generated notes as template", "Leave blank"}, opts)
|
||||
prompterStubs: func(t *testing.T, pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Release notes",
|
||||
[]string{"Write my own", "Write using generated notes as template", "Leave blank"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Write using generated notes as template")
|
||||
case "Submit?":
|
||||
prompter.AssertOptions(t, []string{"Publish release", "Save as draft", "Cancel"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Submit?",
|
||||
[]string{"Publish release", "Save as draft", "Cancel"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Publish release")
|
||||
default:
|
||||
return -1, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.InputFunc = func(p, d string) (string, error) {
|
||||
switch p {
|
||||
case "Title (optional)":
|
||||
return d, nil
|
||||
default:
|
||||
return "", prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
switch p {
|
||||
case "Is this a prerelease?":
|
||||
return false, nil
|
||||
default:
|
||||
return false, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
})
|
||||
pm.RegisterInput("Title (optional)", func(_, d string) (string, error) {
|
||||
return d, nil
|
||||
})
|
||||
pm.RegisterConfirm("Is this a prerelease?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git tag --list`, 1, "")
|
||||
|
|
@ -1111,35 +1081,23 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
opts: &CreateOptions{
|
||||
TagName: "v1.2.3",
|
||||
},
|
||||
prompterStubs: func(t *testing.T, pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
switch p {
|
||||
case "Release notes":
|
||||
prompter.AssertOptions(t, []string{"Write my own", "Write using commit log as template", "Leave blank"}, opts)
|
||||
prompterStubs: func(t *testing.T, pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Release notes",
|
||||
[]string{"Write my own", "Write using commit log as template", "Leave blank"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Write using commit log as template")
|
||||
case "Submit?":
|
||||
prompter.AssertOptions(t, []string{"Publish release", "Save as draft", "Cancel"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Submit?",
|
||||
[]string{"Publish release", "Save as draft", "Cancel"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Publish release")
|
||||
default:
|
||||
return -1, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.InputFunc = func(p, d string) (string, error) {
|
||||
switch p {
|
||||
case "Title (optional)":
|
||||
return d, nil
|
||||
default:
|
||||
return "", prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
switch p {
|
||||
case "Is this a prerelease?":
|
||||
return false, nil
|
||||
default:
|
||||
return false, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
})
|
||||
pm.RegisterInput("Title (optional)", func(_, d string) (string, error) {
|
||||
return d, nil
|
||||
})
|
||||
pm.RegisterConfirm("Is this a prerelease?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git tag --list`, 1, "")
|
||||
|
|
@ -1169,35 +1127,23 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
opts: &CreateOptions{
|
||||
TagName: "v1.2.3",
|
||||
},
|
||||
prompterStubs: func(t *testing.T, pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
switch p {
|
||||
case "Release notes":
|
||||
prompter.AssertOptions(t, []string{"Write my own", "Write using git tag message as template", "Leave blank"}, opts)
|
||||
prompterStubs: func(t *testing.T, pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Release notes",
|
||||
[]string{"Write my own", "Write using git tag message as template", "Leave blank"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Write using git tag message as template")
|
||||
case "Submit?":
|
||||
prompter.AssertOptions(t, []string{"Publish release", "Save as draft", "Cancel"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Submit?",
|
||||
[]string{"Publish release", "Save as draft", "Cancel"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Publish release")
|
||||
default:
|
||||
return -1, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.InputFunc = func(p, d string) (string, error) {
|
||||
switch p {
|
||||
case "Title (optional)":
|
||||
return d, nil
|
||||
default:
|
||||
return "", prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
switch p {
|
||||
case "Is this a prerelease?":
|
||||
return false, nil
|
||||
default:
|
||||
return false, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
})
|
||||
pm.RegisterInput("Title (optional)", func(_, d string) (string, error) {
|
||||
return d, nil
|
||||
})
|
||||
pm.RegisterConfirm("Is this a prerelease?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git tag --list`, 0, "hello from annotated tag")
|
||||
|
|
@ -1243,35 +1189,23 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
TagName: "v1.2.3",
|
||||
Target: "main",
|
||||
},
|
||||
prompterStubs: func(t *testing.T, pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
switch p {
|
||||
case "Release notes":
|
||||
prompter.AssertOptions(t, []string{"Write my own", "Write using generated notes as template", "Write using git tag message as template", "Leave blank"}, opts)
|
||||
prompterStubs: func(t *testing.T, pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Release notes",
|
||||
[]string{"Write my own", "Write using generated notes as template", "Write using git tag message as template", "Leave blank"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Leave blank")
|
||||
case "Submit?":
|
||||
prompter.AssertOptions(t, []string{"Publish release", "Save as draft", "Cancel"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Submit?",
|
||||
[]string{"Publish release", "Save as draft", "Cancel"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Publish release")
|
||||
default:
|
||||
return -1, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.InputFunc = func(p, d string) (string, error) {
|
||||
switch p {
|
||||
case "Title (optional)":
|
||||
return d, nil
|
||||
default:
|
||||
return "", prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
switch p {
|
||||
case "Is this a prerelease?":
|
||||
return false, nil
|
||||
default:
|
||||
return false, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
})
|
||||
pm.RegisterInput("Title (optional)", func(_, d string) (string, error) {
|
||||
return d, nil
|
||||
})
|
||||
pm.RegisterConfirm("Is this a prerelease?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git tag --list`, 0, "tag exists")
|
||||
|
|
@ -1303,35 +1237,23 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
TagName: "v1.2.3",
|
||||
NotesStartTag: "v1.1.0",
|
||||
},
|
||||
prompterStubs: func(t *testing.T, pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
switch p {
|
||||
case "Release notes":
|
||||
prompter.AssertOptions(t, []string{"Write my own", "Write using generated notes as template", "Leave blank"}, opts)
|
||||
prompterStubs: func(t *testing.T, pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Release notes",
|
||||
[]string{"Write my own", "Write using generated notes as template", "Leave blank"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Write using generated notes as template")
|
||||
case "Submit?":
|
||||
prompter.AssertOptions(t, []string{"Publish release", "Save as draft", "Cancel"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Submit?",
|
||||
[]string{"Publish release", "Save as draft", "Cancel"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Publish release")
|
||||
default:
|
||||
return -1, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.InputFunc = func(p, d string) (string, error) {
|
||||
switch p {
|
||||
case "Title (optional)":
|
||||
return d, nil
|
||||
default:
|
||||
return "", prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
switch p {
|
||||
case "Is this a prerelease?":
|
||||
return false, nil
|
||||
default:
|
||||
return false, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
})
|
||||
pm.RegisterInput("Title (optional)", func(_, d string) (string, error) {
|
||||
return d, nil
|
||||
})
|
||||
pm.RegisterConfirm("Is this a prerelease?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git tag --list`, 1, "")
|
||||
|
|
@ -1369,35 +1291,23 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
TagName: "v1.2.3",
|
||||
NotesStartTag: "v1.1.0",
|
||||
},
|
||||
prompterStubs: func(t *testing.T, pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
switch p {
|
||||
case "Release notes":
|
||||
prompter.AssertOptions(t, []string{"Write my own", "Write using commit log as template", "Leave blank"}, opts)
|
||||
prompterStubs: func(t *testing.T, pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Release notes",
|
||||
[]string{"Write my own", "Write using commit log as template", "Leave blank"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Write using commit log as template")
|
||||
case "Submit?":
|
||||
prompter.AssertOptions(t, []string{"Publish release", "Save as draft", "Cancel"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Submit?",
|
||||
[]string{"Publish release", "Save as draft", "Cancel"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Publish release")
|
||||
default:
|
||||
return -1, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.InputFunc = func(p, d string) (string, error) {
|
||||
switch p {
|
||||
case "Title (optional)":
|
||||
return d, nil
|
||||
default:
|
||||
return "", prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
switch p {
|
||||
case "Is this a prerelease?":
|
||||
return false, nil
|
||||
default:
|
||||
return false, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
})
|
||||
pm.RegisterInput("Title (optional)", func(_, d string) (string, error) {
|
||||
return d, nil
|
||||
})
|
||||
pm.RegisterConfirm("Is this a prerelease?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git tag --list`, 1, "")
|
||||
|
|
@ -1427,35 +1337,25 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
TagName: "v1.2.3",
|
||||
VerifyTag: true,
|
||||
},
|
||||
prompterStubs: func(t *testing.T, pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(p, d string, opts []string) (int, error) {
|
||||
switch p {
|
||||
case "Release notes":
|
||||
prompter.AssertOptions(t, []string{"Write my own", "Write using generated notes as template", "Write using git tag message as template", "Leave blank"}, opts)
|
||||
prompterStubs: func(t *testing.T, pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Release notes",
|
||||
[]string{"Write my own", "Write using generated notes as template", "Write using git tag message as template", "Leave blank"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Leave blank")
|
||||
case "Submit?":
|
||||
prompter.AssertOptions(t, []string{"Publish release", "Save as draft", "Cancel"}, opts)
|
||||
})
|
||||
pm.RegisterSelect("Submit?",
|
||||
[]string{"Publish release", "Save as draft", "Cancel"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Publish release")
|
||||
default:
|
||||
return -1, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.InputFunc = func(p, d string) (string, error) {
|
||||
switch p {
|
||||
case "Title (optional)":
|
||||
return d, nil
|
||||
default:
|
||||
return "", prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
pm.ConfirmFunc = func(p string, d bool) (bool, error) {
|
||||
switch p {
|
||||
case "Is this a prerelease?":
|
||||
return false, nil
|
||||
default:
|
||||
return false, prompter.NoSuchPromptErr(p)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
pm.RegisterInput("Title (optional)", func(_, d string) (string, error) {
|
||||
return d, nil
|
||||
})
|
||||
|
||||
pm.RegisterConfirm("Is this a prerelease?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git tag --list`, 0, "tag exists")
|
||||
|
|
@ -1524,7 +1424,7 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
tt.opts.GitClient = &git.Client{GitPath: "some/path/git"}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
pm := &prompter.PrompterMock{}
|
||||
pm := prompter.NewMockPrompter(t)
|
||||
if tt.prompterStubs != nil {
|
||||
tt.prompterStubs(t, pm)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/api"
|
||||
ghContext "github.com/cli/cli/v2/context"
|
||||
|
|
@ -14,14 +13,19 @@ import (
|
|||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type iprompter interface {
|
||||
Input(string, string) (string, error)
|
||||
Confirm(string, bool) (bool, error)
|
||||
}
|
||||
|
||||
type RenameOptions struct {
|
||||
HttpClient func() (*http.Client, error)
|
||||
GitClient *git.Client
|
||||
IO *iostreams.IOStreams
|
||||
Prompter iprompter
|
||||
Config func() (config.Config, error)
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
Remotes func() (ghContext.Remotes, error)
|
||||
|
|
@ -37,6 +41,7 @@ func NewCmdRename(f *cmdutil.Factory, runf func(*RenameOptions) error) *cobra.Co
|
|||
GitClient: f.GitClient,
|
||||
Remotes: f.Remotes,
|
||||
Config: f.Config,
|
||||
Prompter: f.Prompter,
|
||||
}
|
||||
|
||||
var confirm bool
|
||||
|
|
@ -95,28 +100,17 @@ func renameRun(opts *RenameOptions) error {
|
|||
}
|
||||
|
||||
if newRepoName == "" {
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(
|
||||
&survey.Input{
|
||||
Message: fmt.Sprintf("Rename %s to: ", ghrepo.FullName(currRepo)),
|
||||
},
|
||||
&newRepoName,
|
||||
)
|
||||
if err != nil {
|
||||
if newRepoName, err = opts.Prompter.Input(fmt.Sprintf(
|
||||
"Rename %s to:", ghrepo.FullName(currRepo)), ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if opts.DoConfirm {
|
||||
var confirmed bool
|
||||
p := &survey.Confirm{
|
||||
Message: fmt.Sprintf("Rename %s to %s?", ghrepo.FullName(currRepo), newRepoName),
|
||||
Default: false,
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(p, &confirmed)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prompt: %w", err)
|
||||
if confirmed, err = opts.Prompter.Confirm(fmt.Sprintf(
|
||||
"Rename %s to %s?", ghrepo.FullName(currRepo), newRepoName), false); err != nil {
|
||||
return err
|
||||
}
|
||||
if !confirmed {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ import (
|
|||
"github.com/cli/cli/v2/git"
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/internal/run"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/httpmock"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
"github.com/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -105,20 +105,21 @@ func TestNewCmdRename(t *testing.T) {
|
|||
|
||||
func TestRenameRun(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
opts RenameOptions
|
||||
httpStubs func(*httpmock.Registry)
|
||||
execStubs func(*run.CommandStubber)
|
||||
askStubs func(*prompt.AskStubber)
|
||||
wantOut string
|
||||
tty bool
|
||||
name string
|
||||
opts RenameOptions
|
||||
httpStubs func(*httpmock.Registry)
|
||||
execStubs func(*run.CommandStubber)
|
||||
promptStubs func(*prompter.MockPrompter)
|
||||
wantOut string
|
||||
tty bool
|
||||
}{
|
||||
{
|
||||
name: "none argument",
|
||||
wantOut: "✓ Renamed repository OWNER/NEW_REPO\n✓ Updated the \"origin\" remote\n",
|
||||
askStubs: func(q *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt
|
||||
q.StubOne("NEW_REPO")
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterInput("Rename OWNER/REPO to:", func(_, _ string) (string, error) {
|
||||
return "NEW_REPO", nil
|
||||
})
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
|
|
@ -136,9 +137,10 @@ func TestRenameRun(t *testing.T) {
|
|||
HasRepoOverride: true,
|
||||
},
|
||||
wantOut: "✓ Renamed repository OWNER/NEW_REPO\n",
|
||||
askStubs: func(q *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt
|
||||
q.StubOne("NEW_REPO")
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterInput("Rename OWNER/REPO to:", func(_, _ string) (string, error) {
|
||||
return "NEW_REPO", nil
|
||||
})
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
|
|
@ -185,9 +187,10 @@ func TestRenameRun(t *testing.T) {
|
|||
DoConfirm: true,
|
||||
},
|
||||
wantOut: "✓ Renamed repository OWNER/NEW_REPO\n✓ Updated the \"origin\" remote\n",
|
||||
askStubs: func(q *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt
|
||||
q.StubOne(true)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterConfirm("Rename OWNER/REPO to NEW_REPO?", func(_ string, _ bool) (bool, error) {
|
||||
return true, nil
|
||||
})
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
|
|
@ -206,20 +209,20 @@ func TestRenameRun(t *testing.T) {
|
|||
newRepoSelector: "NEW_REPO",
|
||||
DoConfirm: true,
|
||||
},
|
||||
askStubs: func(q *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt
|
||||
q.StubOne(false)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterConfirm("Rename OWNER/REPO to NEW_REPO?", func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
})
|
||||
},
|
||||
wantOut: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
|
||||
q, teardown := prompt.InitAskStubber()
|
||||
defer teardown()
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(q)
|
||||
pm := prompter.NewMockPrompter(t)
|
||||
tt.opts.Prompter = pm
|
||||
if tt.promptStubs != nil {
|
||||
tt.promptStubs(pm)
|
||||
}
|
||||
|
||||
repo, _ := ghrepo.FromFullName("OWNER/REPO")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue