mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
feat(label): address labels by name and add import and clone
label edit bug and label delete kind/feature failed with "invalid resource number", and label create took its name as --name and required --color. Like gh, label create takes the name as an argument and picks a random color without -c; label edit and delete take names or IDs (delete several at once, after a confirmation that names them), and -c/-d/-n/-f are the gh short flags. Without a name on a terminal, label create asks for the name, color and description. label list shows ID NAME COLOR DESCRIPTION FLAGS with a colored swatch and exclusive and archived labels flagged. Mutations report ✓ lines. label import reads a label file or stdin (label create --file still works), label clone copies another repository's labels, skipping those that exist unless --force, and label export writes to stdout by default or to -O/--output. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
10 files changed
+583
-194
No files matched your search
@@ -5,8 +5,6 @@ package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -17,162 +15,6 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func (a *application) labelCommand() *cobra.Command {
|
||||
group := &cobra.Command{Use: "label", Short: "Manage repository or organization labels"}
|
||||
var org string
|
||||
group.PersistentFlags().StringVar(&org, "org", "", "Manage organization labels instead of repository labels")
|
||||
service := func(cmd *cobra.Command) (services.Labels, error) {
|
||||
if org != "" && a.options.repo != "" {
|
||||
return services.Labels{}, clierr.Wrap(clierr.Usage, errors.New("--org and --repo are mutually exclusive"))
|
||||
}
|
||||
t, err := a.resolve(cmd.Context(), org == "")
|
||||
return services.Labels{Client: t.client, Repository: t.Repo, Organization: org}, err
|
||||
}
|
||||
group.AddCommand(a.labelExportCommand(service))
|
||||
var limit, page int
|
||||
list := &cobra.Command{Use: "list", Short: "List labels in the selected scope", Args: argsExact(0), RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
s, err := service(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
items, err := s.List(cmd.Context(), limit, page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeList(a, cmd, items, labelRow)
|
||||
}}
|
||||
pageFlags(list, &limit, &page)
|
||||
group.AddCommand(list)
|
||||
for _, verb := range []string{"create", "edit"} {
|
||||
var name, color, description, file string
|
||||
var exclusive, archived, force bool
|
||||
command := &cobra.Command{Use: verb, Short: titleCase(verb) + " a label"}
|
||||
if verb == "edit" {
|
||||
command.Use += " <id>"
|
||||
command.Args = argsExact(1)
|
||||
} else {
|
||||
command.Args = argsExact(0)
|
||||
}
|
||||
command.Flags().StringVar(&name, "name", "", "Label name")
|
||||
command.Flags().StringVar(&color, "color", "", "Six-digit RGB color")
|
||||
command.Flags().StringVar(&description, "description", "", "Label description")
|
||||
command.Flags().BoolVar(&exclusive, "exclusive", false, "Only one label from this exclusive group may be applied")
|
||||
command.Flags().BoolVar(&archived, "archived", false, "Archive the label so it cannot be newly applied")
|
||||
if verb == "create" {
|
||||
command.Flags().StringVar(&file, "file", "", "Import color/name rows with optional ;description")
|
||||
command.Flags().BoolVar(&force, "force", false, "Update the label if one with the same name exists")
|
||||
}
|
||||
command.RunE = func(cmd *cobra.Command, args []string) error {
|
||||
opts := services.LabelOptions{}
|
||||
var imported []services.LabelOptions
|
||||
var id int64
|
||||
if verb == "edit" {
|
||||
var err error
|
||||
id, err = number(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if file != "" {
|
||||
if cmd.Flags().Changed("name") || cmd.Flags().Changed("color") || cmd.Flags().Changed("description") || cmd.Flags().Changed("exclusive") || cmd.Flags().Changed("archived") {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("--file cannot be combined with label fields"))
|
||||
}
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
if imported, err = parseLabelFile(f); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if verb == "create" {
|
||||
if _, err := a.require(cmd, &name, "name"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := a.require(cmd, &color, "color"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if verb == "create" || cmd.Flags().Changed("name") {
|
||||
if name == "" {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("label name cannot be empty"))
|
||||
}
|
||||
opts.Name = &name
|
||||
}
|
||||
if verb == "create" || cmd.Flags().Changed("color") {
|
||||
color = strings.TrimPrefix(color, "#")
|
||||
if !labelColor.MatchString(color) {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("--color requires six hexadecimal digits"))
|
||||
}
|
||||
opts.Color = &color
|
||||
}
|
||||
if cmd.Flags().Changed("description") {
|
||||
opts.Description = &description
|
||||
}
|
||||
if cmd.Flags().Changed("exclusive") {
|
||||
opts.Exclusive = &exclusive
|
||||
}
|
||||
if cmd.Flags().Changed("archived") {
|
||||
opts.Archived = &archived
|
||||
}
|
||||
if opts.Name == nil && opts.Color == nil && opts.Description == nil && opts.Exclusive == nil && opts.Archived == nil {
|
||||
return clierr.Wrap(clierr.Usage, errors.New("supply label fields to edit"))
|
||||
}
|
||||
}
|
||||
s, err := service(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var existing []services.Label
|
||||
if verb == "create" {
|
||||
if existing, err = s.All(cmd.Context()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if file != "" {
|
||||
results := []services.Label{}
|
||||
var failures []error
|
||||
for _, row := range imported {
|
||||
item, err := s.CreateUnique(cmd.Context(), existing, row, force)
|
||||
if err != nil {
|
||||
failures = append(failures, fmt.Errorf("label %s: %w", *row.Name, err))
|
||||
continue
|
||||
}
|
||||
results, existing = append(results, item), append(existing, item)
|
||||
}
|
||||
return errors.Join(append(failures, writeList(a, cmd, results, labelRow))...)
|
||||
}
|
||||
var item services.Label
|
||||
if verb == "create" {
|
||||
item, err = s.CreateUnique(cmd.Context(), existing, opts, force)
|
||||
} else {
|
||||
item, err = s.Edit(cmd.Context(), id, opts)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return writeItem(a, cmd, item, labelRow)
|
||||
}
|
||||
group.AddCommand(command)
|
||||
}
|
||||
group.AddCommand(&cobra.Command{Use: "delete <id>", Short: "Delete a label", Annotations: textOutput("label deletion does not return a resource"), Args: argsExact(1), RunE: func(cmd *cobra.Command, args []string) error {
|
||||
id, err := number(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s, err := service(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := a.confirm(cmd, "Delete label "+args[0]); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.Delete(cmd.Context(), id)
|
||||
}})
|
||||
return group
|
||||
}
|
||||
|
||||
func (a *application) milestoneCommand() *cobra.Command {
|
||||
group := &cobra.Command{Use: "milestone", Short: "Manage repository milestones"}
|
||||
service := func(cmd *cobra.Command) (services.Milestones, error) {
|
||||
@@ -343,10 +185,6 @@ func (a *application) milestoneCommand() *cobra.Command {
|
||||
return group
|
||||
}
|
||||
|
||||
func labelRow(item services.Label) []terminal.Cell {
|
||||
return []terminal.Cell{{Text: strconv.FormatInt(item.ID, 10)}, {Text: item.Name, Color: item.Color}, {Text: item.Color, Color: item.Color}, {Text: item.Description}}
|
||||
}
|
||||
|
||||
func milestoneRow(item services.Milestone) []terminal.Cell {
|
||||
return []terminal.Cell{{Text: strconv.FormatInt(item.ID, 10)}, {Text: item.Title}, {Text: item.State, Color: stateColors[item.State]}}
|
||||
}
|
||||
Reference in new issue
Block a user