mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
feat(label): edit a label in a form without flags
label edit without flags on a terminal now opens a form with the label's name, color, description and flags, like milestone edit and issue edit, instead of failing; without a terminal it reports the shared "nothing to edit" error. The help of issue and milestone close and reopen names its commands without generating the text from the verb. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
6 files changed
+143
-8
No files matched your search
@@ -414,11 +414,11 @@ func issueTemplate(ctx context.Context, service services.Issues, name string) (s
|
||||
// changing them.
|
||||
func (a *application) issueStateCommand(verb string) *cobra.Command {
|
||||
var comment string
|
||||
state, past, completeState := "closed", "Closed", "open"
|
||||
state, past, completeState, short := "closed", "Closed", "open", "Close issues"
|
||||
if verb == "reopen" {
|
||||
state, past, completeState = "open", "Reopened", "closed"
|
||||
state, past, completeState, short = "open", "Reopened", "closed", "Reopen issues"
|
||||
}
|
||||
cmd := &cobra.Command{Use: verb + " {<number> | <url>}...", Short: titleCase(verb) + " issues", Example: fmt.Sprintf(`$ tea issue %[1]s 12
|
||||
cmd := &cobra.Command{Use: verb + " {<number> | <url>}...", Short: short, Example: fmt.Sprintf(`$ tea issue %[1]s 12
|
||||
$ tea issue %[1]s 12 13 --comment "Done in #14"`, verb), Annotations: map[string]string{"tea.arguments": issueArguments}, Args: usageArgs(cobra.MinimumNArgs(1)), RunE: func(cmd *cobra.Command, args []string) error {
|
||||
target, numbers, err := a.resolveRefs(cmd, args, issueRef)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.dev/tea/internal/terminal"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -193,3 +194,45 @@ func TestLabelCreatePicksAColorAndPrompts(t *testing.T) {
|
||||
require.Equal(t, "From a prompt", created[1]["description"])
|
||||
require.Equal(t, []string{"Label name", "Color (hex, e.g. d73a4a; empty = random):", "Description (optional):"}, prompt.asked)
|
||||
}
|
||||
|
||||
// labelFormPrompter answers the label form with edit applied to the current values.
|
||||
type labelFormPrompter struct {
|
||||
scriptedPrompter
|
||||
heading string
|
||||
edit func(*terminal.LabelFormValues)
|
||||
}
|
||||
|
||||
func (p *labelFormPrompter) EditLabel(_ context.Context, heading string, current terminal.LabelFormValues) (terminal.LabelFormValues, error) {
|
||||
p.heading = heading
|
||||
p.edit(¤t)
|
||||
return current, nil
|
||||
}
|
||||
|
||||
func TestLabelEditFormStartsFromTheLabel(t *testing.T) {
|
||||
var edited string
|
||||
server := newAuthenticatedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.Method + " " + r.URL.Path {
|
||||
case "GET /api/v1/repos/alice/project/labels":
|
||||
if r.URL.Query().Get("page") != "1" {
|
||||
_, _ = w.Write([]byte(`[]`))
|
||||
return
|
||||
}
|
||||
_, _ = w.Write([]byte(`[{"id":11,"name":"bug","color":"ee0701","description":"Broken"}]`))
|
||||
case "PATCH /api/v1/repos/alice/project/labels/11":
|
||||
edited = requestFields(t, r, "name", "color", "description", "exclusive")
|
||||
_, _ = w.Write([]byte(`{"id":11,"name":"defect"}`))
|
||||
default:
|
||||
t.Errorf("unexpected %s %s", r.Method, r.URL.Path)
|
||||
}
|
||||
}))
|
||||
defer server.Close()
|
||||
deps, _, _ := serverDeps(t, server.URL)
|
||||
deps.Streams.InTTY, deps.Streams.ErrTTY = true, true
|
||||
prompt := &labelFormPrompter{edit: func(v *terminal.LabelFormValues) { v.Name, v.Exclusive = "defect", true }}
|
||||
deps.Prompter = prompt
|
||||
require.NoError(t, Execute(context.Background(), deps, []string{"label", "edit", "bug", "-R", "alice/project"}))
|
||||
require.Equal(t, `Editing label "bug" in alice/project`, prompt.heading)
|
||||
require.Equal(t, "name=defect color=ee0701 description=Broken exclusive=true", edited)
|
||||
deps.Streams.InTTY, deps.Streams.ErrTTY = false, false
|
||||
require.ErrorIs(t, Execute(context.Background(), deps, []string{"label", "edit", "bug", "-R", "alice/project"}), errNothingToEdit)
|
||||
}
|
||||
+17
-2
@@ -240,14 +240,19 @@ func (a *application) reportLabel(cmd *cobra.Command, s services.Labels, item se
|
||||
func (a *application) labelEditCommand(scope labelScope, complete cobra.CompletionFunc) *cobra.Command {
|
||||
var fields labelFields
|
||||
var byName bool
|
||||
cmd := &cobra.Command{Use: "edit <label>", Short: "Edit a label", Example: `$ tea label edit bug --name defect --color b60205
|
||||
cmd := &cobra.Command{Use: "edit <label>", Short: "Edit a label", Long: "Edit a label. Without flags on a terminal, a form starts from the current values.", Example: `$ tea label edit bug --name defect --color b60205
|
||||
$ tea label edit "kind/question" --description "Further information is requested"
|
||||
$ tea label edit old-stuff --archived`, Annotations: map[string]string{"tea.arguments": labelArguments}, Args: argsExact(1), RunE: func(cmd *cobra.Command, args []string) error {
|
||||
opts, err := fields.options(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if opts == (services.LabelOptions{}) {
|
||||
prompt, err := a.canPrompt()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
form, hasForm := a.deps.Prompter.(terminal.LabelForm)
|
||||
if opts == (services.LabelOptions{}) && (!prompt || !hasForm) {
|
||||
return errNothingToEdit
|
||||
}
|
||||
s, err := scope(cmd)
|
||||
@@ -258,6 +263,16 @@ $ tea label edit old-stuff --archived`, Annotations: map[string]string{"tea.argu
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if opts == (services.LabelOptions{}) {
|
||||
current := found[0]
|
||||
values, err := form.EditLabel(cmd.Context(), "Editing "+labelName(s, current), terminal.LabelFormValues{
|
||||
Name: current.Name, Color: current.Color, Description: current.Description, Exclusive: current.Exclusive, Archived: current.Archived,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts = services.LabelOptions{Name: &values.Name, Color: &values.Color, Description: &values.Description, Exclusive: &values.Exclusive, Archived: &values.Archived}
|
||||
}
|
||||
item, err := s.Edit(cmd.Context(), found[0].ID, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -18,11 +18,11 @@ import (
|
||||
// of changing them.
|
||||
func (a *application) milestoneStateCommand(verb string, service milestoneService) *cobra.Command {
|
||||
var byName bool
|
||||
state, past := "closed", "Closed"
|
||||
state, past, short := "closed", "Closed", "Close milestones"
|
||||
if verb == "reopen" {
|
||||
state, past = "open", "Reopened"
|
||||
state, past, short = "open", "Reopened", "Reopen milestones"
|
||||
}
|
||||
cmd := &cobra.Command{Use: verb + " <milestone>...", Short: titleCase(verb) + " milestones", Example: fmt.Sprintf(`$ tea milestone %[1]s v1.0
|
||||
cmd := &cobra.Command{Use: verb + " <milestone>...", Short: short, Example: fmt.Sprintf(`$ tea milestone %[1]s v1.0
|
||||
$ tea milestone %[1]s v1.0 v1.1`, verb), Annotations: map[string]string{"tea.arguments": milestoneArguments}, Args: usageArgs(cobra.MinimumNArgs(1)), RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if slices.ContainsFunc(args, func(arg string) bool { return strings.TrimSpace(arg) == "" }) {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("milestone title or ID cannot be empty"))
|
||||
|
||||
Reference in new issue
Block a user