Ensure huh prompter cleans up
This commit is contained in:
parent
84a3ba83e4
commit
cb2b50576f
2 changed files with 47 additions and 10 deletions
|
|
@ -1,10 +1,12 @@
|
|||
package prompter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"charm.land/huh/v2"
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
"github.com/cli/cli/v2/pkg/surveyext"
|
||||
ghPrompter "github.com/cli/go-gh/v2/pkg/prompter"
|
||||
|
|
@ -24,6 +26,18 @@ func (p *huhPrompter) newForm(groups ...*huh.Group) *huh.Form {
|
|||
WithOutput(p.stdout)
|
||||
}
|
||||
|
||||
func (p *huhPrompter) runForm(form *huh.Form) error {
|
||||
err := form.Run()
|
||||
if errors.Is(err, huh.ErrUserAborted) {
|
||||
// TODO(huh-prompter-improvements)
|
||||
// It's unfortunate that we take a dependency on survey/terminal here, but our clean cancellation logic
|
||||
// in cmd.go expects it. Better would be to have a prompter.Cancelled sentinel error, but then we need to
|
||||
// go and change non-experimental code to do so, and I don't think we should take that on right now.
|
||||
return terminal.InterruptErr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *huhPrompter) buildSelectForm(prompt, defaultValue string, options []string) (*huh.Form, *int) {
|
||||
var result int
|
||||
|
||||
|
|
@ -52,7 +66,7 @@ func (p *huhPrompter) buildSelectForm(prompt, defaultValue string, options []str
|
|||
|
||||
func (p *huhPrompter) Select(prompt, defaultValue string, options []string) (int, error) {
|
||||
form, result := p.buildSelectForm(prompt, defaultValue, options)
|
||||
err := form.Run()
|
||||
err := p.runForm(form)
|
||||
return *result, err
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +99,7 @@ func (p *huhPrompter) buildMultiSelectForm(prompt string, defaults []string, opt
|
|||
|
||||
func (p *huhPrompter) MultiSelect(prompt string, defaults []string, options []string) ([]int, error) {
|
||||
form, result := p.buildMultiSelectForm(prompt, defaults, options)
|
||||
err := form.Run()
|
||||
err := p.runForm(form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -100,7 +114,7 @@ func (p *huhPrompter) buildMultiSelectWithSearchForm(prompt, searchPrompt string
|
|||
|
||||
func (p *huhPrompter) MultiSelectWithSearch(prompt, searchPrompt string, defaultValues, persistentValues []string, searchFunc func(string) MultiSelectSearchResult) ([]string, error) {
|
||||
form, field := p.buildMultiSelectWithSearchForm(prompt, searchPrompt, defaultValues, persistentValues, searchFunc)
|
||||
err := form.Run()
|
||||
err := p.runForm(form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -121,7 +135,7 @@ func (p *huhPrompter) buildInputForm(prompt, defaultValue string) (*huh.Form, *s
|
|||
|
||||
func (p *huhPrompter) Input(prompt, defaultValue string) (string, error) {
|
||||
form, result := p.buildInputForm(prompt, defaultValue)
|
||||
err := form.Run()
|
||||
err := p.runForm(form)
|
||||
return *result, err
|
||||
}
|
||||
|
||||
|
|
@ -140,7 +154,7 @@ func (p *huhPrompter) buildPasswordForm(prompt string) (*huh.Form, *string) {
|
|||
|
||||
func (p *huhPrompter) Password(prompt string) (string, error) {
|
||||
form, result := p.buildPasswordForm(prompt)
|
||||
err := form.Run()
|
||||
err := p.runForm(form)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -161,7 +175,7 @@ func (p *huhPrompter) buildConfirmForm(prompt string, defaultValue bool) (*huh.F
|
|||
|
||||
func (p *huhPrompter) Confirm(prompt string, defaultValue bool) (bool, error) {
|
||||
form, result := p.buildConfirmForm(prompt, defaultValue)
|
||||
err := form.Run()
|
||||
err := p.runForm(form)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -189,7 +203,7 @@ func (p *huhPrompter) buildAuthTokenForm() (*huh.Form, *string) {
|
|||
|
||||
func (p *huhPrompter) AuthToken() (string, error) {
|
||||
form, result := p.buildAuthTokenForm()
|
||||
err := form.Run()
|
||||
err := p.runForm(form)
|
||||
return *result, err
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +223,7 @@ func (p *huhPrompter) buildConfirmDeletionForm(requiredValue string) *huh.Form {
|
|||
}
|
||||
|
||||
func (p *huhPrompter) ConfirmDeletion(requiredValue string) error {
|
||||
return p.buildConfirmDeletionForm(requiredValue).Run()
|
||||
return p.runForm(p.buildConfirmDeletionForm(requiredValue))
|
||||
}
|
||||
|
||||
func (p *huhPrompter) buildInputHostnameForm() (*huh.Form, *string) {
|
||||
|
|
@ -227,7 +241,7 @@ func (p *huhPrompter) buildInputHostnameForm() (*huh.Form, *string) {
|
|||
|
||||
func (p *huhPrompter) InputHostname() (string, error) {
|
||||
form, result := p.buildInputHostnameForm()
|
||||
err := form.Run()
|
||||
err := p.runForm(form)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -258,7 +272,7 @@ func (p *huhPrompter) buildMarkdownEditorForm(prompt string, blankAllowed bool)
|
|||
|
||||
func (p *huhPrompter) MarkdownEditor(prompt, defaultValue string, blankAllowed bool) (string, error) {
|
||||
form, result := p.buildMarkdownEditorForm(prompt, blankAllowed)
|
||||
err := form.Run()
|
||||
err := p.runForm(form)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"charm.land/huh/v2"
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
|
@ -618,3 +619,25 @@ func TestHuhPrompterMultiSelectWithSearchBackspace(t *testing.T) {
|
|||
assert.Equal(t, []string{"alice"}, result.selectedKeys())
|
||||
})
|
||||
}
|
||||
|
||||
func TestRunFormTranslatesErrUserAborted(t *testing.T) {
|
||||
p := newTestHuhPrompter()
|
||||
form, _ := p.buildSelectForm("Pick one:", "", []string{"a", "b", "c"})
|
||||
|
||||
r, w := io.Pipe()
|
||||
form.WithInput(r).WithOutput(io.Discard).WithWidth(80)
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() { errCh <- p.runForm(form) }()
|
||||
|
||||
// Send Ctrl+C to trigger huh.ErrUserAborted
|
||||
_, err := w.Write([]byte{0x03})
|
||||
require.NoError(t, err)
|
||||
|
||||
select {
|
||||
case err := <-errCh:
|
||||
assert.ErrorIs(t, err, terminal.InterruptErr, "expected huh.ErrUserAborted to be translated to terminal.InterruptErr")
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("runForm did not complete in time")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue