mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
refactor(prompts): fold Asker into Prompter and share delete confirmations
FormPrompter is the only production prompter and implements the rich prompt API, so Ask, AskText and ConfirmDefault become the Prompter interface and the plain Input/Confirm fallbacks go away. Confirmations that default to no derive their non-terminal wording from the prompt, and single deletes share deleteConfirmed for the prompt, the request and the done line. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
31 files changed
+131
-253
No files matched your search
@@ -31,15 +31,6 @@ func accessiblePrompter(t *testing.T, input string) (*FormPrompter, *bytes.Buffe
|
||||
|
||||
func noEdit(context.Context, string) (Draft, error) { return Draft{}, nil }
|
||||
|
||||
type fakePrompt struct{ inputs int }
|
||||
|
||||
func (f *fakePrompt) Input(context.Context, string) (string, error) {
|
||||
f.inputs++
|
||||
return "provided", nil
|
||||
}
|
||||
func (f *fakePrompt) SecretInput(context.Context, string) (string, error) { return "", nil }
|
||||
func (f *fakePrompt) Confirm(context.Context, string) (bool, error) { return false, nil }
|
||||
|
||||
func TestPromptPolicy(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
policy Policy
|
||||
@@ -54,12 +45,12 @@ func TestPromptPolicy(t *testing.T) {
|
||||
} {
|
||||
require.Equal(t, tc.expected, tc.policy.CanPrompt(tc.streams))
|
||||
}
|
||||
prompt := &fakePrompt{}
|
||||
prompt := &askingPrompt{}
|
||||
value := "supplied"
|
||||
asked, err := RequireInput(context.Background(), &value, "title", "title", nil, Streams{}, Policy{}, prompt)
|
||||
require.NoError(t, err)
|
||||
require.False(t, asked)
|
||||
require.Zero(t, prompt.inputs)
|
||||
require.Empty(t, prompt.titles)
|
||||
value = ""
|
||||
_, err = RequireInput(context.Background(), &value, "title", "title", nil, Streams{}, Policy{}, prompt)
|
||||
require.ErrorContains(t, err, "--title")
|
||||
@@ -68,7 +59,6 @@ func TestPromptPolicy(t *testing.T) {
|
||||
// askingPrompt answers Asker prompts from scripted answers. Ask skips answers that validate rejects,
|
||||
// as an inline re-prompt does, and cancels when none is left.
|
||||
type askingPrompt struct {
|
||||
fakePrompt
|
||||
answers, rejected, titles []string
|
||||
accept bool
|
||||
defaults []bool
|
||||
@@ -87,6 +77,8 @@ func (p *askingPrompt) Ask(_ context.Context, title string, validate func(string
|
||||
return "", ErrCanceled
|
||||
}
|
||||
|
||||
func (p *askingPrompt) SecretInput(context.Context, string) (string, error) { return "", nil }
|
||||
|
||||
func (p *askingPrompt) AskText(_ context.Context, title, initial string) (string, error) {
|
||||
p.titles = append(p.titles, title)
|
||||
return initial + " edited", nil
|
||||
@@ -112,14 +104,13 @@ func TestConfirmAction(t *testing.T) {
|
||||
message string
|
||||
rejected []string
|
||||
}{
|
||||
{name: "accepted by flag", c: deleteLabel, yes: true, prompt: &fakePrompt{}},
|
||||
{name: "names the action without a terminal", c: deleteLabel, prompt: &fakePrompt{}, code: clierr.Usage, message: `confirmation required to delete label "bug" from alice/x; rerun with --yes`},
|
||||
{name: "without a terminal or action", c: Confirmation{Prompt: "Go?"}, prompt: &fakePrompt{}, code: clierr.Usage, message: "confirmation required; rerun with --yes"},
|
||||
{name: "accepted by flag", c: deleteLabel, yes: true, prompt: &askingPrompt{}},
|
||||
{name: "names the action without a terminal", c: deleteLabel, prompt: &askingPrompt{}, code: clierr.Usage, message: `confirmation required to delete label "bug" from alice/x; rerun with --yes`},
|
||||
{name: "names the prompted action without a terminal", c: Confirmation{Prompt: "Delete alice/x? It becomes read-only."}, prompt: &askingPrompt{}, code: clierr.Usage, message: "confirmation required to delete alice/x; rerun with --yes"},
|
||||
{name: "without a terminal or action", c: Confirmation{Prompt: "Go?", DefaultYes: true}, prompt: &askingPrompt{}, code: clierr.Usage, message: "confirmation required; rerun with --yes"},
|
||||
{name: "accepted", c: deleteLabel, streams: terminal, prompt: &askingPrompt{accept: true}},
|
||||
{name: "declined", c: deleteLabel, streams: terminal, prompt: &askingPrompt{}, code: clierr.Canceled, message: "canceled"},
|
||||
{name: "declined to a plain prompter", c: deleteLabel, streams: terminal, prompt: &fakePrompt{}, code: clierr.Canceled, message: "canceled"},
|
||||
{name: "re-prompts until the name is typed", c: typed, streams: terminal, prompt: &askingPrompt{answers: []string{"alice/y", " Alice/X "}}, rejected: []string{"alice/y"}},
|
||||
{name: "typed wrong to a plain prompter", c: typed, streams: terminal, prompt: &fakePrompt{}, code: clierr.Canceled, message: "canceled"},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := ConfirmAction(context.Background(), tc.c, tc.yes, tc.streams, Policy{Enabled: true}, tc.prompt)
|
||||
@@ -165,10 +156,6 @@ func TestRequireInput(t *testing.T) {
|
||||
require.Equal(t, []string{"Color (hex)"}, asker.titles)
|
||||
|
||||
value = ""
|
||||
_, err = RequireInput(context.Background(), &value, "color", "Color (hex)", hex, streams, policy, &fakePrompt{})
|
||||
require.Equal(t, clierr.Usage, clierr.ExitCode(err))
|
||||
require.EqualError(t, err, "--color: use six hex digits")
|
||||
|
||||
_, err = RequireInput(context.Background(), &value, "color", "Color (hex)", hex, Streams{}, policy, asker)
|
||||
require.EqualError(t, err, "missing required input: supply --color")
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user