Merge pull request #7302 from cli/run-prompts
replace prompts in `gh run` commands
This commit is contained in:
commit
79128a23c8
14 changed files with 263 additions and 255 deletions
|
|
@ -14,7 +14,7 @@ import (
|
|||
//go:generate moq -rm -out prompter_mock.go . Prompter
|
||||
type Prompter interface {
|
||||
Select(string, string, []string) (int, error)
|
||||
MultiSelect(string, string, []string) ([]string, error)
|
||||
MultiSelect(string, []string, []string) ([]int, error)
|
||||
Input(string, string) (string, error)
|
||||
InputHostname() (string, error)
|
||||
Password(string) (string, error)
|
||||
|
|
@ -86,7 +86,7 @@ func (p *surveyPrompter) Select(message, defaultValue string, options []string)
|
|||
return
|
||||
}
|
||||
|
||||
func (p *surveyPrompter) MultiSelect(message, defaultValue string, options []string) (result []string, err error) {
|
||||
func (p *surveyPrompter) MultiSelect(message string, defaultValues, options []string) (result []int, err error) {
|
||||
q := &survey.MultiSelect{
|
||||
Message: message,
|
||||
Options: options,
|
||||
|
|
@ -94,8 +94,17 @@ func (p *surveyPrompter) MultiSelect(message, defaultValue string, options []str
|
|||
Filter: LatinMatchingFilter,
|
||||
}
|
||||
|
||||
if defaultValue != "" {
|
||||
q.Default = defaultValue
|
||||
if len(defaultValues) > 0 {
|
||||
// TODO I don't actually know that this is needed, just being extra cautious
|
||||
validatedDefault := []string{}
|
||||
for _, x := range defaultValues {
|
||||
for _, y := range options {
|
||||
if x == y {
|
||||
validatedDefault = append(validatedDefault, x)
|
||||
}
|
||||
}
|
||||
}
|
||||
q.Default = validatedDefault
|
||||
}
|
||||
|
||||
err = p.ask(q, &result)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ var _ Prompter = &PrompterMock{}
|
|||
// MarkdownEditorFunc: func(s1 string, s2 string, b bool) (string, error) {
|
||||
// panic("mock out the MarkdownEditor method")
|
||||
// },
|
||||
// MultiSelectFunc: func(s1 string, s2 string, strings []string) ([]string, error) {
|
||||
// MultiSelectFunc: func(s string, strings1 []string, strings2 []string) ([]int, error) {
|
||||
// panic("mock out the MultiSelect method")
|
||||
// },
|
||||
// PasswordFunc: func(s string) (string, error) {
|
||||
|
|
@ -70,7 +70,7 @@ type PrompterMock struct {
|
|||
MarkdownEditorFunc func(s1 string, s2 string, b bool) (string, error)
|
||||
|
||||
// MultiSelectFunc mocks the MultiSelect method.
|
||||
MultiSelectFunc func(s1 string, s2 string, strings []string) ([]string, error)
|
||||
MultiSelectFunc func(s string, strings1 []string, strings2 []string) ([]int, error)
|
||||
|
||||
// PasswordFunc mocks the Password method.
|
||||
PasswordFunc func(s string) (string, error)
|
||||
|
|
@ -116,12 +116,12 @@ type PrompterMock struct {
|
|||
}
|
||||
// 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
|
||||
// S is the s argument value.
|
||||
S string
|
||||
// Strings1 is the strings1 argument value.
|
||||
Strings1 []string
|
||||
// Strings2 is the strings2 argument value.
|
||||
Strings2 []string
|
||||
}
|
||||
// Password holds details about calls to the Password method.
|
||||
Password []struct {
|
||||
|
|
@ -348,23 +348,23 @@ func (mock *PrompterMock) MarkdownEditorCalls() []struct {
|
|||
}
|
||||
|
||||
// MultiSelect calls MultiSelectFunc.
|
||||
func (mock *PrompterMock) MultiSelect(s1 string, s2 string, strings []string) ([]string, error) {
|
||||
func (mock *PrompterMock) MultiSelect(s string, strings1 []string, strings2 []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
|
||||
S string
|
||||
Strings1 []string
|
||||
Strings2 []string
|
||||
}{
|
||||
S1: s1,
|
||||
S2: s2,
|
||||
Strings: strings,
|
||||
S: s,
|
||||
Strings1: strings1,
|
||||
Strings2: strings2,
|
||||
}
|
||||
mock.lockMultiSelect.Lock()
|
||||
mock.calls.MultiSelect = append(mock.calls.MultiSelect, callInfo)
|
||||
mock.lockMultiSelect.Unlock()
|
||||
return mock.MultiSelectFunc(s1, s2, strings)
|
||||
return mock.MultiSelectFunc(s, strings1, strings2)
|
||||
}
|
||||
|
||||
// MultiSelectCalls gets all the calls that were made to MultiSelect.
|
||||
|
|
@ -372,14 +372,14 @@ func (mock *PrompterMock) MultiSelect(s1 string, s2 string, strings []string) ([
|
|||
//
|
||||
// len(mockedPrompter.MultiSelectCalls())
|
||||
func (mock *PrompterMock) MultiSelectCalls() []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
Strings []string
|
||||
S string
|
||||
Strings1 []string
|
||||
Strings2 []string
|
||||
} {
|
||||
var calls []struct {
|
||||
S1 string
|
||||
S2 string
|
||||
Strings []string
|
||||
S string
|
||||
Strings1 []string
|
||||
Strings2 []string
|
||||
}
|
||||
mock.lockMultiSelect.RLock()
|
||||
calls = mock.calls.MultiSelect
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ type ConfirmStub struct {
|
|||
type MultiSelectStub struct {
|
||||
Prompt string
|
||||
ExpectedOpts []string
|
||||
Fn func(string, string, []string) ([]string, error)
|
||||
Fn func(string, []string, []string) ([]int, error)
|
||||
}
|
||||
|
||||
type InputHostnameStub struct {
|
||||
|
|
@ -84,8 +84,6 @@ type MockPrompter struct {
|
|||
ConfirmDeletionStubs []ConfirmDeletionStub
|
||||
}
|
||||
|
||||
// TODO thread safety
|
||||
|
||||
func NewMockPrompter(t *testing.T) *MockPrompter {
|
||||
m := &MockPrompter{
|
||||
t: t,
|
||||
|
|
@ -120,17 +118,17 @@ func NewMockPrompter(t *testing.T) *MockPrompter {
|
|||
return s.Fn(p, d, opts)
|
||||
}
|
||||
|
||||
m.MultiSelectFunc = func(p, d string, opts []string) ([]string, error) {
|
||||
m.MultiSelectFunc = func(p string, d, opts []string) ([]int, error) {
|
||||
var s MultiSelectStub
|
||||
if len(m.SelectStubs) > 0 {
|
||||
if len(m.MultiSelectStubs) > 0 {
|
||||
s = m.MultiSelectStubs[0]
|
||||
m.SelectStubs = m.SelectStubs[1:len(m.SelectStubs)]
|
||||
m.MultiSelectStubs = m.MultiSelectStubs[1:len(m.MultiSelectStubs)]
|
||||
} else {
|
||||
return []string{}, NoSuchPromptErr(p)
|
||||
return []int{}, NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
if s.Prompt != p {
|
||||
return []string{}, NoSuchPromptErr(p)
|
||||
return []int{}, NoSuchPromptErr(p)
|
||||
}
|
||||
|
||||
AssertOptions(m.t, s.ExpectedOpts, opts)
|
||||
|
|
@ -240,7 +238,7 @@ func (m *MockPrompter) RegisterSelect(prompt string, opts []string, stub func(_,
|
|||
Fn: stub})
|
||||
}
|
||||
|
||||
func (m *MockPrompter) RegisterMultiSelect(prompt string, opts []string, stub func(_, _ string, _ []string) ([]string, error)) {
|
||||
func (m *MockPrompter) RegisterMultiSelect(prompt string, d, opts []string, stub func(_ string, _, _ []string) ([]int, error)) {
|
||||
m.MultiSelectStubs = append(m.MultiSelectStubs, MultiSelectStub{
|
||||
Prompt: prompt,
|
||||
ExpectedOpts: opts,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ type CancelOptions struct {
|
|||
HttpClient func() (*http.Client, error)
|
||||
IO *iostreams.IOStreams
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
Prompter shared.Prompter
|
||||
|
||||
Prompt bool
|
||||
|
||||
|
|
@ -27,6 +28,7 @@ func NewCmdCancel(f *cmdutil.Factory, runF func(*CancelOptions) error) *cobra.Co
|
|||
opts := &CancelOptions{
|
||||
IO: f.IOStreams,
|
||||
HttpClient: f.HttpClient,
|
||||
Prompter: f.Prompter,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
|
|
@ -83,11 +85,10 @@ func runCancel(opts *CancelOptions) error {
|
|||
if len(runs) == 0 {
|
||||
return fmt.Errorf("found no in progress runs to cancel")
|
||||
}
|
||||
runID, err = shared.PromptForRun(cs, runs)
|
||||
if err != nil {
|
||||
if runID, err = shared.SelectRun(opts.Prompter, cs, runs); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO silly stopgap until dust settles and PromptForRun can just return a run
|
||||
// TODO silly stopgap until dust settles and SelectRun can just return a run
|
||||
for _, r := range runs {
|
||||
if fmt.Sprintf("%d", r.ID) == runID {
|
||||
run = &r
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmd/run/shared"
|
||||
workflowShared "github.com/cli/cli/v2/pkg/cmd/workflow/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/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -86,13 +86,13 @@ func TestRunCancel(t *testing.T) {
|
|||
inProgressRun := shared.TestRun(1234, shared.InProgress, "")
|
||||
completedRun := shared.TestRun(4567, shared.Completed, shared.Failure)
|
||||
tests := []struct {
|
||||
name string
|
||||
httpStubs func(*httpmock.Registry)
|
||||
askStubs func(*prompt.AskStubber)
|
||||
opts *CancelOptions
|
||||
wantErr bool
|
||||
wantOut string
|
||||
errMsg string
|
||||
name string
|
||||
httpStubs func(*httpmock.Registry)
|
||||
promptStubs func(*prompter.MockPrompter)
|
||||
opts *CancelOptions
|
||||
wantErr bool
|
||||
wantOut string
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "cancel run",
|
||||
|
|
@ -194,9 +194,12 @@ func TestRunCancel(t *testing.T) {
|
|||
httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/1234/cancel"),
|
||||
httpmock.StatusStringResponse(202, "{}"))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(0)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"* cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "* cool commit, CI (trunk) Feb 23, 2021")
|
||||
})
|
||||
},
|
||||
wantOut: "✓ Request to cancel workflow submitted.\n",
|
||||
},
|
||||
|
|
@ -217,11 +220,10 @@ func TestRunCancel(t *testing.T) {
|
|||
return ghrepo.FromFullName("OWNER/REPO")
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
|
||||
as, teardown := prompt.InitAskStubber()
|
||||
defer teardown()
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
pm := prompter.NewMockPrompter(t)
|
||||
tt.opts.Prompter = pm
|
||||
if tt.promptStubs != nil {
|
||||
tt.promptStubs(pm)
|
||||
}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -5,12 +5,10 @@ import (
|
|||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/pkg/cmd/run/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
"github.com/cli/cli/v2/pkg/set"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
@ -18,7 +16,7 @@ import (
|
|||
type DownloadOptions struct {
|
||||
IO *iostreams.IOStreams
|
||||
Platform platform
|
||||
Prompter prompter
|
||||
Prompter iprompter
|
||||
|
||||
DoPrompt bool
|
||||
RunID string
|
||||
|
|
@ -31,13 +29,14 @@ type platform interface {
|
|||
List(runID string) ([]shared.Artifact, error)
|
||||
Download(url string, dir string) error
|
||||
}
|
||||
type prompter interface {
|
||||
Prompt(message string, options []string, result interface{}) error
|
||||
type iprompter interface {
|
||||
MultiSelect(string, []string, []string) ([]int, error)
|
||||
}
|
||||
|
||||
func NewCmdDownload(f *cmdutil.Factory, runF func(*DownloadOptions) error) *cobra.Command {
|
||||
opts := &DownloadOptions{
|
||||
IO: f.IOStreams,
|
||||
IO: f.IOStreams,
|
||||
Prompter: f.Prompter,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
|
|
@ -85,7 +84,6 @@ func NewCmdDownload(f *cmdutil.Factory, runF func(*DownloadOptions) error) *cobr
|
|||
client: httpClient,
|
||||
repo: baseRepo,
|
||||
}
|
||||
opts.Prompter = &surveyPrompter{}
|
||||
|
||||
if runF != nil {
|
||||
return runF(opts)
|
||||
|
|
@ -133,10 +131,14 @@ func runDownload(opts *DownloadOptions) error {
|
|||
if len(options) > 10 {
|
||||
options = options[:10]
|
||||
}
|
||||
err := opts.Prompter.Prompt("Select artifacts to download:", options, &wantNames)
|
||||
if err != nil {
|
||||
var selected []int
|
||||
if selected, err = opts.Prompter.MultiSelect("Select artifacts to download:", nil, options); err != nil {
|
||||
return err
|
||||
}
|
||||
wantNames = []string{}
|
||||
for _, x := range selected {
|
||||
wantNames = append(wantNames, options[x])
|
||||
}
|
||||
if len(wantNames) == 0 {
|
||||
return errors.New("no artifacts selected")
|
||||
}
|
||||
|
|
@ -194,13 +196,3 @@ func matchAnyPattern(patterns []string, name string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
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,
|
||||
}, result)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmd/run/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
|
|
@ -144,11 +145,11 @@ func Test_NewCmdDownload(t *testing.T) {
|
|||
|
||||
func Test_runDownload(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
opts DownloadOptions
|
||||
mockAPI func(*mockPlatform)
|
||||
mockPrompt func(*mockPrompter)
|
||||
wantErr string
|
||||
name string
|
||||
opts DownloadOptions
|
||||
mockAPI func(*mockPlatform)
|
||||
promptStubs func(*prompter.MockPrompter)
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "download non-expired",
|
||||
|
|
@ -281,13 +282,11 @@ func Test_runDownload(t *testing.T) {
|
|||
}, nil)
|
||||
p.On("Download", "http://download.com/artifact2.zip", ".").Return(nil)
|
||||
},
|
||||
mockPrompt: func(p *mockPrompter) {
|
||||
p.On("Prompt", "Select artifacts to download:", []string{"artifact-1", "artifact-2"}, mock.AnythingOfType("*[]string")).
|
||||
Run(func(args mock.Arguments) {
|
||||
result := args.Get(2).(*[]string)
|
||||
*result = []string{"artifact-2"}
|
||||
}).
|
||||
Return(nil)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterMultiSelect("Select artifacts to download:", nil, []string{"artifact-1", "artifact-2"},
|
||||
func(_ string, _, opts []string) ([]int, error) {
|
||||
return []int{1}, nil
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -297,7 +296,12 @@ func Test_runDownload(t *testing.T) {
|
|||
ios, _, stdout, stderr := iostreams.Test()
|
||||
opts.IO = ios
|
||||
opts.Platform = newMockPlatform(t, tt.mockAPI)
|
||||
opts.Prompter = newMockPrompter(t, tt.mockPrompt)
|
||||
|
||||
pm := prompter.NewMockPrompter(t)
|
||||
opts.Prompter = pm
|
||||
if tt.promptStubs != nil {
|
||||
tt.promptStubs(pm)
|
||||
}
|
||||
|
||||
err := runDownload(opts)
|
||||
if tt.wantErr != "" {
|
||||
|
|
@ -337,24 +341,3 @@ func (p *mockPlatform) Download(url string, dir string) error {
|
|||
args := p.Called(url, dir)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
type mockPrompter struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func newMockPrompter(t *testing.T, config func(*mockPrompter)) *mockPrompter {
|
||||
m := &mockPrompter{}
|
||||
m.Test(t)
|
||||
t.Cleanup(func() {
|
||||
m.AssertExpectations(t)
|
||||
})
|
||||
if config != nil {
|
||||
config(m)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (p *mockPrompter) Prompt(msg string, opts []string, res interface{}) error {
|
||||
args := p.Called(msg, opts, res)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ type RerunOptions struct {
|
|||
HttpClient func() (*http.Client, error)
|
||||
IO *iostreams.IOStreams
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
Prompter shared.Prompter
|
||||
|
||||
RunID string
|
||||
OnlyFailed bool
|
||||
|
|
@ -32,6 +33,7 @@ type RerunOptions struct {
|
|||
func NewCmdRerun(f *cmdutil.Factory, runF func(*RerunOptions) error) *cobra.Command {
|
||||
opts := &RerunOptions{
|
||||
IO: f.IOStreams,
|
||||
Prompter: f.Prompter,
|
||||
HttpClient: f.HttpClient,
|
||||
}
|
||||
|
||||
|
|
@ -114,8 +116,7 @@ func runRerun(opts *RerunOptions) error {
|
|||
if len(runs) == 0 {
|
||||
return errors.New("no recent runs have failed; please specify a specific `<run-id>`")
|
||||
}
|
||||
runID, err = shared.PromptForRun(cs, runs)
|
||||
if err != nil {
|
||||
if runID, err = shared.SelectRun(opts.Prompter, cs, runs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmd/run/shared"
|
||||
workflowShared "github.com/cli/cli/v2/pkg/cmd/workflow/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/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -161,15 +161,15 @@ func TestNewCmdRerun(t *testing.T) {
|
|||
|
||||
func TestRerun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
httpStubs func(*httpmock.Registry)
|
||||
askStubs func(*prompt.AskStubber)
|
||||
opts *RerunOptions
|
||||
tty bool
|
||||
wantErr bool
|
||||
errOut string
|
||||
wantOut string
|
||||
wantDebug bool
|
||||
name string
|
||||
httpStubs func(*httpmock.Registry)
|
||||
promptStubs func(*prompter.MockPrompter)
|
||||
opts *RerunOptions
|
||||
tty bool
|
||||
wantErr bool
|
||||
errOut string
|
||||
wantOut string
|
||||
wantDebug bool
|
||||
}{
|
||||
{
|
||||
name: "arg",
|
||||
|
|
@ -336,9 +336,12 @@ func TestRerun(t *testing.T) {
|
|||
httpmock.REST("POST", "repos/OWNER/REPO/actions/runs/1234/rerun"),
|
||||
httpmock.StringResponse("{}"))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(2)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return 2, nil
|
||||
})
|
||||
},
|
||||
wantOut: "✓ Requested rerun of run 1234\n",
|
||||
},
|
||||
|
|
@ -408,11 +411,10 @@ func TestRerun(t *testing.T) {
|
|||
return ghrepo.FromFullName("OWNER/REPO")
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
|
||||
as, teardown := prompt.InitAskStubber()
|
||||
defer teardown()
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
pm := prompter.NewMockPrompter(t)
|
||||
tt.opts.Prompter = pm
|
||||
if tt.promptStubs != nil {
|
||||
tt.promptStubs(pm)
|
||||
}
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -9,15 +9,16 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
workflowShared "github.com/cli/cli/v2/pkg/cmd/workflow/shared"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/prompt"
|
||||
)
|
||||
|
||||
type Prompter interface {
|
||||
Select(string, string, []string) (int, error)
|
||||
}
|
||||
|
||||
const (
|
||||
// Run statuses
|
||||
Queued Status = "queued"
|
||||
|
|
@ -451,7 +452,7 @@ func GetJob(client *api.Client, repo ghrepo.Interface, jobID string) (*Job, erro
|
|||
}
|
||||
|
||||
// SelectRun prompts the user to select a run from a list of runs by using the recommended prompter interface
|
||||
func SelectRun(p prompter.Prompter, cs *iostreams.ColorScheme, runs []Run) (string, error) {
|
||||
func SelectRun(p Prompter, cs *iostreams.ColorScheme, runs []Run) (string, error) {
|
||||
now := time.Now()
|
||||
|
||||
candidates := []string{}
|
||||
|
|
@ -472,36 +473,6 @@ func SelectRun(p prompter.Prompter, cs *iostreams.ColorScheme, runs []Run) (stri
|
|||
return fmt.Sprintf("%d", runs[selected].ID), nil
|
||||
}
|
||||
|
||||
// TODO: this should be deprecated in favor of SelectRun
|
||||
func PromptForRun(cs *iostreams.ColorScheme, runs []Run) (string, error) {
|
||||
var selected int
|
||||
now := time.Now()
|
||||
|
||||
candidates := []string{}
|
||||
|
||||
for _, run := range runs {
|
||||
symbol, _ := Symbol(cs, run.Status, run.Conclusion)
|
||||
candidates = append(candidates,
|
||||
// TODO truncate commit message, long ones look terrible
|
||||
fmt.Sprintf("%s %s, %s (%s) %s", symbol, run.Title(), run.WorkflowName(), run.HeadBranch, preciseAgo(now, run.StartedTime())))
|
||||
}
|
||||
|
||||
// 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,
|
||||
PageSize: 10,
|
||||
}, &selected)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%d", runs[selected].ID), nil
|
||||
}
|
||||
|
||||
func GetRun(client *api.Client, repo ghrepo.Interface, runID string, attempt uint64) (*Run, error) {
|
||||
var result Run
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/browser"
|
||||
|
|
@ -24,7 +23,6 @@ import (
|
|||
"github.com/cli/cli/v2/pkg/cmd/run/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"
|
||||
)
|
||||
|
||||
|
|
@ -65,6 +63,7 @@ type ViewOptions struct {
|
|||
IO *iostreams.IOStreams
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
Browser browser.Browser
|
||||
Prompter shared.Prompter
|
||||
RunLogCache runLogCache
|
||||
|
||||
RunID string
|
||||
|
|
@ -86,6 +85,7 @@ func NewCmdView(f *cmdutil.Factory, runF func(*ViewOptions) error) *cobra.Comman
|
|||
opts := &ViewOptions{
|
||||
IO: f.IOStreams,
|
||||
HttpClient: f.HttpClient,
|
||||
Prompter: f.Prompter,
|
||||
Now: time.Now,
|
||||
Browser: f.Browser,
|
||||
RunLogCache: rlc{},
|
||||
|
|
@ -205,7 +205,7 @@ func runView(opts *ViewOptions) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to get runs: %w", err)
|
||||
}
|
||||
runID, err = shared.PromptForRun(cs, runs.WorkflowRuns)
|
||||
runID, err = shared.SelectRun(opts.Prompter, cs, runs.WorkflowRuns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -228,7 +228,7 @@ func runView(opts *ViewOptions) error {
|
|||
}
|
||||
|
||||
if opts.Prompt && len(jobs) > 1 {
|
||||
selectedJob, err = promptForJob(cs, jobs)
|
||||
selectedJob, err = promptForJob(opts.Prompter, cs, jobs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -459,20 +459,14 @@ func getRunLog(cache runLogCache, httpClient *http.Client, repo ghrepo.Interface
|
|||
return cache.Open(filepath)
|
||||
}
|
||||
|
||||
func promptForJob(cs *iostreams.ColorScheme, jobs []shared.Job) (*shared.Job, error) {
|
||||
func promptForJob(prompter shared.Prompter, cs *iostreams.ColorScheme, jobs []shared.Job) (*shared.Job, error) {
|
||||
candidates := []string{"View all jobs in this run"}
|
||||
for _, job := range jobs {
|
||||
symbol, _ := shared.Symbol(cs, job.Status, job.Conclusion)
|
||||
candidates = append(candidates, fmt.Sprintf("%s %s", symbol, job.Name))
|
||||
}
|
||||
|
||||
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,
|
||||
PageSize: 12,
|
||||
}, &selected)
|
||||
selected, err := prompter.Select("View a specific job in this run?", "", candidates)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ import (
|
|||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/internal/browser"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmd/run/shared"
|
||||
workflowShared "github.com/cli/cli/v2/pkg/cmd/workflow/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/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -169,15 +169,15 @@ func TestNewCmdView(t *testing.T) {
|
|||
|
||||
func TestViewRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
httpStubs func(*httpmock.Registry)
|
||||
askStubs func(*prompt.AskStubber)
|
||||
opts *ViewOptions
|
||||
tty bool
|
||||
wantErr bool
|
||||
wantOut string
|
||||
browsedURL string
|
||||
errMsg string
|
||||
name string
|
||||
httpStubs func(*httpmock.Registry)
|
||||
promptStubs func(*prompter.MockPrompter)
|
||||
opts *ViewOptions
|
||||
tty bool
|
||||
wantErr bool
|
||||
wantOut string
|
||||
browsedURL string
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "associate with PR",
|
||||
|
|
@ -532,9 +532,12 @@ func TestViewRun(t *testing.T) {
|
|||
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
|
||||
httpmock.JSONResponse(shared.TestWorkflow))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(2)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "✓ cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "✓ cool commit, CI (trunk) Feb 23, 2021")
|
||||
})
|
||||
},
|
||||
opts: &ViewOptions{
|
||||
Prompt: true,
|
||||
|
|
@ -579,11 +582,17 @@ func TestViewRun(t *testing.T) {
|
|||
},
|
||||
}))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(2)
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(1)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "✓ cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "✓ cool commit, CI (trunk) Feb 23, 2021")
|
||||
})
|
||||
pm.RegisterSelect("View a specific job in this run?",
|
||||
[]string{"View all jobs in this run", "✓ cool job", "X sad job"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "✓ cool job")
|
||||
})
|
||||
},
|
||||
wantOut: coolJobRunLogOutput,
|
||||
},
|
||||
|
|
@ -626,11 +635,17 @@ func TestViewRun(t *testing.T) {
|
|||
},
|
||||
}))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(2)
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(1)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "✓ cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "✓ cool commit, CI (trunk) Feb 23, 2021")
|
||||
})
|
||||
pm.RegisterSelect("View a specific job in this run?",
|
||||
[]string{"View all jobs in this run", "✓ cool job", "X sad job"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "✓ cool job")
|
||||
})
|
||||
},
|
||||
wantOut: coolJobRunLogOutput,
|
||||
},
|
||||
|
|
@ -717,11 +732,17 @@ func TestViewRun(t *testing.T) {
|
|||
},
|
||||
}))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(2)
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(0)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "✓ cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "✓ cool commit, CI (trunk) Feb 23, 2021")
|
||||
})
|
||||
pm.RegisterSelect("View a specific job in this run?",
|
||||
[]string{"View all jobs in this run", "✓ cool job", "X sad job"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "View all jobs in this run")
|
||||
})
|
||||
},
|
||||
wantOut: expectedRunLogOutput,
|
||||
},
|
||||
|
|
@ -791,11 +812,17 @@ func TestViewRun(t *testing.T) {
|
|||
},
|
||||
}))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(4)
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(2)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "✓ cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return 4, nil
|
||||
})
|
||||
pm.RegisterSelect("View a specific job in this run?",
|
||||
[]string{"View all jobs in this run", "✓ cool job", "X sad job"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "X sad job")
|
||||
})
|
||||
},
|
||||
wantOut: quuxTheBarfLogOutput,
|
||||
},
|
||||
|
|
@ -838,11 +865,17 @@ func TestViewRun(t *testing.T) {
|
|||
},
|
||||
}))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(4)
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(2)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "✓ cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return 4, nil
|
||||
})
|
||||
pm.RegisterSelect("View a specific job in this run?",
|
||||
[]string{"View all jobs in this run", "✓ cool job", "X sad job"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "X sad job")
|
||||
})
|
||||
},
|
||||
wantOut: quuxTheBarfLogOutput,
|
||||
},
|
||||
|
|
@ -906,11 +939,17 @@ func TestViewRun(t *testing.T) {
|
|||
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
|
||||
httpmock.JSONResponse(shared.TestWorkflow))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(4)
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(0)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "✓ cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return 4, nil
|
||||
})
|
||||
pm.RegisterSelect("View a specific job in this run?",
|
||||
[]string{"View all jobs in this run", "✓ cool job", "X sad job"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "View all jobs in this run")
|
||||
})
|
||||
},
|
||||
wantOut: quuxTheBarfLogOutput,
|
||||
},
|
||||
|
|
@ -1054,11 +1093,17 @@ func TestViewRun(t *testing.T) {
|
|||
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
|
||||
httpmock.JSONResponse(shared.TestWorkflow))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(2)
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(0)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "✓ cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "✓ cool commit, CI (trunk) Feb 23, 2021")
|
||||
})
|
||||
pm.RegisterSelect("View a specific job in this run?",
|
||||
[]string{"View all jobs in this run", "✓ cool job", "X sad job"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "View all jobs in this run")
|
||||
})
|
||||
},
|
||||
wantOut: "\n✓ trunk CI · 3\nTriggered via push about 59 minutes ago\n\nJOBS\n✓ cool job in 4m34s (ID 10)\nX sad job in 4m34s (ID 20)\n ✓ barf the quux\n X quux the barf\n\nANNOTATIONS\nX the job is sad\nsad job: blaze.py#420\n\n\nFor more information about a job, try: gh run view --job=<job-id>\nView this run on GitHub: https://github.com/runs/3\n",
|
||||
},
|
||||
|
|
@ -1099,11 +1144,17 @@ func TestViewRun(t *testing.T) {
|
|||
httpmock.REST("GET", "repos/OWNER/REPO/actions/workflows/123"),
|
||||
httpmock.JSONResponse(shared.TestWorkflow))
|
||||
},
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(2)
|
||||
//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
|
||||
as.StubOne(1)
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"X cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "✓ cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "- cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "* cool commit, CI (trunk) Feb 23, 2021", "X cool commit, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "✓ cool commit, CI (trunk) Feb 23, 2021")
|
||||
})
|
||||
pm.RegisterSelect("View a specific job in this run?",
|
||||
[]string{"View all jobs in this run", "✓ cool job", "X sad job"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "✓ cool job")
|
||||
})
|
||||
},
|
||||
wantOut: "\n✓ trunk CI · 3\nTriggered via push about 59 minutes ago\n\n✓ cool job in 4m34s (ID 10)\n ✓ fob the barz\n ✓ barz the fob\n\nTo see the full job log, try: gh run view --log --job=10\nView this run on GitHub: https://github.com/runs/3\n",
|
||||
},
|
||||
|
|
@ -1211,11 +1262,10 @@ func TestViewRun(t *testing.T) {
|
|||
return ghrepo.FromFullName("OWNER/REPO")
|
||||
}
|
||||
|
||||
//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
|
||||
as, teardown := prompt.InitAskStubber()
|
||||
defer teardown()
|
||||
if tt.askStubs != nil {
|
||||
tt.askStubs(as)
|
||||
pm := prompter.NewMockPrompter(t)
|
||||
tt.opts.Prompter = pm
|
||||
if tt.promptStubs != nil {
|
||||
tt.promptStubs(pm)
|
||||
}
|
||||
|
||||
browser := &browser.Stub{}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ type WatchOptions struct {
|
|||
IO *iostreams.IOStreams
|
||||
HttpClient func() (*http.Client, error)
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
Prompter shared.Prompter
|
||||
|
||||
RunID string
|
||||
Interval int
|
||||
|
|
@ -37,6 +38,7 @@ func NewCmdWatch(f *cmdutil.Factory, runF func(*WatchOptions) error) *cobra.Comm
|
|||
opts := &WatchOptions{
|
||||
IO: f.IOStreams,
|
||||
HttpClient: f.HttpClient,
|
||||
Prompter: f.Prompter,
|
||||
Now: time.Now,
|
||||
}
|
||||
|
||||
|
|
@ -102,11 +104,10 @@ func watchRun(opts *WatchOptions) error {
|
|||
if len(runs) == 0 {
|
||||
return fmt.Errorf("found no in progress runs to watch")
|
||||
}
|
||||
runID, err = shared.PromptForRun(cs, runs)
|
||||
if err != nil {
|
||||
if runID, err = shared.SelectRun(opts.Prompter, cs, runs); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO silly stopgap until dust settles and PromptForRun can just return a run
|
||||
// TODO silly stopgap until dust settles and SelectRun can just return a run
|
||||
for _, r := range runs {
|
||||
if fmt.Sprintf("%d", r.ID) == runID {
|
||||
run = &r
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/internal/prompter"
|
||||
"github.com/cli/cli/v2/pkg/cmd/run/shared"
|
||||
workflowShared "github.com/cli/cli/v2/pkg/cmd/workflow/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/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -193,14 +193,14 @@ func TestWatchRun(t *testing.T) {
|
|||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
httpStubs func(*httpmock.Registry)
|
||||
askStubs func(*prompt.AskStubber)
|
||||
opts *WatchOptions
|
||||
tty bool
|
||||
wantErr bool
|
||||
errMsg string
|
||||
wantOut string
|
||||
name string
|
||||
httpStubs func(*httpmock.Registry)
|
||||
promptStubs func(*prompter.MockPrompter)
|
||||
opts *WatchOptions
|
||||
tty bool
|
||||
wantErr bool
|
||||
errMsg string
|
||||
wantOut string
|
||||
}{
|
||||
{
|
||||
name: "run ID provided run already completed",
|
||||
|
|
@ -269,10 +269,12 @@ func TestWatchRun(t *testing.T) {
|
|||
Prompt: true,
|
||||
},
|
||||
httpStubs: successfulRunStubs,
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
as.StubPrompt("Select a workflow run").
|
||||
AssertOptions([]string{"* commit1, CI (trunk) Feb 23, 2021", "* commit2, CI (trunk) Feb 23, 2021"}).
|
||||
AnswerWith("* commit2, CI (trunk) Feb 23, 2021")
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"* commit1, CI (trunk) Feb 23, 2021", "* commit2, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "* commit2, CI (trunk) Feb 23, 2021")
|
||||
})
|
||||
},
|
||||
wantOut: "\x1b[?1049h\x1b[0;0H\x1b[JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\n* trunk CI · 2\nTriggered via push about 59 minutes ago\n\nJOBS\n✓ cool job in 4m34s (ID 10)\n ✓ fob the barz\n ✓ barz the fob\n\x1b[?1049l✓ trunk CI · 2\nTriggered via push about 59 minutes ago\n\nJOBS\n✓ cool job in 4m34s (ID 10)\n ✓ fob the barz\n ✓ barz the fob\n\n✓ Run CI (2) completed with 'success'\n",
|
||||
},
|
||||
|
|
@ -285,10 +287,12 @@ func TestWatchRun(t *testing.T) {
|
|||
ExitStatus: true,
|
||||
},
|
||||
httpStubs: failedRunStubs,
|
||||
askStubs: func(as *prompt.AskStubber) {
|
||||
as.StubPrompt("Select a workflow run").
|
||||
AssertOptions([]string{"* commit1, CI (trunk) Feb 23, 2021", "* commit2, CI (trunk) Feb 23, 2021"}).
|
||||
AnswerWith("* commit2, CI (trunk) Feb 23, 2021")
|
||||
promptStubs: func(pm *prompter.MockPrompter) {
|
||||
pm.RegisterSelect("Select a workflow run",
|
||||
[]string{"* commit1, CI (trunk) Feb 23, 2021", "* commit2, CI (trunk) Feb 23, 2021"},
|
||||
func(_, _ string, opts []string) (int, error) {
|
||||
return prompter.IndexFor(opts, "* commit2, CI (trunk) Feb 23, 2021")
|
||||
})
|
||||
},
|
||||
wantOut: "\x1b[?1049h\x1b[0;0H\x1b[JRefreshing run status every 0 seconds. Press Ctrl+C to quit.\n\n* trunk CI · 2\nTriggered via push about 59 minutes ago\n\n\x1b[?1049lX trunk CI · 2\nTriggered via push about 59 minutes ago\n\nJOBS\nX sad job in 4m34s (ID 20)\n ✓ barf the quux\n X quux the barf\n\nANNOTATIONS\nX the job is sad\nsad job: blaze.py#420\n\n\nX Run CI (2) completed with 'failure'\n",
|
||||
wantErr: true,
|
||||
|
|
@ -317,10 +321,10 @@ 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)
|
||||
pm := prompter.NewMockPrompter(t)
|
||||
tt.opts.Prompter = pm
|
||||
if tt.promptStubs != nil {
|
||||
tt.promptStubs(pm)
|
||||
}
|
||||
|
||||
err := watchRun(tt.opts)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue