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
@@ -293,7 +293,7 @@ func (a *application) actionValue(cmd *cobra.Command, secret bool, name, body, b
|
||||
if secret {
|
||||
return a.deps.Prompter.SecretInput(cmd.Context(), "Paste the value of "+strings.ToUpper(name)+":")
|
||||
}
|
||||
return a.deps.Prompter.Input(cmd.Context(), "Value of "+strings.ToUpper(name)+":")
|
||||
return a.deps.Prompter.Ask(cmd.Context(), "Value of "+strings.ToUpper(name)+":", nil)
|
||||
}
|
||||
|
||||
// envEntry is one NAME=value line of a dotenv file.
|
||||
@@ -348,10 +348,7 @@ $ tea %[1]s delete DEPLOY_TOKEN --org acme --yes`, kind),
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{
|
||||
Prompt: fmt.Sprintf("Delete %s %s from %s?", kind, name, selected),
|
||||
NonTTY: fmt.Sprintf("delete %s %s from %s", kind, name, selected),
|
||||
}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: fmt.Sprintf("Delete %s %s from %s?", kind, name, selected)}); err != nil {
|
||||
return err
|
||||
}
|
||||
if secret {
|
||||
|
||||
+3
-10
@@ -399,7 +399,6 @@ func (a *application) askInput(cmd *cobra.Command, input services.WorkflowInput)
|
||||
if input.Description != "" {
|
||||
title += " — " + input.Description
|
||||
}
|
||||
asker, rich := a.deps.Prompter.(terminal.Asker)
|
||||
switch chooser, ok := a.deps.Prompter.(terminal.Chooser); {
|
||||
case input.Type == "choice" && ok && len(input.Options) > 0:
|
||||
choices := make([]terminal.Choice, len(input.Options))
|
||||
@@ -407,8 +406,8 @@ func (a *application) askInput(cmd *cobra.Command, input services.WorkflowInput)
|
||||
choices[i] = terminal.Choice{Label: option, Value: option}
|
||||
}
|
||||
return chooser.Choose(cmd.Context(), title, choices, input.Default)
|
||||
case input.Type == "boolean" && rich:
|
||||
yes, err := asker.ConfirmDefault(cmd.Context(), title, input.Default == "true")
|
||||
case input.Type == "boolean":
|
||||
yes, err := a.deps.Prompter.ConfirmDefault(cmd.Context(), title, input.Default == "true")
|
||||
return strconv.FormatBool(yes), err
|
||||
}
|
||||
if input.Default != "" {
|
||||
@@ -424,13 +423,7 @@ func (a *application) askInput(cmd *cobra.Command, input services.WorkflowInput)
|
||||
_, err := inputValue(input, answer)
|
||||
return err
|
||||
}
|
||||
var answer string
|
||||
var err error
|
||||
if rich {
|
||||
answer, err = asker.Ask(cmd.Context(), title, validate)
|
||||
} else if answer, err = a.deps.Prompter.Input(cmd.Context(), title); err == nil {
|
||||
err = validate(answer)
|
||||
}
|
||||
answer, err := a.deps.Prompter.Ask(cmd.Context(), title, validate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"gitea.dev/tea/internal/clierr"
|
||||
"gitea.dev/tea/internal/terminal"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -240,5 +239,3 @@ func TestWorkflowRunFollowStreamsTheLogsOfItsJobs(t *testing.T) {
|
||||
require.Equal(t, clierr.Usage, clierr.ExitCode(err))
|
||||
require.ErrorContains(t, err, "--follow cannot be combined with --json")
|
||||
}
|
||||
|
||||
var _ terminal.Asker = (*dispatchingPrompter)(nil)
|
||||
@@ -354,7 +354,7 @@ $ tea admin user delete spammer --purge`,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
confirmation := terminal.Confirmation{Prompt: fmt.Sprintf("Delete user %s?", user.Username), NonTTY: "delete user " + user.Username}
|
||||
confirmation := terminal.Confirmation{Prompt: "Delete user " + user.Username + "?"}
|
||||
if purge {
|
||||
confirmation = terminal.Confirmation{
|
||||
Prompt: fmt.Sprintf("Delete user %s with their repositories, packages and organization memberships? This cannot be undone.", user.Username),
|
||||
|
||||
@@ -758,7 +758,7 @@ instance.`,
|
||||
case !exists:
|
||||
return clierr.Wrap(clierr.Usage, t.accountError(t.User))
|
||||
}
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: fmt.Sprintf("Log out %s from %s?", t.User, t.Host), NonTTY: "log out " + t.User + " from " + t.Host}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: fmt.Sprintf("Log out %s from %s?", t.User, t.Host)}); err != nil {
|
||||
return err
|
||||
}
|
||||
manager, err := auth.NewManager(a.deps.Settings, a.deps.Credentials)
|
||||
|
||||
@@ -250,7 +250,7 @@ $ tea branch delete old-a old-b --yes`,
|
||||
return err
|
||||
}
|
||||
subject := branchSubject(args)
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + " from " + target.Repo + "?", NonTTY: "delete " + subject + " from " + target.Repo}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + " from " + target.Repo + "?"}); err != nil {
|
||||
return err
|
||||
}
|
||||
service := services.Branches{Client: target.client}
|
||||
@@ -384,7 +384,7 @@ func (a *application) branchUnprotectCommand() *cobra.Command {
|
||||
return err
|
||||
}
|
||||
subject := "the protection of " + strings.Join(args, ", ")
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Remove " + subject + " in " + target.Repo + "?", NonTTY: "remove " + subject + " in " + target.Repo}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Remove " + subject + " in " + target.Repo + "?"}); err != nil {
|
||||
return err
|
||||
}
|
||||
service := services.Branches{Client: target.client}
|
||||
|
||||
@@ -119,11 +119,7 @@ func (a *application) promptComment(cmd *cobra.Command, initial string) (string,
|
||||
draft, err := a.editDraft(cmd, initial)
|
||||
return draft.Body, draft, err
|
||||
}
|
||||
if asker, ok := a.deps.Prompter.(terminal.Asker); ok {
|
||||
body, err := asker.AskText(cmd.Context(), commentTitle, initial)
|
||||
return body, terminal.Draft{}, err
|
||||
}
|
||||
body, err := a.deps.Prompter.Input(cmd.Context(), commentTitle)
|
||||
body, err := a.deps.Prompter.AskText(cmd.Context(), commentTitle, initial)
|
||||
return body, terminal.Draft{}, err
|
||||
}
|
||||
|
||||
@@ -189,14 +185,9 @@ func (a *application) editComment(cmd *cobra.Command, t target, comment services
|
||||
// deleteComment deletes comment after a confirmation that defaults to no.
|
||||
func (a *application) deleteComment(cmd *cobra.Command, t target, comment services.Comment) error {
|
||||
name := commentName(t, comment)
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + name + "?", NonTTY: "delete " + name}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := (services.Comments{Client: t.client, Repository: t.Repo}).Delete(cmd.Context(), comment.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s", name)
|
||||
return nil
|
||||
return a.deleteConfirmed(cmd, name, func() error {
|
||||
return (services.Comments{Client: t.client, Repository: t.Repo}).Delete(cmd.Context(), comment.ID)
|
||||
})
|
||||
}
|
||||
|
||||
// commentView shows one comment; now dates it on a terminal.
|
||||
|
||||
@@ -54,9 +54,9 @@ func (a *application) editDraft(cmd *cobra.Command, body string) (terminal.Draft
|
||||
// already given is never lost to a missing editor.
|
||||
func (a *application) bodyEditor(cmd *cobra.Command) terminal.BodyEditor {
|
||||
preferences, err := a.preferences()
|
||||
if asker, ok := a.deps.Prompter.(terminal.Asker); ok && err == nil && preferences.Editor == "" {
|
||||
if err == nil && preferences.Editor == "" {
|
||||
return func(ctx context.Context, initial string) (terminal.Draft, error) {
|
||||
body, err := asker.AskText(ctx, terminal.BodyTitle, initial)
|
||||
body, err := a.deps.Prompter.AskText(ctx, terminal.BodyTitle, initial)
|
||||
return terminal.Draft{Body: body}, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ func TestReviewLifecycleEditorRejectsEmptyRequiredText(t *testing.T) {
|
||||
|
||||
func TestBodyEditorTypesInlineWithoutAnEditor(t *testing.T) {
|
||||
deps, _, _ := testDeps(t)
|
||||
prompt := &askingPrompter{}
|
||||
prompt := &scriptedPrompter{}
|
||||
deps.Prompter = prompt
|
||||
a, cmd := outputApplication(deps, "")
|
||||
draft, err := a.bodyEditor(cmd)(context.Background(), "## Steps")
|
||||
@@ -340,10 +340,4 @@ func TestBodyEditorTypesInlineWithoutAnEditor(t *testing.T) {
|
||||
require.Equal(t, terminal.Draft{Path: path, Body: "edited body"}, draft)
|
||||
require.Equal(t, "## Steps", editor.initial)
|
||||
require.Len(t, prompt.texts, 1)
|
||||
|
||||
deps.Prompter = &scriptedPrompter{}
|
||||
deps.Getenv = envFunc(nil)
|
||||
a, cmd = outputApplication(deps, "")
|
||||
_, err = a.bodyEditor(cmd)(context.Background(), "")
|
||||
require.ErrorContains(t, err, "configure an editor")
|
||||
}
|
||||
@@ -5,6 +5,7 @@ package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmp"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -153,17 +154,34 @@ type scriptedPrompter struct {
|
||||
asked []string
|
||||
secrets []string
|
||||
confirmations []string
|
||||
texts []string
|
||||
defaults []bool
|
||||
}
|
||||
|
||||
func (p *scriptedPrompter) Input(_ context.Context, field string) (string, error) {
|
||||
func (p *scriptedPrompter) Ask(_ context.Context, field string, validate func(string) error) (string, error) {
|
||||
p.asked = append(p.asked, field)
|
||||
if value, ok := p.inputs[field]; ok {
|
||||
value, ok := p.inputs[field]
|
||||
if !ok {
|
||||
if p.input == "" {
|
||||
return "", errors.New("unexpected input prompt " + field)
|
||||
}
|
||||
value = p.input
|
||||
}
|
||||
// A form re-prompts until the answer is valid; the script has no other answer, so it gives up.
|
||||
if validate != nil && validate(value) != nil {
|
||||
return "", terminal.ErrCanceled
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// AskText records the title and initial text, and answers like Ask, else with "typed body".
|
||||
func (p *scriptedPrompter) AskText(_ context.Context, title, initial string) (string, error) {
|
||||
p.asked = append(p.asked, title)
|
||||
p.texts = append(p.texts, title+" "+initial)
|
||||
if value, ok := p.inputs[title]; ok {
|
||||
return value, nil
|
||||
}
|
||||
if p.input == "" {
|
||||
return "", errors.New("unexpected input prompt " + field)
|
||||
}
|
||||
return p.input, nil
|
||||
return cmp.Or(p.input, "typed body"), nil
|
||||
}
|
||||
|
||||
func (p *scriptedPrompter) SecretInput(_ context.Context, title string) (string, error) {
|
||||
@@ -174,8 +192,9 @@ func (p *scriptedPrompter) SecretInput(_ context.Context, title string) (string,
|
||||
return p.secret, nil
|
||||
}
|
||||
|
||||
func (p *scriptedPrompter) Confirm(_ context.Context, description string) (bool, error) {
|
||||
func (p *scriptedPrompter) ConfirmDefault(_ context.Context, description string, defaultYes bool) (bool, error) {
|
||||
p.confirmations = append(p.confirmations, description)
|
||||
p.defaults = append(p.defaults, defaultYes)
|
||||
return p.accept, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -145,14 +145,7 @@ $ tea %[1]s attachment upload %[2]s screenshot.png --name before.png`, words.gro
|
||||
return err
|
||||
}
|
||||
name := attachmentName(t, n, item)
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + name + "?", NonTTY: "delete " + name}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := service.DeleteAttachment(cmd.Context(), n, id); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s", name)
|
||||
return nil
|
||||
return a.deleteConfirmed(cmd, name, func() error { return service.DeleteAttachment(cmd.Context(), n, id) })
|
||||
}}
|
||||
|
||||
var destination downloadFlags
|
||||
|
||||
@@ -177,7 +177,7 @@ func TestLabelCreatePicksAColorAndPrompts(t *testing.T) {
|
||||
deps, _, _ := serverDeps(t, server.URL)
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"label", "create", "triage", "-R", "alice/project"}))
|
||||
require.Contains(t, labelColors, created[0]["color"])
|
||||
prompt := &askingPrompter{scriptedPrompter: scriptedPrompter{inputs: map[string]string{"Label name": "prompted", "Color (hex, e.g. d73a4a; empty = random):": "#00AA00", "Description (optional):": "From a prompt"}}}
|
||||
prompt := &scriptedPrompter{inputs: map[string]string{"Label name": "prompted", "Color (hex, e.g. d73a4a; empty = random):": "#00AA00", "Description (optional):": "From a prompt"}}
|
||||
deps.Prompter = prompt
|
||||
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"label", "create", "-R", "alice/project"}))
|
||||
|
||||
@@ -196,12 +196,8 @@ $ tea label create bug -c ee0701 --force`, Args: usageArgs(cobra.MaximumNArgs(1)
|
||||
|
||||
// askLabelDetails asks for the optional color and description of a label whose name was prompted.
|
||||
func (a *application) askLabelDetails(cmd *cobra.Command, opts *services.LabelOptions) error {
|
||||
asker, ok := a.deps.Prompter.(terminal.Asker)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if opts.Color == nil {
|
||||
color, err := asker.Ask(cmd.Context(), "Color (hex, e.g. d73a4a; empty = random):", func(s string) error {
|
||||
color, err := a.deps.Prompter.Ask(cmd.Context(), "Color (hex, e.g. d73a4a; empty = random):", func(s string) error {
|
||||
if s != "" && !labelColor.MatchString(strings.TrimPrefix(s, "#")) {
|
||||
return errors.New("use six hexadecimal digits")
|
||||
}
|
||||
@@ -215,7 +211,7 @@ func (a *application) askLabelDetails(cmd *cobra.Command, opts *services.LabelOp
|
||||
}
|
||||
}
|
||||
if opts.Description == nil {
|
||||
description, err := asker.Ask(cmd.Context(), "Description (optional):", nil)
|
||||
description, err := a.deps.Prompter.Ask(cmd.Context(), "Description (optional):", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -288,7 +284,7 @@ $ tea label delete wontfix duplicate --yes`, Annotations: map[string]string{"tea
|
||||
if len(found) > 1 {
|
||||
subject = fmt.Sprintf("%d labels (%s)", len(found), strings.Join(names, ", "))
|
||||
}
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + " from " + s.Scope() + "?", NonTTY: "delete " + subject + " from " + s.Scope()}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + " from " + s.Scope() + "?"}); err != nil {
|
||||
return err
|
||||
}
|
||||
return batchDone(a, cmd, found, func(item services.Label) string { return "label " + strconv.Quote(item.Name) }, func(item services.Label) (services.Label, error) {
|
||||
|
||||
@@ -357,7 +357,7 @@ $ tea milestone delete 7 --yes`, Annotations: map[string]string{"tea.confirm": "
|
||||
return err
|
||||
}
|
||||
name := fmt.Sprintf("milestone %q (ID %d) from %s", item.Title, item.ID, t.Repo)
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + name + "?", NonTTY: "delete " + name}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + name + "?"}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Delete(cmd.Context(), item.ID); err != nil {
|
||||
|
||||
@@ -19,6 +19,19 @@ func (a *application) confirmAction(cmd *cobra.Command, c terminal.Confirmation)
|
||||
return terminal.ConfirmAction(cmd.Context(), c, a.options.yes, a.deps.Streams, a.policy(s), a.deps.Prompter)
|
||||
}
|
||||
|
||||
// deleteConfirmed asks to delete subject, such as `label "bug" from alice/x`, deletes it with del
|
||||
// and reports "Deleted <subject>".
|
||||
func (a *application) deleteConfirmed(cmd *cobra.Command, subject string, del func() error) error {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + "?"}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := del(); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s", subject)
|
||||
return nil
|
||||
}
|
||||
|
||||
// requireInput fills a missing value from a prompt titled label, such as "Label name", re-prompting
|
||||
// until the answer is non-empty and validate, when set, accepts it. Without prompts it returns a
|
||||
// usage error naming --flag. It reports whether it prompted.
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"gitea.dev/tea/internal/clierr"
|
||||
@@ -12,27 +11,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// askingPrompter is scriptedPrompter with the terminal.Asker extension that FormPrompter has.
|
||||
type askingPrompter struct {
|
||||
scriptedPrompter
|
||||
texts []string
|
||||
defaults []bool
|
||||
}
|
||||
|
||||
func (p *askingPrompter) Ask(ctx context.Context, title string, _ func(string) error) (string, error) {
|
||||
return p.Input(ctx, title)
|
||||
}
|
||||
|
||||
func (p *askingPrompter) AskText(_ context.Context, title, initial string) (string, error) {
|
||||
p.texts = append(p.texts, title+" "+initial)
|
||||
return "typed body", nil
|
||||
}
|
||||
|
||||
func (p *askingPrompter) ConfirmDefault(ctx context.Context, title string, defaultYes bool) (bool, error) {
|
||||
p.defaults = append(p.defaults, defaultYes)
|
||||
return p.Confirm(ctx, title)
|
||||
}
|
||||
|
||||
func TestConfirmActionFollowsThePromptPolicy(t *testing.T) {
|
||||
c := terminal.Confirmation{Prompt: `Delete label "bug" from alice/x?`, NonTTY: `delete label "bug" from alice/x`}
|
||||
deps, _, _ := testDeps(t)
|
||||
@@ -43,7 +21,7 @@ func TestConfirmActionFollowsThePromptPolicy(t *testing.T) {
|
||||
a.options.yes = true
|
||||
require.NoError(t, a.confirmAction(cmd, c))
|
||||
|
||||
prompt := &askingPrompter{}
|
||||
prompt := &scriptedPrompter{}
|
||||
deps.Prompter = prompt
|
||||
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
||||
a, cmd = outputApplication(deps, "")
|
||||
|
||||
@@ -78,7 +78,7 @@ func TestPullMergeAsksForTheMethodAndBranchDeletion(t *testing.T) {
|
||||
form := &mergeForm{options: func(choices terminal.MergeFormChoices) terminal.MergeFormValues {
|
||||
return terminal.MergeFormValues{Method: "rebase", DeleteBranch: false}
|
||||
}}
|
||||
prompt := &askingPrompter{}
|
||||
prompt := &scriptedPrompter{}
|
||||
deps, _, diagnostics := serverDeps(t, server.URL)
|
||||
deps.MergeForm, deps.Prompter = form, prompt
|
||||
deps.Streams.InTTY, deps.Streams.ErrTTY, deps.Streams.OutTTY = true, true, true
|
||||
@@ -187,7 +187,7 @@ func TestPullMergePicksAPullRequestForTheBranch(t *testing.T) {
|
||||
}
|
||||
deps, _, _ := serverDeps(t, server.URL)
|
||||
deps.Getenv = serverEnv(server.URL, map[string]string{"TEA_REPO": "alice/project"})
|
||||
deps.MergeForm, deps.Prompter = form, &askingPrompter{}
|
||||
deps.MergeForm, deps.Prompter = form, &scriptedPrompter{}
|
||||
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
||||
deps.Git = &fakeGit{results: map[string]string{"symbolic-ref --short HEAD": "main"}}
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"pr", "merge"}))
|
||||
|
||||
@@ -37,7 +37,7 @@ func TestPullReviewImplicitInteractiveForm(t *testing.T) {
|
||||
}))
|
||||
defer server.Close()
|
||||
calls := 0
|
||||
prompt := &askingPrompter{scriptedPrompter: scriptedPrompter{accept: true}}
|
||||
prompt := &scriptedPrompter{accept: true}
|
||||
deps, out, diagnostics := serverDeps(t, server.URL)
|
||||
deps.Getenv = serverEnv(server.URL, map[string]string{"EDITOR": "vi"})
|
||||
deps.ReviewForm = reviewFormFunc(func(_ context.Context, choices terminal.ReviewFormChoices) (terminal.ReviewFormValues, error) {
|
||||
@@ -78,7 +78,7 @@ func TestPullReviewFormKeepsTheBodyWhenSubmissionIsDeclined(t *testing.T) {
|
||||
require.Nil(t, choices.ReviewDiff, "annotating the diff needs an editor")
|
||||
return terminal.ReviewFormValues{Event: "COMMENT", Body: "Self note"}, nil
|
||||
})
|
||||
deps.Prompter = &askingPrompter{}
|
||||
deps.Prompter = &scriptedPrompter{}
|
||||
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
||||
err := Execute(context.Background(), deps, []string{"pr", "review", "3", "-R", "alice/project"})
|
||||
require.ErrorIs(t, err, terminal.ErrCanceled)
|
||||
|
||||
@@ -134,14 +134,7 @@ func (a *application) pullReviewDeleteCommand() *cobra.Command {
|
||||
return err
|
||||
}
|
||||
subject := fmt.Sprintf("review %d by %s on %s#%d", id, item.Author, t.Repo, n)
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + "?", NonTTY: "delete " + subject}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := service.Delete(cmd.Context(), n, id); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s", subject)
|
||||
return nil
|
||||
return a.deleteConfirmed(cmd, subject, func() error { return service.Delete(cmd.Context(), n, id) })
|
||||
}}
|
||||
cmd.Annotations["tea.confirm"] = "true"
|
||||
cmd.Example = "$ tea pr review delete 13 21"
|
||||
@@ -191,7 +184,7 @@ func (a *application) pullReviewDismissCommand(dismiss bool) *cobra.Command {
|
||||
}
|
||||
subject := fmt.Sprintf("%s on %s#%d", reviewPossessive(current), t.Repo, n)
|
||||
if dismiss {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Dismiss " + subject + "?", NonTTY: "dismiss " + subject}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Dismiss " + subject + "?"}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestReviewPromptAndFlagsReachIdenticalOptions(t *testing.T) {
|
||||
}))
|
||||
defer server.Close()
|
||||
deps, out, diagnostics := serverDeps(t, server.URL)
|
||||
prompt := &askingPrompter{}
|
||||
prompt := &scriptedPrompter{}
|
||||
deps.Prompter = prompt
|
||||
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
||||
args := []string{"pr", "review", "1", "-R", "owner/repo", "--event", "REQUEST_CHANGES"}
|
||||
|
||||
@@ -430,7 +430,7 @@ $ tea release delete v1.0.0-rc1 v1.0.0-rc2 --delete-tag --yes`,
|
||||
subject = "release " + args[0] + " and its tag"
|
||||
}
|
||||
}
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + " from " + target.Repo + "?", NonTTY: "delete " + subject + " from " + target.Repo}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + " from " + target.Repo + "?"}); err != nil {
|
||||
return err
|
||||
}
|
||||
service := services.Releases{Client: target.client, Repository: target.Repo}
|
||||
|
||||
@@ -167,7 +167,7 @@ $ tea repo edit --default-merge-style squash --add-topic cli --add-topic go`,
|
||||
}
|
||||
}
|
||||
if options.Archived != nil && *options.Archived {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Archive " + t.Repo + "? It becomes read-only.", NonTTY: "archive " + t.Repo}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Archive " + t.Repo + "? It becomes read-only."}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,14 +223,7 @@ $ tea ssh-key delete 2 --yes`,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + sshKeyLabel(key) + "?", NonTTY: "delete " + sshKeyLabel(key)}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := service.Delete(cmd.Context(), id); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s", sshKeyLabel(key))
|
||||
return nil
|
||||
return a.deleteConfirmed(cmd, sshKeyLabel(key), func() error { return service.Delete(cmd.Context(), id) })
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -356,7 +356,7 @@ func (a *application) selectAccount(ctx context.Context, t *target, s settings.S
|
||||
if !authenticate || a.deps.Getenv("GITEA_TOKEN") != "" || !a.policy(s).CanPrompt(a.deps.Streams) || a.deps.Prompter == nil {
|
||||
return nil
|
||||
}
|
||||
selected, err := a.deps.Prompter.Input(ctx, "account ("+accountNames(users)+")")
|
||||
selected, err := a.deps.Prompter.Ask(ctx, "account ("+accountNames(users)+")", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
+4
-10
@@ -459,12 +459,12 @@ $ tea team delete 7 --yes`,
|
||||
if team.Organization != "" {
|
||||
subject += " from " + team.Organization
|
||||
}
|
||||
confirmation := terminal.Confirmation{Prompt: "Delete " + subject + "?", NonTTY: "delete " + subject}
|
||||
confirmation := terminal.Confirmation{Prompt: "Delete " + subject + "?"}
|
||||
if team.Permission == "owner" {
|
||||
if !force {
|
||||
return clierr.Wrap(clierr.Usage, fmt.Errorf("%s is the organization's owner team and its members would lose owner access; pass --force to delete it", subject))
|
||||
}
|
||||
confirmation = terminal.Confirmation{Prompt: "Delete owner " + subject + "? Its members lose owner access.", Typed: team.Slug(), NonTTY: "delete owner " + subject}
|
||||
confirmation = terminal.Confirmation{Prompt: "Delete owner " + subject + "? Its members lose owner access.", Typed: team.Slug()}
|
||||
}
|
||||
if err := a.confirmAction(cmd, confirmation); err != nil {
|
||||
return err
|
||||
@@ -556,10 +556,7 @@ $ tea team member add 2 bob carol`,
|
||||
return err
|
||||
}
|
||||
members := args[1:]
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{
|
||||
Prompt: fmt.Sprintf("Remove %s from team %s?", joinNames(members), team.Slug()),
|
||||
NonTTY: fmt.Sprintf("remove %s from team %s", joinNames(members), team.Slug()),
|
||||
}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: fmt.Sprintf("Remove %s from team %s?", joinNames(members), team.Slug())}); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, username := range members {
|
||||
@@ -661,10 +658,7 @@ repositories of other owners cannot be granted to a team.`,
|
||||
repos = append(repos, repo)
|
||||
}
|
||||
if !grant {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{
|
||||
Prompt: fmt.Sprintf("Revoke team %s access to %s?", team.Slug(), joinNames(repos)),
|
||||
NonTTY: fmt.Sprintf("revoke team %s access to %s", team.Slug(), joinNames(repos)),
|
||||
}); err != nil {
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: fmt.Sprintf("Revoke team %s access to %s?", team.Slug(), joinNames(repos))}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
+4
-16
@@ -196,14 +196,7 @@ $ tea time delete 12 8`, Annotations: map[string]string{"tea.text": "time delete
|
||||
return err
|
||||
}
|
||||
subject := fmt.Sprintf("%s logged by %s on %s#%d", spent(record.Seconds), record.User, target.Repo, n)
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + "?", NonTTY: "delete " + subject}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := service.Delete(cmd.Context(), n, id); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s", subject)
|
||||
return nil
|
||||
return a.deleteConfirmed(cmd, subject, func() error { return service.Delete(cmd.Context(), n, id) })
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -214,13 +207,8 @@ func (a *application) timeResetCommand() *cobra.Command {
|
||||
return err
|
||||
}
|
||||
subject := fmt.Sprintf("all time logged on %s#%d", target.Repo, n)
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + "?", NonTTY: "delete " + subject}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := (services.Times{Client: target.client, Repository: target.Repo}).Reset(cmd.Context(), n); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s", subject)
|
||||
return nil
|
||||
return a.deleteConfirmed(cmd, subject, func() error {
|
||||
return (services.Times{Client: target.client, Repository: target.Repo}).Reset(cmd.Context(), n)
|
||||
})
|
||||
}}
|
||||
}
|
||||
@@ -455,18 +455,7 @@ $ tea webhook delete 4 --org acme --yes`,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
where := webhookScopeName(service.Scope)
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{
|
||||
Prompt: fmt.Sprintf("Delete %s from %s?", webhookLabel(hook), where),
|
||||
NonTTY: fmt.Sprintf("delete %s from %s", webhookLabel(hook), where),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := service.Delete(cmd.Context(), id); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s from %s", webhookLabel(hook), where)
|
||||
return nil
|
||||
return a.deleteConfirmed(cmd, webhookLabel(hook)+" from "+webhookScopeName(service.Scope), func() error { return service.Delete(cmd.Context(), id) })
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -316,14 +316,9 @@ func (a *application) wikiDeleteCommand() *cobra.Command {
|
||||
return err
|
||||
}
|
||||
subject := "wiki page " + strconv.Quote(args[0]) + " from " + target.Repo
|
||||
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Delete " + subject + "?", NonTTY: "delete " + subject}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := (services.Wiki{Client: target.client, Repository: target.Repo}).Delete(cmd.Context(), args[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
a.done(cmd, "Deleted %s", subject)
|
||||
return nil
|
||||
return a.deleteConfirmed(cmd, subject, func() error {
|
||||
return (services.Wiki{Client: target.client, Repository: target.Repo}).Delete(cmd.Context(), args[0])
|
||||
})
|
||||
},
|
||||
}
|
||||
command.ValidArgsFunction = a.completeWikiPages()
|
||||
|
||||
Reference in new issue
Block a user