refactor(services): leave CLI flag and command names to the app layer

Services report ErrRunScanExhausted, ErrMaxPages and plain conflicts,
and the commands add the --branch/--max-pages/--force hints. Unknown
label names use the shared NotFoundError, and the repository-scoped
review and team search refusal moves into tea search's own usage
check.

Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
bircni committed 2026-10-12 18:44:29 +02:00
1 parent f2f1dd1e34
commit af14803b3a
10 files changed
+37 -18

No files matched your search

+3
View File
@@ -78,6 +78,9 @@ $ tea run list --since 24h --json id,status,conclusion,workflow`,
opts.Workflow = workflow.ID
}
page, err := service.RunsPage(cmd.Context(), opts)
if errors.Is(err, services.ErrRunScanExhausted) {
return fmt.Errorf("%w; narrow the search with --branch, --workflow or --status", err)
}
if err != nil {
return err
}
+5 -1
View File
@@ -256,7 +256,7 @@ func (a *application) apiCommand() *cobra.Command {
response.tty = a.deps.Streams.OutTTY
response.color = response.tty && a.colorEnabled()
}
return (services.API{Client: target.client}).Visit(cmd.Context(), services.APIOptions{Endpoint: endpoint, Method: method, Body: body, Headers: headers, Paginate: paginate, MaxPages: maxPages}, func(r *http.Response) error {
err = (services.API{Client: target.client}).Visit(cmd.Context(), services.APIOptions{Endpoint: endpoint, Method: method, Body: body, Headers: headers, Paginate: paginate, MaxPages: maxPages}, func(r *http.Response) error {
if verbose {
if err := writeRequestHead(cmd.ErrOrStderr(), r.Request); err != nil {
return err
@@ -273,6 +273,10 @@ func (a *application) apiCommand() *cobra.Command {
}
return response.write(destination, r)
})
if errors.Is(err, services.ErrMaxPages) {
return errors.New("API pagination exceeded --max-pages")
}
return err
})
}}
cmd.Flags().StringVarP(&method, "method", "X", "GET", "HTTP `method`")
+2 -2
View File
@@ -56,8 +56,8 @@ repository with --repo. Words of the query match titles and bodies.`, nouns), Ex
if opts.Team != "" && opts.Owner == "" {
return clierr.Wrap(clierr.Usage, errors.New("--team requires --owner"))
}
if opts.Team != "" && target.Repo != "" {
return clierr.Wrap(clierr.Usage, errors.New("--team requires instance-wide search; omit --repo or TEA_REPO"))
if (opts.Team != "" || opts.ReviewRequested || opts.Reviewed) && target.Repo != "" {
return clierr.Wrap(clierr.Usage, errors.New("--team, --review-requested and --reviewed require instance-wide search; omit --repo or TEA_REPO"))
}
opts.Author = target.expandMe(opts.Author)
if target.Repo != "" {
+10 -1
View File
@@ -182,7 +182,7 @@ $ tea label create bug -c ee0701 --force`, Args: usageArgs(cobra.MaximumNArgs(1)
}
item, updated, err := s.CreateUnique(cmd.Context(), existing, opts, force)
if err != nil {
return err
return forceHint(err)
}
return a.reportLabel(cmd, s, item, updated)
}}
@@ -220,6 +220,14 @@ func (a *application) askLabelDetails(cmd *cobra.Command, opts *services.LabelOp
return nil
}
// forceHint points at --force when a label exists already.
func forceHint(err error) error {
if conflict, ok := errors.AsType[*services.ConflictError](err); ok && conflict.Reason == services.ReasonExists {
conflict.Hint = "pass --force to update it"
}
return err
}
// reportLabel reports a created or updated label as JSON or with a ✓ line.
func (a *application) reportLabel(cmd *cobra.Command, s services.Labels, item services.Label, updated bool) error {
verb := "Created"
@@ -336,6 +344,7 @@ func (a *application) createLabels(cmd *cobra.Command, s services.Labels, rows [
outcome := map[string]string{}
results, failures := applyBatch(cmd, rows, func(row services.LabelOptions) string { return "label " + strconv.Quote(*row.Name) }, func(row services.LabelOptions) (services.Label, error) {
item, updated, err := s.CreateUnique(cmd.Context(), existing, row, force)
err = forceHint(err)
switch {
case err != nil:
return item, err