commit
5ab5b45d2b
61 changed files with 936 additions and 349 deletions
|
|
@ -119,6 +119,7 @@ func (r *ResolvedRemotes) BaseRepo(io *iostreams.IOStreams) (ghrepo.Interface, e
|
|||
// hide the spinner in case a command started the progress indicator before base repo was fully
|
||||
// resolved, e.g. in `gh issue view`
|
||||
io.StopProgressIndicator()
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "Which should be the base repository (used for e.g. querying issues) for this directory?",
|
||||
Options: repoNames,
|
||||
|
|
|
|||
|
|
@ -36,12 +36,7 @@ func NormalizeHostname(h string) string {
|
|||
return hostname
|
||||
}
|
||||
|
||||
func HostnameValidator(v interface{}) error {
|
||||
hostname, valid := v.(string)
|
||||
if !valid {
|
||||
return errors.New("hostname is not a string")
|
||||
}
|
||||
|
||||
func HostnameValidator(hostname string) error {
|
||||
if len(strings.TrimSpace(hostname)) < 1 {
|
||||
return errors.New("a value is required")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func TestNormalizeHostname(t *testing.T) {
|
|||
func TestHostnameValidator(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input interface{}
|
||||
input string
|
||||
wantsErr bool
|
||||
}{
|
||||
{
|
||||
|
|
@ -118,11 +118,6 @@ func TestHostnameValidator(t *testing.T) {
|
|||
input: "internal.instance:2205",
|
||||
wantsErr: true,
|
||||
},
|
||||
{
|
||||
name: "non-string hostname",
|
||||
input: 62,
|
||||
wantsErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
|
|
|||
135
internal/prompter/prompter.go
Normal file
135
internal/prompter/prompter.go
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
package prompter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
"github.com/cli/cli/v2/pkg/surveyext"
|
||||
)
|
||||
|
||||
//go:generate moq -rm -out prompter_mock.go . Prompter
|
||||
type Prompter interface {
|
||||
Select(string, string, []string) (int, error)
|
||||
MultiSelect(string, string, []string) (int, error)
|
||||
Input(string, string) (string, error)
|
||||
InputHostname() (string, error)
|
||||
Password(string) (string, error)
|
||||
AuthToken() (string, error)
|
||||
Confirm(string, bool) (bool, error)
|
||||
MarkdownEditor(string, string, bool) (string, error)
|
||||
}
|
||||
|
||||
func New(editorCmd string, stdin io.Reader, stdout, stderr io.Writer) Prompter {
|
||||
return &surveyPrompter{
|
||||
editorCmd: editorCmd,
|
||||
stdin: stdin.(terminal.FileReader),
|
||||
stdout: stdout.(terminal.FileWriter),
|
||||
stderr: stderr,
|
||||
}
|
||||
}
|
||||
|
||||
type surveyPrompter struct {
|
||||
editorCmd string
|
||||
stdin terminal.FileReader
|
||||
stdout terminal.FileWriter
|
||||
stderr io.Writer
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) Select(message, defaultValue string, options []string) (result int, err error) {
|
||||
q := &survey.Select{
|
||||
Message: message,
|
||||
Default: defaultValue,
|
||||
Options: options,
|
||||
PageSize: 20,
|
||||
}
|
||||
|
||||
err = p.ask(q, &result)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) MultiSelect(message, defaultValue string, options []string) (result int, err error) {
|
||||
q := &survey.MultiSelect{
|
||||
Message: message,
|
||||
Default: defaultValue,
|
||||
Options: options,
|
||||
PageSize: 20,
|
||||
}
|
||||
|
||||
err = p.ask(q, &result)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) ask(q survey.Prompt, response interface{}, opts ...survey.AskOpt) error {
|
||||
opts = append(opts, survey.WithStdio(p.stdin, p.stdout, p.stderr))
|
||||
err := survey.AskOne(q, response, opts...)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) Input(prompt, defaultValue string) (result string, err error) {
|
||||
err = p.ask(&survey.Input{
|
||||
Message: prompt,
|
||||
Default: defaultValue,
|
||||
}, &result)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) InputHostname() (result string, err error) {
|
||||
err = p.ask(
|
||||
&survey.Input{
|
||||
Message: "GHE hostname:",
|
||||
}, &result, survey.WithValidator(func(v interface{}) error {
|
||||
return ghinstance.HostnameValidator(v.(string))
|
||||
}))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) Password(prompt string) (result string, err error) {
|
||||
err = p.ask(&survey.Password{
|
||||
Message: prompt,
|
||||
}, &result)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) Confirm(prompt string, defaultValue bool) (result bool, err error) {
|
||||
err = p.ask(&survey.Confirm{
|
||||
Message: prompt,
|
||||
Default: defaultValue,
|
||||
}, &result)
|
||||
|
||||
return
|
||||
}
|
||||
func (p *surveyPrompter) MarkdownEditor(message, defaultValue string, blankAllowed bool) (result string, err error) {
|
||||
|
||||
err = p.ask(&surveyext.GhEditor{
|
||||
BlankAllowed: blankAllowed,
|
||||
EditorCommand: p.editorCmd,
|
||||
Editor: &survey.Editor{
|
||||
Message: message,
|
||||
Default: defaultValue,
|
||||
FileName: "*.md",
|
||||
HideDefault: true,
|
||||
AppendDefault: true,
|
||||
},
|
||||
}, &result)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) AuthToken() (result string, err error) {
|
||||
err = p.ask(&survey.Password{
|
||||
Message: "Paste your authentication token:",
|
||||
}, &result, survey.WithValidator(survey.Required))
|
||||
|
||||
return
|
||||
}
|
||||
408
internal/prompter/prompter_mock.go
Normal file
408
internal/prompter/prompter_mock.go
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
// Code generated by moq; DO NOT EDIT.
|
||||
// github.com/matryer/moq
|
||||
|
||||
package prompter
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Ensure, that PrompterMock does implement Prompter.
|
||||
// If this is not the case, regenerate this file with moq.
|
||||
var _ Prompter = &PrompterMock{}
|
||||
|
||||
// PrompterMock is a mock implementation of Prompter.
|
||||
//
|
||||
// func TestSomethingThatUsesPrompter(t *testing.T) {
|
||||
//
|
||||
// // make and configure a mocked Prompter
|
||||
// mockedPrompter := &PrompterMock{
|
||||
// AuthTokenFunc: func() (string, error) {
|
||||
// panic("mock out the AuthToken method")
|
||||
// },
|
||||
// ConfirmFunc: func(s string, b bool) (bool, error) {
|
||||
// panic("mock out the Confirm method")
|
||||
// },
|
||||
// InputFunc: func(s1 string, s2 string) (string, error) {
|
||||
// panic("mock out the Input method")
|
||||
// },
|
||||
// InputHostnameFunc: func() (string, error) {
|
||||
// panic("mock out the InputHostname method")
|
||||
// },
|
||||
// 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) {
|
||||
// panic("mock out the MultiSelect method")
|
||||
// },
|
||||
// PasswordFunc: func(s string) (string, error) {
|
||||
// panic("mock out the Password method")
|
||||
// },
|
||||
// SelectFunc: func(s1 string, s2 string, strings []string) (int, error) {
|
||||
// panic("mock out the Select method")
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // use mockedPrompter in code that requires Prompter
|
||||
// // and then make assertions.
|
||||
//
|
||||
// }
|
||||
type PrompterMock struct {
|
||||
// AuthTokenFunc mocks the AuthToken method.
|
||||
AuthTokenFunc func() (string, error)
|
||||
|
||||
// ConfirmFunc mocks the Confirm method.
|
||||
ConfirmFunc func(s string, b bool) (bool, error)
|
||||
|
||||
// InputFunc mocks the Input method.
|
||||
InputFunc func(s1 string, s2 string) (string, error)
|
||||
|
||||
// InputHostnameFunc mocks the InputHostname method.
|
||||
InputHostnameFunc func() (string, error)
|
||||
|
||||
// MarkdownEditorFunc mocks the MarkdownEditor method.
|
||||
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)
|
||||
|
||||
// PasswordFunc mocks the Password method.
|
||||
PasswordFunc func(s string) (string, error)
|
||||
|
||||
// SelectFunc mocks the Select method.
|
||||
SelectFunc func(s1 string, s2 string, strings []string) (int, error)
|
||||
|
||||
// calls tracks calls to the methods.
|
||||
calls struct {
|
||||
// AuthToken holds details about calls to the AuthToken method.
|
||||
AuthToken []struct {
|
||||
}
|
||||
// Confirm holds details about calls to the Confirm method.
|
||||
Confirm []struct {
|
||||
// S is the s argument value.
|
||||
S string
|
||||
// B is the b argument value.
|
||||
B bool
|
||||
}
|
||||
// Input holds details about calls to the Input method.
|
||||
Input []struct {
|
||||
// S1 is the s1 argument value.
|
||||
S1 string
|
||||
// S2 is the s2 argument value.
|
||||
S2 string
|
||||
}
|
||||
// InputHostname holds details about calls to the InputHostname method.
|
||||
InputHostname []struct {
|
||||
}
|
||||
// MarkdownEditor holds details about calls to the MarkdownEditor method.
|
||||
MarkdownEditor []struct {
|
||||
// S1 is the s1 argument value.
|
||||
S1 string
|
||||
// S2 is the s2 argument value.
|
||||
S2 string
|
||||
// B is the b argument value.
|
||||
B bool
|
||||
}
|
||||
// MultiSelect holds details about calls to the MultiSelect method.
|
||||
MultiSelect []struct {
|
||||
// S1 is the s1 argument value.
|
||||
S1 string
|
||||
// S2 is the s2 argument value.
|
||||
S2 string
|
||||
// Strings is the strings argument value.
|
||||
Strings []string
|
||||
}
|
||||
// Password holds details about calls to the Password method.
|
||||
Password []struct {
|
||||
// S is the s argument value.
|
||||
S string
|
||||
}
|
||||
// Select holds details about calls to the Select method.
|
||||
Select []struct {
|
||||
// S1 is the s1 argument value.
|
||||
S1 string
|
||||
// S2 is the s2 argument value.
|
||||
S2 string
|
||||
// Strings is the strings argument value.
|
||||
Strings []string
|
||||
}
|
||||
}
|
||||
lockAuthToken sync.RWMutex
|
||||
lockConfirm sync.RWMutex
|
||||
lockInput sync.RWMutex
|
||||
lockInputHostname sync.RWMutex
|
||||
lockMarkdownEditor sync.RWMutex
|
||||
lockMultiSelect sync.RWMutex
|
||||
lockPassword sync.RWMutex
|
||||
lockSelect sync.RWMutex
|
||||
}
|
||||
|
||||
// AuthToken calls AuthTokenFunc.
|
||||
func (mock *PrompterMock) AuthToken() (string, error) {
|
||||
if mock.AuthTokenFunc == nil {
|
||||
panic("PrompterMock.AuthTokenFunc: method is nil but Prompter.AuthToken was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
}{}
|
||||
mock.lockAuthToken.Lock()
|
||||
mock.calls.AuthToken = append(mock.calls.AuthToken, callInfo)
|
||||
mock.lockAuthToken.Unlock()
|
||||
return mock.AuthTokenFunc()
|
||||
}
|
||||
|
||||
// AuthTokenCalls gets all the calls that were made to AuthToken.
|
||||
// Check the length with:
|
||||
// len(mockedPrompter.AuthTokenCalls())
|
||||
func (mock *PrompterMock) AuthTokenCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
}
|
||||
mock.lockAuthToken.RLock()
|
||||
calls = mock.calls.AuthToken
|
||||
mock.lockAuthToken.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Confirm calls ConfirmFunc.
|
||||
func (mock *PrompterMock) Confirm(s string, b bool) (bool, error) {
|
||||
if mock.ConfirmFunc == nil {
|
||||
panic("PrompterMock.ConfirmFunc: method is nil but Prompter.Confirm was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
S string
|
||||
B bool
|
||||
}{
|
||||
S: s,
|
||||
B: b,
|
||||
}
|
||||
mock.lockConfirm.Lock()
|
||||
mock.calls.Confirm = append(mock.calls.Confirm, callInfo)
|
||||
mock.lockConfirm.Unlock()
|
||||
return mock.ConfirmFunc(s, b)
|
||||
}
|
||||
|
||||
// ConfirmCalls gets all the calls that were made to Confirm.
|
||||
// Check the length with:
|
||||
// len(mockedPrompter.ConfirmCalls())
|
||||
func (mock *PrompterMock) ConfirmCalls() []struct {
|
||||
S string
|
||||
B bool
|
||||
} {
|
||||
var calls []struct {
|
||||
S string
|
||||
B bool
|
||||
}
|
||||
mock.lockConfirm.RLock()
|
||||
calls = mock.calls.Confirm
|
||||
mock.lockConfirm.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Input calls InputFunc.
|
||||
func (mock *PrompterMock) Input(s1 string, s2 string) (string, error) {
|
||||
if mock.InputFunc == nil {
|
||||
panic("PrompterMock.InputFunc: method is nil but Prompter.Input was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
S1 string
|
||||
S2 string
|
||||
}{
|
||||
S1: s1,
|
||||
S2: s2,
|
||||
}
|
||||
mock.lockInput.Lock()
|
||||
mock.calls.Input = append(mock.calls.Input, callInfo)
|
||||
mock.lockInput.Unlock()
|
||||
return mock.InputFunc(s1, s2)
|
||||
}
|
||||
|
||||
// InputCalls gets all the calls that were made to Input.
|
||||
// Check the length with:
|
||||
// len(mockedPrompter.InputCalls())
|
||||
func (mock *PrompterMock) InputCalls() []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
} {
|
||||
var calls []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
}
|
||||
mock.lockInput.RLock()
|
||||
calls = mock.calls.Input
|
||||
mock.lockInput.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// InputHostname calls InputHostnameFunc.
|
||||
func (mock *PrompterMock) InputHostname() (string, error) {
|
||||
if mock.InputHostnameFunc == nil {
|
||||
panic("PrompterMock.InputHostnameFunc: method is nil but Prompter.InputHostname was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
}{}
|
||||
mock.lockInputHostname.Lock()
|
||||
mock.calls.InputHostname = append(mock.calls.InputHostname, callInfo)
|
||||
mock.lockInputHostname.Unlock()
|
||||
return mock.InputHostnameFunc()
|
||||
}
|
||||
|
||||
// InputHostnameCalls gets all the calls that were made to InputHostname.
|
||||
// Check the length with:
|
||||
// len(mockedPrompter.InputHostnameCalls())
|
||||
func (mock *PrompterMock) InputHostnameCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
}
|
||||
mock.lockInputHostname.RLock()
|
||||
calls = mock.calls.InputHostname
|
||||
mock.lockInputHostname.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// MarkdownEditor calls MarkdownEditorFunc.
|
||||
func (mock *PrompterMock) MarkdownEditor(s1 string, s2 string, b bool) (string, error) {
|
||||
if mock.MarkdownEditorFunc == nil {
|
||||
panic("PrompterMock.MarkdownEditorFunc: method is nil but Prompter.MarkdownEditor was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
S1 string
|
||||
S2 string
|
||||
B bool
|
||||
}{
|
||||
S1: s1,
|
||||
S2: s2,
|
||||
B: b,
|
||||
}
|
||||
mock.lockMarkdownEditor.Lock()
|
||||
mock.calls.MarkdownEditor = append(mock.calls.MarkdownEditor, callInfo)
|
||||
mock.lockMarkdownEditor.Unlock()
|
||||
return mock.MarkdownEditorFunc(s1, s2, b)
|
||||
}
|
||||
|
||||
// MarkdownEditorCalls gets all the calls that were made to MarkdownEditor.
|
||||
// Check the length with:
|
||||
// len(mockedPrompter.MarkdownEditorCalls())
|
||||
func (mock *PrompterMock) MarkdownEditorCalls() []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
B bool
|
||||
} {
|
||||
var calls []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
B bool
|
||||
}
|
||||
mock.lockMarkdownEditor.RLock()
|
||||
calls = mock.calls.MarkdownEditor
|
||||
mock.lockMarkdownEditor.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// MultiSelect calls MultiSelectFunc.
|
||||
func (mock *PrompterMock) MultiSelect(s1 string, s2 string, strings []string) (int, error) {
|
||||
if mock.MultiSelectFunc == nil {
|
||||
panic("PrompterMock.MultiSelectFunc: method is nil but Prompter.MultiSelect was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
S1 string
|
||||
S2 string
|
||||
Strings []string
|
||||
}{
|
||||
S1: s1,
|
||||
S2: s2,
|
||||
Strings: strings,
|
||||
}
|
||||
mock.lockMultiSelect.Lock()
|
||||
mock.calls.MultiSelect = append(mock.calls.MultiSelect, callInfo)
|
||||
mock.lockMultiSelect.Unlock()
|
||||
return mock.MultiSelectFunc(s1, s2, strings)
|
||||
}
|
||||
|
||||
// MultiSelectCalls gets all the calls that were made to MultiSelect.
|
||||
// Check the length with:
|
||||
// len(mockedPrompter.MultiSelectCalls())
|
||||
func (mock *PrompterMock) MultiSelectCalls() []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
Strings []string
|
||||
} {
|
||||
var calls []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
Strings []string
|
||||
}
|
||||
mock.lockMultiSelect.RLock()
|
||||
calls = mock.calls.MultiSelect
|
||||
mock.lockMultiSelect.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Password calls PasswordFunc.
|
||||
func (mock *PrompterMock) Password(s string) (string, error) {
|
||||
if mock.PasswordFunc == nil {
|
||||
panic("PrompterMock.PasswordFunc: method is nil but Prompter.Password was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
S string
|
||||
}{
|
||||
S: s,
|
||||
}
|
||||
mock.lockPassword.Lock()
|
||||
mock.calls.Password = append(mock.calls.Password, callInfo)
|
||||
mock.lockPassword.Unlock()
|
||||
return mock.PasswordFunc(s)
|
||||
}
|
||||
|
||||
// PasswordCalls gets all the calls that were made to Password.
|
||||
// Check the length with:
|
||||
// len(mockedPrompter.PasswordCalls())
|
||||
func (mock *PrompterMock) PasswordCalls() []struct {
|
||||
S string
|
||||
} {
|
||||
var calls []struct {
|
||||
S string
|
||||
}
|
||||
mock.lockPassword.RLock()
|
||||
calls = mock.calls.Password
|
||||
mock.lockPassword.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Select calls SelectFunc.
|
||||
func (mock *PrompterMock) Select(s1 string, s2 string, strings []string) (int, error) {
|
||||
if mock.SelectFunc == nil {
|
||||
panic("PrompterMock.SelectFunc: method is nil but Prompter.Select was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
S1 string
|
||||
S2 string
|
||||
Strings []string
|
||||
}{
|
||||
S1: s1,
|
||||
S2: s2,
|
||||
Strings: strings,
|
||||
}
|
||||
mock.lockSelect.Lock()
|
||||
mock.calls.Select = append(mock.calls.Select, callInfo)
|
||||
mock.lockSelect.Unlock()
|
||||
return mock.SelectFunc(s1, s2, strings)
|
||||
}
|
||||
|
||||
// SelectCalls gets all the calls that were made to Select.
|
||||
// Check the length with:
|
||||
// len(mockedPrompter.SelectCalls())
|
||||
func (mock *PrompterMock) SelectCalls() []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
Strings []string
|
||||
} {
|
||||
var calls []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
Strings []string
|
||||
}
|
||||
mock.lockSelect.RLock()
|
||||
calls = mock.calls.Select
|
||||
mock.lockSelect.RUnlock()
|
||||
return calls
|
||||
}
|
||||
22
internal/prompter/test.go
Normal file
22
internal/prompter/test.go
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package prompter
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Test helpers
|
||||
|
||||
func IndexFor(options []string, answer string) (int, error) {
|
||||
for ix, a := range options {
|
||||
if a == answer {
|
||||
return ix, nil
|
||||
}
|
||||
}
|
||||
return -1, NoSuchAnswerErr(answer)
|
||||
}
|
||||
|
||||
func NoSuchAnswerErr(answer string) error {
|
||||
return fmt.Errorf("no such answer '%s'", answer)
|
||||
}
|
||||
|
||||
func NoSuchPromptErr(prompt string) error {
|
||||
return fmt.Errorf("no such prompt '%s'", prompt)
|
||||
}
|
||||
|
|
@ -6,14 +6,13 @@ import (
|
|||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmd/auth/shared"
|
||||
"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"
|
||||
)
|
||||
|
||||
|
|
@ -21,6 +20,7 @@ type LoginOptions struct {
|
|||
IO *iostreams.IOStreams
|
||||
Config func() (config.Config, error)
|
||||
HttpClient func() (*http.Client, error)
|
||||
Prompter prompter.Prompter
|
||||
|
||||
MainExecutable string
|
||||
|
||||
|
|
@ -38,6 +38,7 @@ func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Comm
|
|||
IO: f.IOStreams,
|
||||
Config: f.Config,
|
||||
HttpClient: f.HttpClient,
|
||||
Prompter: f.Prompter,
|
||||
}
|
||||
|
||||
var tokenStdin bool
|
||||
|
|
@ -129,7 +130,7 @@ func loginRun(opts *LoginOptions) error {
|
|||
hostname := opts.Hostname
|
||||
if opts.Interactive && hostname == "" {
|
||||
var err error
|
||||
hostname, err = promptForHostname()
|
||||
hostname, err = promptForHostname(opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -159,15 +160,9 @@ func loginRun(opts *LoginOptions) error {
|
|||
existingToken, _ := cfg.AuthToken(hostname)
|
||||
if existingToken != "" && opts.Interactive {
|
||||
if err := shared.HasMinimumScopes(httpClient, hostname, existingToken); err == nil {
|
||||
var keepGoing bool
|
||||
err = prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: fmt.Sprintf(
|
||||
"You're already logged into %s. Do you want to re-authenticate?",
|
||||
hostname),
|
||||
Default: false,
|
||||
}, &keepGoing)
|
||||
keepGoing, err := opts.Prompter.Confirm(fmt.Sprintf("You're already logged into %s. Do you want to re-authenticate?", hostname), false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
return err
|
||||
}
|
||||
if !keepGoing {
|
||||
return nil
|
||||
|
|
@ -185,34 +180,28 @@ func loginRun(opts *LoginOptions) error {
|
|||
Scopes: opts.Scopes,
|
||||
Executable: opts.MainExecutable,
|
||||
GitProtocol: opts.GitProtocol,
|
||||
Prompter: opts.Prompter,
|
||||
})
|
||||
}
|
||||
|
||||
func promptForHostname() (string, error) {
|
||||
var hostType int
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "What account do you want to log into?",
|
||||
Options: []string{
|
||||
func promptForHostname(opts *LoginOptions) (string, error) {
|
||||
hostType, err := opts.Prompter.Select(
|
||||
"What account do you want to log into?",
|
||||
"",
|
||||
[]string{
|
||||
"GitHub.com",
|
||||
"GitHub Enterprise Server",
|
||||
},
|
||||
}, &hostType)
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not prompt: %w", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
isEnterprise := hostType == 1
|
||||
|
||||
hostname := ghinstance.Default()
|
||||
if isEnterprise {
|
||||
err := prompt.SurveyAskOne(&survey.Input{
|
||||
Message: "GHE hostname:",
|
||||
}, &hostname, survey.WithValidator(ghinstance.HostnameValidator))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("could not prompt: %w", err)
|
||||
}
|
||||
hostname, err = opts.Prompter.InputHostname()
|
||||
}
|
||||
|
||||
return hostname, nil
|
||||
return hostname, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ import (
|
|||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"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"
|
||||
)
|
||||
|
|
@ -362,14 +362,14 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
stubHomeDir(t, t.TempDir())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
opts *LoginOptions
|
||||
httpStubs func(*httpmock.Registry)
|
||||
askStubs func(*prompt.AskStubber)
|
||||
runStubs func(*run.CommandStubber)
|
||||
wantHosts string
|
||||
wantErrOut *regexp.Regexp
|
||||
cfgStubs func(*config.ConfigMock)
|
||||
name string
|
||||
opts *LoginOptions
|
||||
httpStubs func(*httpmock.Registry)
|
||||
prompterStubs func(*prompter.PrompterMock)
|
||||
runStubs func(*run.CommandStubber)
|
||||
wantHosts string
|
||||
wantErrOut *regexp.Regexp
|
||||
cfgStubs func(*config.ConfigMock)
|
||||
}{
|
||||
{
|
||||
name: "already authenticated",
|
||||
|
|
@ -384,9 +384,13 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(httpmock.REST("GET", ""), httpmock.ScopesResponder("repo,read:org"))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
as.StubPrompt("What account do you want to log into?").AnswerWith("GitHub.com")
|
||||
as.StubPrompt("You're already logged into github.com. Do you want to re-authenticate?").AnswerWith(false)
|
||||
prompterStubs: func(pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
||||
if prompt == "What account do you want to log into?" {
|
||||
return prompter.IndexFor(opts, "GitHub.com")
|
||||
}
|
||||
return -1, prompter.NoSuchPromptErr(prompt)
|
||||
}
|
||||
},
|
||||
wantHosts: "",
|
||||
wantErrOut: nil,
|
||||
|
|
@ -403,11 +407,16 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
user: jillv
|
||||
git_protocol: https
|
||||
`),
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
as.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("HTTPS")
|
||||
as.StubPrompt("Authenticate Git with your GitHub credentials?").AnswerWith(false)
|
||||
as.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token")
|
||||
as.StubPrompt("Paste your authentication token:").AnswerWith("def456")
|
||||
prompterStubs: func(pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
||||
switch prompt {
|
||||
case "What is your preferred protocol for Git operations?":
|
||||
return prompter.IndexFor(opts, "HTTPS")
|
||||
case "How would you like to authenticate GitHub CLI?":
|
||||
return prompter.IndexFor(opts, "Paste an authentication token")
|
||||
}
|
||||
return -1, prompter.NoSuchPromptErr(prompt)
|
||||
}
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git config credential\.https:/`, 1, "")
|
||||
|
|
@ -432,13 +441,21 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
opts: &LoginOptions{
|
||||
Interactive: true,
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
as.StubPrompt("What account do you want to log into?").AnswerWith("GitHub Enterprise Server")
|
||||
as.StubPrompt("GHE hostname:").AnswerWith("brad.vickers")
|
||||
as.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("HTTPS")
|
||||
as.StubPrompt("Authenticate Git with your GitHub credentials?").AnswerWith(false)
|
||||
as.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token")
|
||||
as.StubPrompt("Paste your authentication token:").AnswerWith("def456")
|
||||
prompterStubs: func(pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
||||
switch prompt {
|
||||
case "What account do you want to log into?":
|
||||
return prompter.IndexFor(opts, "GitHub Enterprise Server")
|
||||
case "What is your preferred protocol for Git operations?":
|
||||
return prompter.IndexFor(opts, "HTTPS")
|
||||
case "How would you like to authenticate GitHub CLI?":
|
||||
return prompter.IndexFor(opts, "Paste an authentication token")
|
||||
}
|
||||
return -1, prompter.NoSuchPromptErr(prompt)
|
||||
}
|
||||
pm.InputHostnameFunc = func() (string, error) {
|
||||
return "brad.vickers", nil
|
||||
}
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git config credential\.https:/`, 1, "")
|
||||
|
|
@ -463,12 +480,18 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
opts: &LoginOptions{
|
||||
Interactive: true,
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
as.StubPrompt("What account do you want to log into?").AnswerWith("GitHub.com")
|
||||
as.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("HTTPS")
|
||||
as.StubPrompt("Authenticate Git with your GitHub credentials?").AnswerWith(false)
|
||||
as.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token")
|
||||
as.StubPrompt("Paste your authentication token:").AnswerWith("def456")
|
||||
prompterStubs: func(pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
||||
switch prompt {
|
||||
case "What account do you want to log into?":
|
||||
return prompter.IndexFor(opts, "GitHub.com")
|
||||
case "What is your preferred protocol for Git operations?":
|
||||
return prompter.IndexFor(opts, "HTTPS")
|
||||
case "How would you like to authenticate GitHub CLI?":
|
||||
return prompter.IndexFor(opts, "Paste an authentication token")
|
||||
}
|
||||
return -1, prompter.NoSuchPromptErr(prompt)
|
||||
}
|
||||
},
|
||||
runStubs: func(rs *run.CommandStubber) {
|
||||
rs.Register(`git config credential\.https:/`, 1, "")
|
||||
|
|
@ -487,12 +510,18 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
opts: &LoginOptions{
|
||||
Interactive: true,
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
as.StubPrompt("What account do you want to log into?").AnswerWith("GitHub.com")
|
||||
as.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("SSH")
|
||||
as.StubPrompt("Generate a new SSH key to add to your GitHub account?").AnswerWith(false)
|
||||
as.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token")
|
||||
as.StubPrompt("Paste your authentication token:").AnswerWith("def456")
|
||||
prompterStubs: func(pm *prompter.PrompterMock) {
|
||||
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
||||
switch prompt {
|
||||
case "What account do you want to log into?":
|
||||
return prompter.IndexFor(opts, "GitHub.com")
|
||||
case "What is your preferred protocol for Git operations?":
|
||||
return prompter.IndexFor(opts, "SSH")
|
||||
case "How would you like to authenticate GitHub CLI?":
|
||||
return prompter.IndexFor(opts, "Paste an authentication token")
|
||||
}
|
||||
return -1, prompter.NoSuchPromptErr(prompt)
|
||||
}
|
||||
},
|
||||
wantErrOut: regexp.MustCompile("Tip: you can generate a Personal Access Token here https://github.com/settings/tokens"),
|
||||
},
|
||||
|
|
@ -535,10 +564,17 @@ func Test_loginRun_Survey(t *testing.T) {
|
|||
httpmock.StringResponse(`{"data":{"viewer":{"login":"jillv"}}}`))
|
||||
}
|
||||
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
pm := &prompter.PrompterMock{}
|
||||
pm.ConfirmFunc = func(_ string, _ bool) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
pm.AuthTokenFunc = func() (string, error) {
|
||||
return "def456", nil
|
||||
}
|
||||
if tt.prompterStubs != nil {
|
||||
tt.prompterStubs(pm)
|
||||
}
|
||||
tt.opts.Prompter = pm
|
||||
|
||||
rs, restoreRun := run.Stub()
|
||||
defer restoreRun(t)
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ func logoutRun(opts *LogoutOptions) error {
|
|||
if len(candidates) == 1 {
|
||||
hostname = candidates[0]
|
||||
} else {
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "What account do you want to log out of?",
|
||||
Options: candidates,
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ func Test_logoutRun_tty(t *testing.T) {
|
|||
return &http.Client{Transport: reg}, nil
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ func refreshRun(opts *RefreshOptions) error {
|
|||
if len(candidates) == 1 {
|
||||
hostname = candidates[0]
|
||||
} else {
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "What account do you want to refresh auth for?",
|
||||
Options: candidates,
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ func Test_refreshRun(t *testing.T) {
|
|||
)
|
||||
tt.opts.httpClient = &http.Client{Transport: httpReg}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -7,17 +7,17 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/git"
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/internal/run"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
"github.com/google/shlex"
|
||||
)
|
||||
|
||||
type GitCredentialFlow struct {
|
||||
Executable string
|
||||
Prompter prompter.Prompter
|
||||
|
||||
shouldSetup bool
|
||||
helper string
|
||||
|
|
@ -32,13 +32,12 @@ func (flow *GitCredentialFlow) Prompt(hostname string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
err := prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: "Authenticate Git with your GitHub credentials?",
|
||||
Default: true,
|
||||
}, &flow.shouldSetup)
|
||||
result, err := flow.Prompter.Confirm("Authenticate Git with your GitHub credentials?", true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
return err
|
||||
}
|
||||
flow.shouldSetup = result
|
||||
|
||||
if flow.shouldSetup {
|
||||
if isGitMissing(gitErr) {
|
||||
return gitErr
|
||||
|
|
|
|||
|
|
@ -6,14 +6,13 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/authflow"
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmd/ssh-key/add"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
"github.com/cli/cli/v2/pkg/ssh"
|
||||
)
|
||||
|
||||
|
|
@ -35,6 +34,7 @@ type LoginOptions struct {
|
|||
Scopes []string
|
||||
Executable string
|
||||
GitProtocol string
|
||||
Prompter prompter.Prompter
|
||||
|
||||
sshContext ssh.Context
|
||||
}
|
||||
|
|
@ -47,23 +47,23 @@ func Login(opts *LoginOptions) error {
|
|||
|
||||
gitProtocol := strings.ToLower(opts.GitProtocol)
|
||||
if opts.Interactive && gitProtocol == "" {
|
||||
var proto string
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "What is your preferred protocol for Git operations?",
|
||||
Options: []string{
|
||||
"HTTPS",
|
||||
"SSH",
|
||||
},
|
||||
}, &proto)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
options := []string{
|
||||
"HTTPS",
|
||||
"SSH",
|
||||
}
|
||||
result, err := opts.Prompter.Select(
|
||||
"What is your preferred protocol for Git operations?",
|
||||
"", options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
proto := options[result]
|
||||
gitProtocol = strings.ToLower(proto)
|
||||
}
|
||||
|
||||
var additionalScopes []string
|
||||
|
||||
credentialFlow := &GitCredentialFlow{Executable: opts.Executable}
|
||||
credentialFlow := &GitCredentialFlow{Executable: opts.Executable, Prompter: opts.Prompter}
|
||||
if opts.Interactive && gitProtocol == "https" {
|
||||
if err := credentialFlow.Prompt(hostname); err != nil {
|
||||
return err
|
||||
|
|
@ -80,34 +80,28 @@ func Login(opts *LoginOptions) error {
|
|||
}
|
||||
|
||||
if len(pubKeys) > 0 {
|
||||
var keyChoice int
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "Upload your SSH public key to your GitHub account?",
|
||||
Options: append(pubKeys, "Skip"),
|
||||
}, &keyChoice)
|
||||
options := append(pubKeys, "Skip")
|
||||
keyChoice, err := opts.Prompter.Select(
|
||||
"Upload your SSH public key to your GitHub account?", "",
|
||||
options)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
return err
|
||||
}
|
||||
if keyChoice < len(pubKeys) {
|
||||
keyToUpload = pubKeys[keyChoice]
|
||||
}
|
||||
} else if opts.sshContext.HasKeygen() {
|
||||
var sshChoice bool
|
||||
err := prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: "Generate a new SSH key to add to your GitHub account?",
|
||||
Default: true,
|
||||
}, &sshChoice)
|
||||
|
||||
sshChoice, err := opts.Prompter.Confirm("Generate a new SSH key to add to your GitHub account?", true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if sshChoice {
|
||||
passphrase, err := promptForSshKeyPassphrase()
|
||||
passphrase, err := opts.Prompter.Password(
|
||||
"Enter a passphrase for your new SSH key (Optional)")
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt for key passphrase: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
keyPair, err := opts.sshContext.GenerateSSHKey("id_ed25519", passphrase)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -117,12 +111,11 @@ func Login(opts *LoginOptions) error {
|
|||
}
|
||||
|
||||
if keyToUpload != "" {
|
||||
err := prompt.SurveyAskOne(&survey.Input{
|
||||
Message: "Title for your SSH key:",
|
||||
Default: defaultSSHKeyTitle,
|
||||
}, &keyTitle)
|
||||
var err error
|
||||
keyTitle, err = opts.Prompter.Input(
|
||||
"Title for your SSH key:", defaultSSHKeyTitle)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
additionalScopes = append(additionalScopes, "admin:public_key")
|
||||
|
|
@ -133,15 +126,14 @@ func Login(opts *LoginOptions) error {
|
|||
if opts.Web {
|
||||
authMode = 0
|
||||
} else if opts.Interactive {
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "How would you like to authenticate GitHub CLI?",
|
||||
Options: []string{
|
||||
var err error
|
||||
authMode, err = opts.Prompter.Select(
|
||||
"How would you like to authenticate GitHub CLI?", "",
|
||||
[]string{
|
||||
"Login with a web browser",
|
||||
"Paste an authentication token",
|
||||
},
|
||||
}, &authMode)
|
||||
"Paste an authentication token"})
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,11 +155,9 @@ func Login(opts *LoginOptions) error {
|
|||
The minimum required scopes are %s.
|
||||
`, hostname, scopesSentence(minimumScopes, ghinstance.IsEnterprise(hostname))))
|
||||
|
||||
err := prompt.SurveyAskOne(&survey.Password{
|
||||
Message: "Paste your authentication token:",
|
||||
}, &authToken, survey.WithValidator(survey.Required))
|
||||
authToken, err := opts.Prompter.AuthToken()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := HasMinimumScopes(httpClient, hostname, authToken); err != nil {
|
||||
|
|
@ -221,19 +211,6 @@ func Login(opts *LoginOptions) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func promptForSshKeyPassphrase() (string, error) {
|
||||
var sshPassphrase string
|
||||
err := prompt.SurveyAskOne(&survey.Password{
|
||||
Message: "Enter a passphrase for your new SSH key (Optional)",
|
||||
}, &sshPassphrase)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return sshPassphrase, nil
|
||||
}
|
||||
|
||||
func scopesSentence(scopes []string, isEnterprise bool) string {
|
||||
quoted := make([]string, len(scopes))
|
||||
for i, s := range scopes {
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/internal/run"
|
||||
"github.com/cli/cli/v2/pkg/httpmock"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
"github.com/cli/cli/v2/pkg/ssh"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -47,14 +47,28 @@ func TestLogin_ssh(t *testing.T) {
|
|||
httpmock.REST("POST", "api/v3/user/keys"),
|
||||
httpmock.StringResponse(`{}`))
|
||||
|
||||
ask := prompt.NewAskStubber(t)
|
||||
|
||||
ask.StubPrompt("What is your preferred protocol for Git operations?").AnswerWith("SSH")
|
||||
ask.StubPrompt("Generate a new SSH key to add to your GitHub account?").AnswerWith(true)
|
||||
ask.StubPrompt("Enter a passphrase for your new SSH key (Optional)").AnswerWith("monkey")
|
||||
ask.StubPrompt("Title for your SSH key:").AnswerWith("Test Key")
|
||||
ask.StubPrompt("How would you like to authenticate GitHub CLI?").AnswerWith("Paste an authentication token")
|
||||
ask.StubPrompt("Paste your authentication token:").AnswerWith("ATOKEN")
|
||||
pm := &prompter.PrompterMock{}
|
||||
pm.SelectFunc = func(prompt, _ string, opts []string) (int, error) {
|
||||
switch prompt {
|
||||
case "What is your preferred protocol for Git operations?":
|
||||
return prompter.IndexFor(opts, "SSH")
|
||||
case "How would you like to authenticate GitHub CLI?":
|
||||
return prompter.IndexFor(opts, "Paste an authentication token")
|
||||
}
|
||||
return -1, prompter.NoSuchPromptErr(prompt)
|
||||
}
|
||||
pm.PasswordFunc = func(_ string) (string, error) {
|
||||
return "monkey", nil
|
||||
}
|
||||
pm.ConfirmFunc = func(prompt string, _ bool) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
pm.AuthTokenFunc = func() (string, error) {
|
||||
return "ATOKEN", nil
|
||||
}
|
||||
pm.InputFunc = func(_, _ string) (string, error) {
|
||||
return "Test Key", nil
|
||||
}
|
||||
|
||||
rs, runRestore := run.Stub()
|
||||
defer runRestore(t)
|
||||
|
|
@ -77,6 +91,7 @@ func TestLogin_ssh(t *testing.T) {
|
|||
err := Login(&LoginOptions{
|
||||
IO: ios,
|
||||
Config: &cfg,
|
||||
Prompter: pm,
|
||||
HTTPClient: &http.Client{Transport: &tr},
|
||||
Hostname: "example.com",
|
||||
Interactive: true,
|
||||
|
|
|
|||
|
|
@ -6,13 +6,11 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/git"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/extensions"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
"github.com/cli/cli/v2/utils"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
@ -20,6 +18,7 @@ import (
|
|||
func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
|
||||
m := f.ExtensionManager
|
||||
io := f.IOStreams
|
||||
prompter := f.Prompter
|
||||
|
||||
extCmd := cobra.Command{
|
||||
Use: "extension",
|
||||
|
|
@ -244,22 +243,15 @@ func NewCmdExtension(f *cmdutil.Factory) *cobra.Command {
|
|||
},
|
||||
func() *cobra.Command {
|
||||
promptCreate := func() (string, extensions.ExtTemplateType, error) {
|
||||
var extName string
|
||||
var extTmplType int
|
||||
err := prompt.SurveyAskOne(&survey.Input{
|
||||
Message: "Extension name:",
|
||||
}, &extName)
|
||||
extName, err := prompter.Input("Extension name:", "")
|
||||
if err != nil {
|
||||
return extName, -1, err
|
||||
}
|
||||
err = prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "What kind of extension?",
|
||||
Options: []string{
|
||||
"Script (Bash, Ruby, Python, etc)",
|
||||
"Go",
|
||||
"Other Precompiled (C++, Rust, etc)",
|
||||
},
|
||||
}, &extTmplType)
|
||||
extTmplType, err := prompter.Select("What kind of extension?", "", []string{
|
||||
"Script (Bash, Ruby, Python, etc)",
|
||||
"Go",
|
||||
"Other Precompiled (C++, Rust, etc)",
|
||||
})
|
||||
return extName, extensions.ExtTemplateType(extTmplType), err
|
||||
}
|
||||
var flagType string
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ import (
|
|||
"github.com/MakeNowJust/heredoc"
|
||||
"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/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/extensions"
|
||||
"github.com/cli/cli/v2/pkg/httpmock"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -28,15 +28,15 @@ func TestNewCmdExtension(t *testing.T) {
|
|||
t.Cleanup(func() { _ = os.Chdir(oldWd) })
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args []string
|
||||
managerStubs func(em *extensions.ExtensionManagerMock) func(*testing.T)
|
||||
askStubs func(as *prompt.AskStubber)
|
||||
isTTY bool
|
||||
wantErr bool
|
||||
errMsg string
|
||||
wantStdout string
|
||||
wantStderr string
|
||||
name string
|
||||
args []string
|
||||
managerStubs func(em *extensions.ExtensionManagerMock) func(*testing.T)
|
||||
prompterStubs func(pm *prompter.PrompterMock)
|
||||
isTTY bool
|
||||
wantErr bool
|
||||
errMsg string
|
||||
wantStdout string
|
||||
wantStderr string
|
||||
}{
|
||||
{
|
||||
name: "install an extension",
|
||||
|
|
@ -387,11 +387,16 @@ func TestNewCmdExtension(t *testing.T) {
|
|||
}
|
||||
},
|
||||
isTTY: true,
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
as.StubPrompt("Extension name:").AnswerWith("test")
|
||||
as.StubPrompt("What kind of extension?").
|
||||
AssertOptions([]string{"Script (Bash, Ruby, Python, etc)", "Go", "Other Precompiled (C++, Rust, etc)"}).
|
||||
AnswerDefault()
|
||||
prompterStubs: func(pm *prompter.PrompterMock) {
|
||||
pm.InputFunc = func(prompt, defVal string) (string, error) {
|
||||
if prompt == "Extension name:" {
|
||||
return "test", nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
pm.SelectFunc = func(prompt, defVal string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "Script (Bash, Ruby, Python, etc)")
|
||||
}
|
||||
},
|
||||
wantStdout: heredoc.Doc(`
|
||||
✓ Created directory gh-test
|
||||
|
|
@ -562,9 +567,9 @@ func TestNewCmdExtension(t *testing.T) {
|
|||
assertFunc = tt.managerStubs(em)
|
||||
}
|
||||
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
pm := &prompter.PrompterMock{}
|
||||
if tt.prompterStubs != nil {
|
||||
tt.prompterStubs(pm)
|
||||
}
|
||||
|
||||
reg := httpmock.Registry{}
|
||||
|
|
@ -577,6 +582,7 @@ func TestNewCmdExtension(t *testing.T) {
|
|||
},
|
||||
IOStreams: ios,
|
||||
ExtensionManager: em,
|
||||
Prompter: pm,
|
||||
HttpClient: func() (*http.Client, error) {
|
||||
return &client, nil
|
||||
},
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ 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/pkg/cmd/extension"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
|
|
@ -31,6 +32,7 @@ func New(appVersion string) *cmdutil.Factory {
|
|||
f.HttpClient = httpClientFunc(f, appVersion) // Depends on Config, IOStreams, and appVersion
|
||||
f.Remotes = remotesFunc(f) // Depends on Config
|
||||
f.BaseRepo = BaseRepoFunc(f) // Depends on Remotes
|
||||
f.Prompter = newPrompter(f) // Depends on Config and IOStreams
|
||||
f.Browser = browser(f) // Depends on Config, and IOStreams
|
||||
f.ExtensionManager = extensionManager(f) // Depends on Config, HttpClient, and IOStreams
|
||||
|
||||
|
|
@ -108,6 +110,12 @@ func browser(f *cmdutil.Factory) cmdutil.Browser {
|
|||
return cmdutil.NewBrowser(browserLauncher(f), io.Out, io.ErrOut)
|
||||
}
|
||||
|
||||
func newPrompter(f *cmdutil.Factory) prompter.Prompter {
|
||||
editor, _ := cmdutil.DetermineEditor(f.Config)
|
||||
io := f.IOStreams
|
||||
return prompter.New(editor, io.In, io.Out, io.ErrOut)
|
||||
}
|
||||
|
||||
// Browser precedence
|
||||
// 1. GH_BROWSER
|
||||
// 2. browser from config
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ func editRun(opts *EditOptions) error {
|
|||
if !opts.IO.CanPrompt() {
|
||||
return errors.New("unsure what file to edit; either specify --filename or run interactively")
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "Edit which file?",
|
||||
Options: candidates,
|
||||
|
|
@ -249,6 +250,7 @@ func editRun(opts *EditOptions) error {
|
|||
|
||||
choice := ""
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "What next?",
|
||||
Options: []string{
|
||||
|
|
|
|||
|
|
@ -486,6 +486,7 @@ func Test_editRun(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ func promptGists(client *http.Client, host string, cs *iostreams.ColorScheme) (g
|
|||
Options: opts,
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(questions, &result)
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ func Test_viewRun(t *testing.T) {
|
|||
)),
|
||||
)
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("Select a gist").AnswerDefault()
|
||||
}
|
||||
|
|
@ -469,6 +470,7 @@ func Test_promptGists(t *testing.T) {
|
|||
client := &http.Client{Transport: reg}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -402,6 +402,7 @@ func TestIssueCreate_recover(t *testing.T) {
|
|||
assert.Equal(t, []interface{}{"BUGID", "TODOID"}, inputs["labelIds"])
|
||||
}))
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
|
||||
as.StubPrompt("Title").AnswerDefault()
|
||||
|
|
@ -469,6 +470,7 @@ func TestIssueCreate_nonLegacyTemplate(t *testing.T) {
|
|||
}),
|
||||
)
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
|
||||
as.StubPrompt("Choose a template").AnswerWith("Submit a request")
|
||||
|
|
@ -499,6 +501,7 @@ func TestIssueCreate_continueInBrowser(t *testing.T) {
|
|||
} } }`),
|
||||
)
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
|
||||
as.StubPrompt("Title").AnswerWith("hello")
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ func deleteRun(opts *DeleteOptions) error {
|
|||
// already provided. Otherwise skip confirmation.
|
||||
if opts.IO.CanPrompt() && !opts.Confirmed {
|
||||
answer := ""
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(
|
||||
&survey.Input{
|
||||
Message: fmt.Sprintf("You're going to delete issue #%d. This action cannot be reversed. To confirm, type the issue number:", issue.Number),
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ func TestIssueDelete(t *testing.T) {
|
|||
}),
|
||||
)
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("You're going to delete issue #13. This action cannot be reversed. To confirm, type the issue number:").AnswerWith("13")
|
||||
|
||||
|
|
@ -136,6 +137,7 @@ func TestIssueDelete_cancel(t *testing.T) {
|
|||
} } }`),
|
||||
)
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("You're going to delete issue #13. This action cannot be reversed. To confirm, type the issue number:").AnswerWith("14")
|
||||
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ func deleteRun(opts *deleteOptions) error {
|
|||
|
||||
if !opts.Confirmed {
|
||||
var valid string
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(
|
||||
&survey.Input{Message: fmt.Sprintf("Type %s to confirm deletion:", opts.Name)},
|
||||
&valid,
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ func TestDeleteRun(t *testing.T) {
|
|||
return &http.Client{Transport: reg}, nil
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -569,6 +569,7 @@ func NewCreateContext(opts *CreateOptions) (*CreateContext, error) {
|
|||
pushOptions = append(pushOptions, "Cancel")
|
||||
|
||||
var selectedOption int
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Select{
|
||||
Message: fmt.Sprintf("Where should we push the '%s' branch?", headBranch),
|
||||
Options: pushOptions,
|
||||
|
|
|
|||
|
|
@ -370,6 +370,7 @@ func (m *mergeContext) deleteLocalBranch() error {
|
|||
if m.merged {
|
||||
// prompt for delete
|
||||
if m.opts.IO.CanPrompt() && !m.opts.IsDeleteBranchIndicated {
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: fmt.Sprintf("Pull request #%d was already merged. Delete the branch locally?", m.pr.Number),
|
||||
Default: false,
|
||||
|
|
@ -571,6 +572,7 @@ func mergeMethodSurvey(baseRepo *api.Repository) (PullRequestMergeMethod, error)
|
|||
}
|
||||
|
||||
var result int
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(mergeQuestion, &result)
|
||||
return mergeOpts[result].method, err
|
||||
}
|
||||
|
|
@ -589,6 +591,7 @@ func deleteBranchSurvey(opts *MergeOptions, crossRepoPR, localBranchExists bool)
|
|||
Message: message,
|
||||
Default: false,
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(submit, &result)
|
||||
return result, err
|
||||
}
|
||||
|
|
@ -615,6 +618,7 @@ func confirmSurvey(allowEditMsg bool) (shared.Action, error) {
|
|||
Message: "What's next?",
|
||||
Options: options,
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(submit, &result)
|
||||
if err != nil {
|
||||
return shared.CancelAction, fmt.Errorf("could not prompt: %w", err)
|
||||
|
|
|
|||
|
|
@ -960,6 +960,7 @@ func TestPrMerge_alreadyMerged(t *testing.T) {
|
|||
cs.Register(`git branch -D blueberries`, 0, "")
|
||||
cs.Register(`git pull --ff-only`, 0, "")
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("Pull request #4 was already merged. Delete the branch locally?").AnswerWith(true)
|
||||
|
||||
|
|
@ -1021,6 +1022,7 @@ func TestPrMerge_alreadyMerged_withMergeStrategy_TTY(t *testing.T) {
|
|||
cs.Register(`git rev-parse --verify refs/heads/`, 0, "")
|
||||
cs.Register(`git branch -D `, 0, "")
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("Pull request #4 was already merged. Delete the branch locally?").AnswerWith(true)
|
||||
|
||||
|
|
@ -1100,6 +1102,7 @@ func TestPRMergeTTY(t *testing.T) {
|
|||
|
||||
cs.Register(`git rev-parse --verify refs/heads/blueberries`, 0, "")
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("What merge method would you like to use?").AnswerDefault()
|
||||
as.StubPrompt("Delete the branch locally and on GitHub?").AnswerDefault()
|
||||
|
|
@ -1161,6 +1164,7 @@ func TestPRMergeTTY_withDeleteBranch(t *testing.T) {
|
|||
cs.Register(`git branch -D blueberries`, 0, "")
|
||||
cs.Register(`git pull --ff-only`, 0, "")
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("What merge method would you like to use?").AnswerDefault()
|
||||
as.StubPrompt("What's next?").AnswerWith("Submit")
|
||||
|
|
@ -1220,6 +1224,7 @@ func TestPRMergeTTY_squashEditCommitMsgAndSubject(t *testing.T) {
|
|||
_, cmdTeardown := run.Stub()
|
||||
defer cmdTeardown(t)
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("What merge method would you like to use?").AnswerWith("Squash and merge")
|
||||
as.StubPrompt("Delete the branch on GitHub?").AnswerDefault()
|
||||
|
|
@ -1298,6 +1303,7 @@ func TestPRTTY_cancelled(t *testing.T) {
|
|||
|
||||
cs.Register(`git rev-parse --verify refs/heads/`, 0, "")
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("What merge method would you like to use?").AnswerDefault()
|
||||
as.StubPrompt("Delete the branch locally and on GitHub?").AnswerDefault()
|
||||
|
|
@ -1317,6 +1323,7 @@ func Test_mergeMethodSurvey(t *testing.T) {
|
|||
RebaseMergeAllowed: true,
|
||||
SquashMergeAllowed: true,
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("What merge method would you like to use?").AnswerWith("Rebase and merge")
|
||||
|
||||
|
|
@ -1624,6 +1631,7 @@ func TestPrAddToMergeQueueAdmin(t *testing.T) {
|
|||
defer cmdTeardown(t)
|
||||
cs.Register(`git rev-parse --verify refs/heads/`, 0, "")
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("What merge method would you like to use?").AnswerDefault()
|
||||
as.StubPrompt("Delete the branch locally and on GitHub?").AnswerDefault()
|
||||
|
|
|
|||
|
|
@ -5,16 +5,14 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/config"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmd/pr/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/markdown"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
"github.com/cli/cli/v2/pkg/surveyext"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
|
@ -22,6 +20,7 @@ type ReviewOptions struct {
|
|||
HttpClient func() (*http.Client, error)
|
||||
Config func() (config.Config, error)
|
||||
IO *iostreams.IOStreams
|
||||
Prompter prompter.Prompter
|
||||
|
||||
Finder shared.PRFinder
|
||||
|
||||
|
|
@ -36,6 +35,7 @@ func NewCmdReview(f *cmdutil.Factory, runF func(*ReviewOptions) error) *cobra.Co
|
|||
IO: f.IOStreams,
|
||||
HttpClient: f.HttpClient,
|
||||
Config: f.Config,
|
||||
Prompter: f.Prompter,
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -160,7 +160,7 @@ func reviewRun(opts *ReviewOptions) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reviewData, err = reviewSurvey(opts.IO, editorCommand)
|
||||
reviewData, err = reviewSurvey(opts, editorCommand)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -204,95 +204,51 @@ func reviewRun(opts *ReviewOptions) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func reviewSurvey(io *iostreams.IOStreams, editorCommand string) (*api.PullRequestReviewInput, error) {
|
||||
typeAnswers := struct {
|
||||
ReviewType string
|
||||
}{}
|
||||
typeQs := []*survey.Question{
|
||||
{
|
||||
Name: "reviewType",
|
||||
Prompt: &survey.Select{
|
||||
Message: "What kind of review do you want to give?",
|
||||
Options: []string{
|
||||
"Comment",
|
||||
"Approve",
|
||||
"Request changes",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := prompt.SurveyAsk(typeQs, &typeAnswers)
|
||||
func reviewSurvey(opts *ReviewOptions, editorCommand string) (*api.PullRequestReviewInput, error) {
|
||||
reviewType, err := opts.Prompter.Select(
|
||||
"What kind of review do you want to give?", "",
|
||||
[]string{"Comment", "Approve", "Request Changes"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var reviewState api.PullRequestReviewState
|
||||
|
||||
switch typeAnswers.ReviewType {
|
||||
case "Approve":
|
||||
reviewState = api.ReviewApprove
|
||||
case "Request changes":
|
||||
reviewState = api.ReviewRequestChanges
|
||||
case "Comment":
|
||||
switch reviewType {
|
||||
case 0:
|
||||
reviewState = api.ReviewComment
|
||||
case 1:
|
||||
reviewState = api.ReviewApprove
|
||||
case 2:
|
||||
reviewState = api.ReviewRequestChanges
|
||||
default:
|
||||
panic("unreachable state")
|
||||
}
|
||||
|
||||
bodyAnswers := struct {
|
||||
Body string
|
||||
}{}
|
||||
|
||||
blankAllowed := false
|
||||
if reviewState == api.ReviewApprove {
|
||||
blankAllowed = true
|
||||
}
|
||||
|
||||
bodyQs := []*survey.Question{
|
||||
{
|
||||
Name: "body",
|
||||
Prompt: &surveyext.GhEditor{
|
||||
BlankAllowed: blankAllowed,
|
||||
EditorCommand: editorCommand,
|
||||
Editor: &survey.Editor{
|
||||
Message: "Review body",
|
||||
FileName: "*.md",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = prompt.SurveyAsk(bodyQs, &bodyAnswers)
|
||||
body, err := opts.Prompter.MarkdownEditor("Review body", "", blankAllowed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if bodyAnswers.Body == "" && (reviewState == api.ReviewComment || reviewState == api.ReviewRequestChanges) {
|
||||
if body == "" && (reviewState == api.ReviewComment || reviewState == api.ReviewRequestChanges) {
|
||||
return nil, errors.New("this type of review cannot be blank")
|
||||
}
|
||||
|
||||
if len(bodyAnswers.Body) > 0 {
|
||||
renderedBody, err := markdown.Render(bodyAnswers.Body, markdown.WithIO(io))
|
||||
if len(body) > 0 {
|
||||
renderedBody, err := markdown.Render(body, markdown.WithIO(opts.IO))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Fprintf(io.Out, "Got:\n%s", renderedBody)
|
||||
fmt.Fprintf(opts.IO.Out, "Got:\n%s", renderedBody)
|
||||
}
|
||||
|
||||
confirm := false
|
||||
confirmQs := []*survey.Question{
|
||||
{
|
||||
Name: "confirm",
|
||||
Prompt: &survey.Confirm{
|
||||
Message: "Submit?",
|
||||
Default: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err = prompt.SurveyAsk(confirmQs, &confirm)
|
||||
confirm, err := opts.Prompter.Confirm("Submit?", true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -302,7 +258,7 @@ func reviewSurvey(io *iostreams.IOStreams, editorCommand string) (*api.PullReque
|
|||
}
|
||||
|
||||
return &api.PullRequestReviewInput{
|
||||
Body: bodyAnswers.Body,
|
||||
Body: body,
|
||||
State: reviewState,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ import (
|
|||
"github.com/cli/cli/v2/context"
|
||||
"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/pkg/cmd/pr/shared"
|
||||
"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/cli/cli/v2/test"
|
||||
"github.com/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -166,7 +166,7 @@ func Test_NewCmdReview(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func runCommand(rt http.RoundTripper, remotes context.Remotes, isTTY bool, cli string) (*test.CmdOut, error) {
|
||||
func runCommand(rt http.RoundTripper, prompter prompter.Prompter, remotes context.Remotes, isTTY bool, cli string) (*test.CmdOut, error) {
|
||||
ios, _, stdout, stderr := iostreams.Test()
|
||||
ios.SetStdoutTTY(isTTY)
|
||||
ios.SetStdinTTY(isTTY)
|
||||
|
|
@ -180,6 +180,7 @@ func runCommand(rt http.RoundTripper, remotes context.Remotes, isTTY bool, cli s
|
|||
Config: func() (config.Config, error) {
|
||||
return config.NewBlankConfig(), nil
|
||||
},
|
||||
Prompter: prompter,
|
||||
}
|
||||
|
||||
cmd := NewCmdReview(factory, nil)
|
||||
|
|
@ -248,7 +249,7 @@ func TestPRReview(t *testing.T) {
|
|||
}),
|
||||
)
|
||||
|
||||
output, err := runCommand(http, nil, false, tt.args)
|
||||
output, err := runCommand(http, nil, nil, false, tt.args)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "", output.String())
|
||||
assert.Equal(t, "", output.Stderr())
|
||||
|
|
@ -271,33 +272,13 @@ func TestPRReview_interactive(t *testing.T) {
|
|||
}),
|
||||
)
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
|
||||
as, teardown := prompt.InitAskStubber()
|
||||
defer teardown()
|
||||
pm := &prompter.PrompterMock{
|
||||
SelectFunc: func(_, _ string, _ []string) (int, error) { return 1, nil },
|
||||
MarkdownEditorFunc: func(_, _ string, _ bool) (string, error) { return "cool story", nil },
|
||||
ConfirmFunc: func(_ string, _ bool) (bool, error) { return true, nil },
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt
|
||||
as.Stub([]*prompt.QuestionStub{
|
||||
{
|
||||
Name: "reviewType",
|
||||
Value: "Approve",
|
||||
},
|
||||
})
|
||||
//nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt
|
||||
as.Stub([]*prompt.QuestionStub{
|
||||
{
|
||||
Name: "body",
|
||||
Value: "cool story",
|
||||
},
|
||||
})
|
||||
//nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt
|
||||
as.Stub([]*prompt.QuestionStub{
|
||||
{
|
||||
Name: "confirm",
|
||||
Value: true,
|
||||
},
|
||||
})
|
||||
|
||||
output, err := runCommand(http, nil, true, "")
|
||||
output, err := runCommand(http, pm, nil, true, "")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, heredoc.Doc(`
|
||||
Got:
|
||||
|
|
@ -314,12 +295,12 @@ func TestPRReview_interactive_no_body(t *testing.T) {
|
|||
|
||||
shared.RunCommandFinder("", &api.PullRequest{ID: "THE-ID", Number: 123}, ghrepo.New("OWNER", "REPO"))
|
||||
|
||||
as := prompt.NewAskStubber(t)
|
||||
pm := &prompter.PrompterMock{
|
||||
SelectFunc: func(_, _ string, _ []string) (int, error) { return 2, nil },
|
||||
MarkdownEditorFunc: func(_, _ string, _ bool) (string, error) { return "", nil },
|
||||
}
|
||||
|
||||
as.StubPrompt("What kind of review do you want to give?").AnswerWith("Request changes")
|
||||
as.StubPrompt("Review body").AnswerWith("")
|
||||
|
||||
_, err := runCommand(http, nil, true, "")
|
||||
_, err := runCommand(http, pm, nil, true, "")
|
||||
assert.EqualError(t, err, "this type of review cannot be blank")
|
||||
}
|
||||
|
||||
|
|
@ -338,33 +319,13 @@ func TestPRReview_interactive_blank_approve(t *testing.T) {
|
|||
}),
|
||||
)
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
|
||||
as, teardown := prompt.InitAskStubber()
|
||||
defer teardown()
|
||||
pm := &prompter.PrompterMock{
|
||||
SelectFunc: func(_, _ string, _ []string) (int, error) { return 1, nil },
|
||||
MarkdownEditorFunc: func(_, defVal string, _ bool) (string, error) { return defVal, nil },
|
||||
ConfirmFunc: func(_ string, _ bool) (bool, error) { return true, nil },
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt
|
||||
as.Stub([]*prompt.QuestionStub{
|
||||
{
|
||||
Name: "reviewType",
|
||||
Value: "Approve",
|
||||
},
|
||||
})
|
||||
//nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt
|
||||
as.Stub([]*prompt.QuestionStub{
|
||||
{
|
||||
Name: "body",
|
||||
Default: true,
|
||||
},
|
||||
})
|
||||
//nolint:staticcheck // SA1019: as.Stub is deprecated: use StubPrompt
|
||||
as.Stub([]*prompt.QuestionStub{
|
||||
{
|
||||
Name: "confirm",
|
||||
Value: true,
|
||||
},
|
||||
})
|
||||
|
||||
output, err := runCommand(http, nil, true, "")
|
||||
output, err := runCommand(http, pm, nil, true, "")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "", output.String())
|
||||
assert.Equal(t, "✓ Approved pull request #123\n", output.Stderr())
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ func confirmSubmission(allowPreview, allowMetadata, allowDraft, isDraft bool) (A
|
|||
},
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err := prompt.SurveyAsk(confirmQs, &confirmAnswers)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("could not prompt: %w", err)
|
||||
|
|
@ -122,6 +123,7 @@ func BodySurvey(state *IssueMetadataState, templateContent, editorCommand string
|
|||
},
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err := prompt.SurveyAsk(qs, state)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -148,6 +150,7 @@ func TitleSurvey(state *IssueMetadataState) error {
|
|||
},
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err := prompt.SurveyAsk(qs, state)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -197,6 +200,7 @@ func MetadataSurvey(io *iostreams.IOStreams, baseRepo ghrepo.Interface, fetcher
|
|||
}
|
||||
extraFieldsOptions = append(extraFieldsOptions, "Assignees", "Labels", "Projects", "Milestone")
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err := prompt.SurveyAsk([]*survey.Question{
|
||||
{
|
||||
Name: "metadata",
|
||||
|
|
@ -327,6 +331,7 @@ func MetadataSurvey(io *iostreams.IOStreams, baseRepo ghrepo.Interface, fetcher
|
|||
Milestone string
|
||||
}{}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err = prompt.SurveyAsk(mqs, &values)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ func (m *templateManager) Choose() (Template, error) {
|
|||
}
|
||||
|
||||
var selectedOption int
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "Choose a template",
|
||||
Options: append(names, blankOption),
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ func TestTemplateManager_hasAPI(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "LEGACY", string(m.LegacyBody()))
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("Choose a template").
|
||||
AssertOptions([]string{"Bug report", "Feature request", "Open a blank issue"}).
|
||||
|
|
@ -93,6 +94,7 @@ func TestTemplateManager_hasAPI_PullRequest(t *testing.T) {
|
|||
|
||||
assert.Equal(t, "LEGACY", string(m.LegacyBody()))
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("Choose a template").
|
||||
AssertOptions([]string{"bug_pr.md", "feature_pr.md", "Open a blank pull request"}).
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ func createRun(opts *CreateOptions) error {
|
|||
Options: options,
|
||||
Default: options[0],
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(q, &tag)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
|
|
@ -209,6 +210,7 @@ func createRun(opts *CreateOptions) error {
|
|||
q := &survey.Input{
|
||||
Message: "Tag name",
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(q, &opts.TagName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
|
|
@ -309,6 +311,7 @@ func createRun(opts *CreateOptions) error {
|
|||
},
|
||||
},
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err = prompt.SurveyAsk(qs, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
|
|
@ -373,6 +376,7 @@ func createRun(opts *CreateOptions) error {
|
|||
},
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err = prompt.SurveyAsk(qs, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
|
|
|
|||
|
|
@ -851,6 +851,7 @@ func Test_createRun_interactive(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ func deleteAssetRun(opts *DeleteAssetOptions) error {
|
|||
|
||||
if !opts.SkipConfirm && opts.IO.CanPrompt() {
|
||||
var confirmed bool
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: fmt.Sprintf("Delete asset %s in release %s in %s?", opts.AssetName, release.TagName, ghrepo.FullName(baseRepo)),
|
||||
Default: true,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ func deleteRun(opts *DeleteOptions) error {
|
|||
|
||||
if !opts.SkipConfirm && opts.IO.CanPrompt() {
|
||||
var confirmed bool
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: fmt.Sprintf("Delete release %s in %s?", release.TagName, ghrepo.FullName(baseRepo)),
|
||||
Default: true,
|
||||
|
|
|
|||
|
|
@ -115,6 +115,7 @@ func archiveRun(opts *ArchiveOptions) error {
|
|||
Message: fmt.Sprintf("Archive %s?", fullName),
|
||||
Default: false,
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(p, &opts.Confirmed)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prompt: %w", err)
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ func createRun(opts *CreateOptions) error {
|
|||
"Create a new repository on GitHub from scratch",
|
||||
"Push an existing local repository to GitHub",
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
if err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "What would you like to do?",
|
||||
Options: modeOptions,
|
||||
|
|
@ -353,6 +354,7 @@ func createFromScratch(opts *CreateOptions) error {
|
|||
Message: "Clone the new repository locally?",
|
||||
Default: true,
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(cloneQuestion, &opts.Clone)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -507,6 +509,7 @@ func createFromLocal(opts *CreateOptions) error {
|
|||
Message: `Add a remote?`,
|
||||
Default: true,
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(remoteQuesiton, &addRemote)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -520,6 +523,7 @@ func createFromLocal(opts *CreateOptions) error {
|
|||
Message: "What should the new remote be called?",
|
||||
Default: "origin",
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(pushQuestion, &baseRemote)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -536,6 +540,7 @@ func createFromLocal(opts *CreateOptions) error {
|
|||
Message: fmt.Sprintf(`Would you like to push commits from the current branch to %q?`, baseRemote),
|
||||
Default: true,
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(pushQuestion, &opts.Push)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -684,6 +689,7 @@ func interactiveGitIgnore(client *http.Client, hostname string) (string, error)
|
|||
}
|
||||
|
||||
addGitIgnoreSurvey = append(addGitIgnoreSurvey, addGitIgnoreQuestion)
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err := prompt.SurveyAsk(addGitIgnoreSurvey, &addGitIgnore)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
@ -706,6 +712,7 @@ func interactiveGitIgnore(client *http.Client, hostname string) (string, error)
|
|||
},
|
||||
}
|
||||
gitIg = append(gitIg, gitIgnoreQuestion)
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err = prompt.SurveyAsk(gitIg, &wantedIgnoreTemplate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
@ -730,6 +737,7 @@ func interactiveLicense(client *http.Client, hostname string) (string, error) {
|
|||
}
|
||||
|
||||
addLicenseSurvey = append(addLicenseSurvey, addLicenseQuestion)
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err := prompt.SurveyAsk(addLicenseSurvey, &addLicense)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
@ -757,6 +765,7 @@ func interactiveLicense(client *http.Client, hostname string) (string, error) {
|
|||
},
|
||||
}
|
||||
licenseQs = append(licenseQs, licenseQuestion)
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err = prompt.SurveyAsk(licenseQs, &wantedLicense)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
@ -794,6 +803,7 @@ func interactiveRepoInfo(defaultName string) (string, string, string, error) {
|
|||
RepoVisibility string
|
||||
}{}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err := prompt.SurveyAsk(qs, &answer)
|
||||
if err != nil {
|
||||
return "", "", "", err
|
||||
|
|
@ -808,6 +818,7 @@ func interactiveSource() (string, error) {
|
|||
Message: "Path to local repository",
|
||||
Default: "."}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(sourcePrompt, &sourcePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
@ -823,6 +834,7 @@ func confirmSubmission(repoWithOwner, visibility string) error {
|
|||
var answer struct {
|
||||
ConfirmSubmit bool
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err := prompt.SurveyAsk([]*survey.Question{{
|
||||
Name: "confirmSubmit",
|
||||
Prompt: &survey.Confirm{
|
||||
|
|
|
|||
|
|
@ -8,10 +8,9 @@ import (
|
|||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
@ -19,6 +18,7 @@ import (
|
|||
type DeleteOptions struct {
|
||||
HttpClient func() (*http.Client, error)
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
Prompter prompter.Prompter
|
||||
IO *iostreams.IOStreams
|
||||
RepoArg string
|
||||
Confirmed bool
|
||||
|
|
@ -29,6 +29,7 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co
|
|||
IO: f.IOStreams,
|
||||
HttpClient: f.HttpClient,
|
||||
BaseRepo: f.BaseRepo,
|
||||
Prompter: f.Prompter,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
|
|
@ -91,19 +92,13 @@ func deleteRun(opts *DeleteOptions) error {
|
|||
fullName := ghrepo.FullName(toDelete)
|
||||
|
||||
if !opts.Confirmed {
|
||||
var valid string
|
||||
err := prompt.SurveyAskOne(
|
||||
&survey.Input{Message: fmt.Sprintf("Type %s to confirm deletion:", fullName)},
|
||||
&valid,
|
||||
survey.WithValidator(
|
||||
func(val interface{}) error {
|
||||
if str := val.(string); !strings.EqualFold(str, fullName) {
|
||||
return fmt.Errorf("You entered %s", str)
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
result, err := opts.Prompter.Input(
|
||||
fmt.Sprintf("Type %s to confirm deletion:", fullName), "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
return err
|
||||
}
|
||||
if !strings.EqualFold(result, fullName) {
|
||||
return fmt.Errorf("You entered %s", result)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"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"
|
||||
)
|
||||
|
|
@ -77,25 +77,24 @@ func TestNewCmdDelete(t *testing.T) {
|
|||
|
||||
func Test_deleteRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tty bool
|
||||
opts *DeleteOptions
|
||||
httpStubs func(*httpmock.Registry)
|
||||
askStubs func(*prompt.AskStubber)
|
||||
wantStdout string
|
||||
wantErr bool
|
||||
errMsg string
|
||||
name string
|
||||
tty bool
|
||||
opts *DeleteOptions
|
||||
httpStubs func(*httpmock.Registry)
|
||||
prompterStubs func(*prompter.PrompterMock)
|
||||
wantStdout string
|
||||
wantErr bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "prompting confirmation tty",
|
||||
tty: true,
|
||||
opts: &DeleteOptions{RepoArg: "OWNER/REPO"},
|
||||
wantStdout: "✓ Deleted repository OWNER/REPO\n",
|
||||
askStubs: func(q *prompt.AskStubber) {
|
||||
// TODO: survey stubber doesn't have WithValidator support
|
||||
// so this always passes regardless of prompt input
|
||||
//nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt
|
||||
q.StubOne("OWNER/REPO")
|
||||
prompterStubs: func(p *prompter.PrompterMock) {
|
||||
p.InputFunc = func(_, _ string) (string, error) {
|
||||
return "OWNER/REPO", nil
|
||||
}
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
|
|
@ -108,9 +107,10 @@ func Test_deleteRun(t *testing.T) {
|
|||
tty: true,
|
||||
opts: &DeleteOptions{},
|
||||
wantStdout: "✓ Deleted repository OWNER/REPO\n",
|
||||
askStubs: func(q *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt
|
||||
q.StubOne("OWNER/REPO")
|
||||
prompterStubs: func(p *prompter.PrompterMock) {
|
||||
p.InputFunc = func(_, _ string) (string, error) {
|
||||
return "OWNER/REPO", nil
|
||||
}
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
|
|
@ -135,9 +135,10 @@ func Test_deleteRun(t *testing.T) {
|
|||
opts: &DeleteOptions{RepoArg: "REPO"},
|
||||
wantStdout: "✓ Deleted repository OWNER/REPO\n",
|
||||
tty: true,
|
||||
askStubs: func(q *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: q.StubOne is deprecated: use StubPrompt
|
||||
q.StubOne("OWNER/REPO")
|
||||
prompterStubs: func(p *prompter.PrompterMock) {
|
||||
p.InputFunc = func(_, _ string) (string, error) {
|
||||
return "OWNER/REPO", nil
|
||||
}
|
||||
},
|
||||
httpStubs: func(reg *httpmock.Registry) {
|
||||
reg.Register(
|
||||
|
|
@ -150,12 +151,11 @@ func Test_deleteRun(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
|
||||
q, teardown := prompt.InitAskStubber()
|
||||
defer teardown()
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(q)
|
||||
pm := &prompter.PrompterMock{}
|
||||
if tt.prompterStubs != nil {
|
||||
tt.prompterStubs(pm)
|
||||
}
|
||||
tt.opts.Prompter = pm
|
||||
|
||||
tt.opts.BaseRepo = func() (ghrepo.Interface, error) {
|
||||
return ghrepo.New("OWNER", "REPO"), nil
|
||||
|
|
|
|||
|
|
@ -282,6 +282,7 @@ func interactiveChoice(r *api.Repository) ([]string, error) {
|
|||
options = append(options, optionAllowForking)
|
||||
}
|
||||
var answers []string
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.MultiSelect{
|
||||
Message: "What do you want to edit?",
|
||||
Options: options,
|
||||
|
|
@ -301,6 +302,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
switch c {
|
||||
case optionDescription:
|
||||
opts.Edits.Description = &r.Description
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Input{
|
||||
Message: "Description of the repository",
|
||||
Default: r.Description,
|
||||
|
|
@ -310,6 +312,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
case optionHomePageURL:
|
||||
opts.Edits.Homepage = &r.HomepageURL
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Input{
|
||||
Message: "Repository home page URL",
|
||||
Default: r.HomepageURL,
|
||||
|
|
@ -319,6 +322,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
case optionTopics:
|
||||
var addTopics string
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Input{
|
||||
Message: "Add topics?(csv format)",
|
||||
}, &addTopics)
|
||||
|
|
@ -330,6 +334,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
|
||||
if len(opts.topicsCache) > 0 {
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.MultiSelect{
|
||||
Message: "Remove Topics",
|
||||
Options: opts.topicsCache,
|
||||
|
|
@ -340,6 +345,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
case optionDefaultBranchName:
|
||||
opts.Edits.DefaultBranch = &r.DefaultBranchRef.Name
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Input{
|
||||
Message: "Default branch name",
|
||||
Default: r.DefaultBranchRef.Name,
|
||||
|
|
@ -349,6 +355,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
case optionWikis:
|
||||
opts.Edits.EnableWiki = &r.HasWikiEnabled
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: "Enable Wikis?",
|
||||
Default: r.HasWikiEnabled,
|
||||
|
|
@ -358,6 +365,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
case optionIssues:
|
||||
opts.Edits.EnableIssues = &r.HasIssuesEnabled
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: "Enable Issues?",
|
||||
Default: r.HasIssuesEnabled,
|
||||
|
|
@ -367,6 +375,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
case optionProjects:
|
||||
opts.Edits.EnableProjects = &r.HasProjectsEnabled
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: "Enable Projects?",
|
||||
Default: r.HasProjectsEnabled,
|
||||
|
|
@ -376,6 +385,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
case optionVisibility:
|
||||
opts.Edits.Visibility = &r.Visibility
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "Visibility",
|
||||
Options: []string{"public", "private", "internal"},
|
||||
|
|
@ -396,6 +406,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
if r.RebaseMergeAllowed {
|
||||
defaultMergeOptions = append(defaultMergeOptions, allowRebaseMerge)
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.MultiSelect{
|
||||
Message: "Allowed merge strategies",
|
||||
Default: defaultMergeOptions,
|
||||
|
|
@ -415,6 +426,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
|
||||
opts.Edits.EnableAutoMerge = &r.AutoMergeAllowed
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: "Enable Auto Merge?",
|
||||
Default: r.AutoMergeAllowed,
|
||||
|
|
@ -424,6 +436,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
|
||||
opts.Edits.DeleteBranchOnMerge = &r.DeleteBranchOnMerge
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: "Automatically delete head branches after merging?",
|
||||
Default: r.DeleteBranchOnMerge,
|
||||
|
|
@ -433,6 +446,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
case optionTemplateRepo:
|
||||
opts.Edits.IsTemplate = &r.IsTemplate
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: "Convert into a template repository?",
|
||||
Default: r.IsTemplate,
|
||||
|
|
@ -442,6 +456,7 @@ func interactiveRepoEdit(opts *EditOptions, r *api.Repository) error {
|
|||
}
|
||||
case optionAllowForking:
|
||||
opts.Edits.AllowForking = &r.ForkingAllowed
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err = prompt.SurveyAskOne(&survey.Confirm{
|
||||
Message: "Allow forking (of an organization repository)?",
|
||||
Default: r.ForkingAllowed,
|
||||
|
|
|
|||
|
|
@ -319,6 +319,7 @@ func Test_editRun_interactive(t *testing.T) {
|
|||
opts := &tt.opts
|
||||
opts.HTTPClient = &http.Client{Transport: httpReg}
|
||||
opts.IO = ios
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ func forkRun(opts *ForkOptions) error {
|
|||
|
||||
remoteDesired := opts.Remote
|
||||
if opts.PromptRemote {
|
||||
//nolint:staticcheck // SA1019: prompt.Confirm is deprecated: use Prompter
|
||||
err = prompt.Confirm("Would you like to add a remote for the fork?", &remoteDesired)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prompt: %w", err)
|
||||
|
|
@ -302,6 +303,7 @@ func forkRun(opts *ForkOptions) error {
|
|||
} else {
|
||||
cloneDesired := opts.Clone
|
||||
if opts.PromptClone {
|
||||
//nolint:staticcheck // SA1019: prompt.Confirm is deprecated: use Prompter
|
||||
err = prompt.Confirm("Would you like to clone the fork?", &cloneDesired)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to prompt: %w", err)
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ 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)),
|
||||
|
|
@ -106,6 +107,7 @@ func renameRun(opts *RenameOptions) error {
|
|||
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)
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ func matchAnyPattern(patterns []string, name string) bool {
|
|||
type surveyPrompter struct{}
|
||||
|
||||
func (sp *surveyPrompter) Prompt(message string, options []string, result interface{}) error {
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
return prompt.SurveyAskOne(&survey.MultiSelect{
|
||||
Message: message,
|
||||
Options: options,
|
||||
|
|
|
|||
|
|
@ -356,6 +356,7 @@ func PromptForRun(cs *iostreams.ColorScheme, runs []Run) (string, error) {
|
|||
|
||||
// TODO consider custom filter so it's fuzzier. right now matches start anywhere in string but
|
||||
// become contiguous
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "Select a workflow run",
|
||||
Options: candidates,
|
||||
|
|
|
|||
|
|
@ -446,6 +446,7 @@ func promptForJob(cs *iostreams.ColorScheme, jobs []shared.Job) (*shared.Job, er
|
|||
}
|
||||
|
||||
var selected int
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: "View a specific job in this run?",
|
||||
Options: candidates,
|
||||
|
|
|
|||
|
|
@ -277,6 +277,7 @@ func TestWatchRun(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -373,6 +373,7 @@ func getBody(opts *SetOptions) ([]byte, error) {
|
|||
|
||||
if opts.IO.CanPrompt() {
|
||||
var bodyInput string
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Password{
|
||||
Message: "Paste your secret",
|
||||
}, &bodyInput)
|
||||
|
|
|
|||
|
|
@ -560,6 +560,7 @@ func Test_getBodyPrompt(t *testing.T) {
|
|||
ios.SetStdinTTY(true)
|
||||
ios.SetStdoutTTY(true)
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
as.StubPrompt("Paste your secret").AnswerWith("cool secret")
|
||||
|
||||
|
|
|
|||
|
|
@ -278,6 +278,7 @@ func TestDisableRun(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -327,6 +327,7 @@ func TestEnableRun(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -230,6 +230,7 @@ func collectInputs(yamlContent []byte) (map[string]string, error) {
|
|||
inputAnswer := InputAnswer{
|
||||
providedInputs: providedInputs,
|
||||
}
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAsk is deprecated: use Prompter
|
||||
err = prompt.SurveyAsk(qs, &inputAnswer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -632,6 +632,7 @@ jobs:
|
|||
}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
|
||||
as := prompt.NewAskStubber(t)
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ func SelectWorkflow(workflows []Workflow, promptMsg string, states []WorkflowSta
|
|||
|
||||
var selected int
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
|
||||
err := prompt.SurveyAskOne(&survey.Select{
|
||||
Message: promptMsg,
|
||||
Options: candidates,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/cli/cli/v2/context"
|
||||
"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/pkg/extensions"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
)
|
||||
|
|
@ -20,6 +21,7 @@ type Browser interface {
|
|||
type Factory struct {
|
||||
IOStreams *iostreams.IOStreams
|
||||
Browser Browser
|
||||
Prompter prompter.Prompter
|
||||
|
||||
HttpClient func() (*http.Client, error)
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package prompt
|
|||
|
||||
import "github.com/AlecAivazis/survey/v2"
|
||||
|
||||
// Deprecated: use PrompterMock
|
||||
func StubConfirm(result bool) func() {
|
||||
orig := Confirm
|
||||
Confirm = func(_ string, r *bool) error {
|
||||
|
|
@ -13,6 +14,7 @@ func StubConfirm(result bool) func() {
|
|||
}
|
||||
}
|
||||
|
||||
// Deprecated: use Prompter
|
||||
var Confirm = func(prompt string, result *bool) error {
|
||||
p := &survey.Confirm{
|
||||
Message: prompt,
|
||||
|
|
@ -21,10 +23,12 @@ var Confirm = func(prompt string, result *bool) error {
|
|||
return SurveyAskOne(p, result)
|
||||
}
|
||||
|
||||
// Deprecated: use Prompter
|
||||
var SurveyAskOne = func(p survey.Prompt, response interface{}, opts ...survey.AskOpt) error {
|
||||
return survey.AskOne(p, response, opts...)
|
||||
}
|
||||
|
||||
// Deprecated: use Prompter
|
||||
var SurveyAsk = func(qs []*survey.Question, response interface{}, opts ...survey.AskOpt) error {
|
||||
return survey.Ask(qs, response, opts...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ type testing interface {
|
|||
Cleanup(func())
|
||||
}
|
||||
|
||||
// Deprecated: use PrompterMock
|
||||
func NewAskStubber(t testing) *AskStubber {
|
||||
as, teardown := InitAskStubber()
|
||||
t.Cleanup(func() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue