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
@@ -25,23 +25,41 @@ func (s Labels) finder(byName bool) NameOrID[Label] {
|
||||
return NameOrID[Label]{Kind: "label", Scope: s.Scope(), ID: func(l Label) int64 { return l.ID }, Name: func(l Label) string { return l.Name }, ByName: byName}
|
||||
}
|
||||
|
||||
// Find returns the labels of the scope that raws address, each by ID or name (D10); byName matches
|
||||
// numeric values as names only.
|
||||
func (s Labels) Find(ctx context.Context, raws []string, byName bool) ([]Label, error) {
|
||||
items, err := s.All(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]Label, len(raws))
|
||||
for i, raw := range raws {
|
||||
if result[i], err = s.finder(byName).Find(items, raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CreateUnique creates a label unless existing, the labels of the scope, has one with its name,
|
||||
// ignoring case. Then update edits that label with the supplied fields, keeping its name, and
|
||||
// otherwise CreateUnique fails: Gitea would create a second label that name filters cannot tell
|
||||
// apart.
|
||||
func (s Labels) CreateUnique(ctx context.Context, existing []Label, opts LabelOptions, update bool) (Label, error) {
|
||||
// apart. It reports whether it updated a label.
|
||||
func (s Labels) CreateUnique(ctx context.Context, existing []Label, opts LabelOptions, update bool) (Label, bool, error) {
|
||||
current, err := s.finder(true).Find(existing, deref(opts.Name))
|
||||
if errors.As(err, new(*NotFoundError)) {
|
||||
return s.Create(ctx, opts)
|
||||
label, err := s.Create(ctx, opts)
|
||||
return label, false, err
|
||||
}
|
||||
if err != nil {
|
||||
return Label{}, err
|
||||
return Label{}, false, err
|
||||
}
|
||||
if !update {
|
||||
return Label{}, &ConflictError{Reason: ReasonExists, Kind: "label", Key: strconv.Quote(current.Name), Scope: s.Scope(), Hint: "pass --force to update it"}
|
||||
return Label{}, false, &ConflictError{Reason: ReasonExists, Kind: "label", Key: strconv.Quote(current.Name), Scope: s.Scope(), Hint: "pass --force to update it"}
|
||||
}
|
||||
opts.Name = nil
|
||||
return s.Edit(ctx, current.ID, opts)
|
||||
label, err := s.Edit(ctx, current.ID, opts)
|
||||
return label, true, err
|
||||
}
|
||||
|
||||
func selectLabelNames(scope string, names []string, matches map[string][]int64) ([]int64, error) {
|
||||
|
||||
@@ -45,7 +45,24 @@ func (s Labels) orgEndpoint() string { return "orgs/" + url.PathEscape(s.Organiz
|
||||
|
||||
// List returns scoped labels without merging unrelated organization labels.
|
||||
func (s Labels) List(ctx context.Context, limit, page int) ([]Label, error) {
|
||||
labels, _, err := call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Label, *gitea.Response, error) {
|
||||
labels, _, err := s.list(ctx, limit, page)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertAll(labels, labelFrom), nil
|
||||
}
|
||||
|
||||
// ListPage is List with the number of labels in the scope, as the server counts them.
|
||||
func (s Labels) ListPage(ctx context.Context, limit, page int) (Page[Label], error) {
|
||||
labels, err := listPage(limit, page, func(limit, page int) ([]*gitea.Label, http.Header, error) {
|
||||
labels, resp, err := s.list(ctx, limit, page)
|
||||
return labels, headerOf(resp), err
|
||||
})
|
||||
return Page[Label]{Items: convertAll(labels.Items, labelFrom), More: labels.More, Total: labels.Total, Counted: labels.Counted}, err
|
||||
}
|
||||
|
||||
func (s Labels) list(ctx context.Context, limit, page int) ([]*gitea.Label, *gitea.Response, error) {
|
||||
return call(ctx, s.Client, func(ctx context.Context, c *gitea.Client) ([]*gitea.Label, *gitea.Response, error) {
|
||||
if s.Organization != "" {
|
||||
return c.Organizations.ListOrgLabels(ctx, s.Organization, gitea.ListOrgLabelsOptions{ListOptions: listOptions(limit, page)})
|
||||
}
|
||||
@@ -55,10 +72,6 @@ func (s Labels) List(ctx context.Context, limit, page int) ([]Label, error) {
|
||||
}
|
||||
return c.Repositories.ListRepoLabels(ctx, owner, repo, gitea.ListLabelsOptions{ListOptions: listOptions(limit, page)})
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return convertAll(labels, labelFrom), nil
|
||||
}
|
||||
|
||||
// All returns every label in the scope.
|
||||
|
||||
Reference in new issue
Block a user