refactor(output): share the JSON, created-resource and batch tails

Mutations end with a.jsonResult or a.created instead of hand-rolled
--json branches, the two identical jsonResult/writeMutationJSON helpers
become one, and writeBatchJSON checks --json itself so batch commands
share one tail.

Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
bircni committed 2026-10-12 10:43:46 +02:00
1 parent 27e39ec4be
commit 6b204a34c0
32 files changed
+85 -215

No files matched your search

+2 -8
View File
@@ -617,11 +617,8 @@ $ tea run cancel 34 --force`,
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, run)
}
a.done(cmd, "Requested cancellation of run %d", id)
return nil
return a.jsonResult(cmd, run)
},
}
cmd.Flags().BoolVar(&force, "force", false, "Cancel without waiting for the runner to acknowledge")
@@ -678,11 +675,8 @@ $ tea run rerun 34 --job build`,
if run, err = service.Run(cmd.Context(), id); err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, run)
}
a.done(cmd, "Requested rerun of run %d (attempt %d); watch it with: tea run watch %d%s", id, run.Attempt, id, a.suggestedRepo(t))
return nil
return a.jsonResult(cmd, run)
},
}
cmd.Flags().BoolVar(&failed, "failed", false, "Rerun only the failed jobs")
+2 -5
View File
@@ -243,7 +243,7 @@ $ tea workflow run nightly --follow`,
if !follow {
a.nextStep(cmd, "Watch it: tea run watch %d%s", result.ID, a.suggestedRepo(t))
}
if err := a.printURL(cmd, result.URL); err != nil || !follow {
if err := a.created(cmd, result, result.URL); err != nil || !follow {
return err
}
ctx, cancel := context.WithTimeout(cmd.Context(), timeout)
@@ -474,10 +474,7 @@ $ tea workflow %s Nightly`, verb, verb),
}
a.done(cmd, "%s %s", done, workflow.Label())
}
if a.options.json != "" {
return a.writeJSON(cmd, workflow)
}
return nil
return a.jsonResult(cmd, workflow)
},
}
}
+1 -4
View File
@@ -280,10 +280,7 @@ $ tea admin user create ci-bot --email ci@example.com --password-file pw.txt --m
return err
}
a.done(cmd, "Created user %s", user.Username)
if err := a.printURL(cmd, user.URL); err != nil {
return err
}
return a.jsonResult(cmd, user)
return a.created(cmd, user, user.URL)
}
return command
}
+1 -1
View File
@@ -196,7 +196,7 @@ $ tea branch create bisect --source 3f2a9c1`,
} else {
a.done(cmd, "Created branch %s from %s in %s at %s", item.Name, source, target.Repo, shortSHA(item.SHA))
}
return a.writeMutationJSON(cmd, item)
return a.jsonResult(cmd, item)
},
}
command.Flags().StringVarP(&source, "source", "s", "", "Branch, tag or commit to start from (default: the default branch)")
+1 -4
View File
@@ -143,15 +143,12 @@ argument select it, and the branch tracks the head branch, so that git push upda
undoRemote()
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, result)
}
if result.Detached {
a.done(cmd, "Checked out #%d at %s (detached HEAD)", n, shortSHA(result.Commit))
} else {
a.done(cmd, "Checked out #%d into %s", n, result.Branch)
}
return nil
return a.jsonResult(cmd, result)
}}
cmd.Flags().BoolVar(&update, "update", false, "Fast-forward an existing branch to the PR head; reject divergence")
cmd.Flags().BoolVar(&detached, "detach", false, "Check out the PR commit without creating or changing a branch")
+2 -8
View File
@@ -142,11 +142,8 @@ func (a *application) commentOn(cmd *cobra.Command, t target, n int64, kind refK
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, comment)
}
a.done(cmd, "Commented on %s", refLabel(t.Repo, n, item.Title))
return a.printURL(cmd, comment.URL)
return a.created(cmd, comment, comment.URL)
}
// lastComment returns the newest comment on n by the account tea acts as.
@@ -185,11 +182,8 @@ func (a *application) editComment(cmd *cobra.Command, t target, comment services
return err
}
edited.IssueNumber = comment.IssueNumber
if a.options.json != "" {
return a.writeJSON(cmd, edited)
}
a.done(cmd, "Edited %s", commentName(t, edited))
return nil
return a.jsonResult(cmd, edited)
}
// deleteComment deletes comment after a confirmation that defaults to no.
+19 -11
View File
@@ -149,12 +149,20 @@ func (a *application) feedback(cmd *cobra.Command, icon, color, format string, a
fmt.Fprintln(cmd.ErrOrStderr(), terminal.Colorize(color, icon, a.colorEnabled())+" "+terminal.SafeLine(fmt.Sprintf(format, args...)))
}
// printURL writes the URL of a created resource to stdout unless --json is set, so scripts can
// capture it: url=$(tea issue create …).
func (a *application) printURL(cmd *cobra.Command, url string) error {
if a.options.json != "" {
// jsonResult writes the result of a mutation when --json asks for it; people get a done line instead.
func (a *application) jsonResult(cmd *cobra.Command, item any) error {
if a.options.json == "" {
return nil
}
return a.writeJSON(cmd, item)
}
// created writes a created resource as JSON with --json, else its URL to stdout, so scripts can
// capture it: url=$(tea issue create …).
func (a *application) created(cmd *cobra.Command, item any, url string) error {
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
_, err := fmt.Fprintln(cmd.OutOrStdout(), terminal.SafeLine(url))
return err
}
@@ -170,7 +178,7 @@ type abortBatch struct{ error }
func (e abortBatch) Unwrap() error { return e.error }
// applyBatch applies run to each selection and continues past individual failures, which it
// returns prefixed with the selection's label. succeeded sees each result as it arrives.
// returns prefixed with the selection's label. succeeded, when set, sees each result as it arrives.
func applyBatch[K, T any](cmd *cobra.Command, keys []K, label func(K) string, run func(K) (T, error), succeeded func(T)) ([]T, []error) {
results := []T{}
var failures []error
@@ -189,14 +197,18 @@ func applyBatch[K, T any](cmd *cobra.Command, keys []K, label func(K) string, ru
continue
}
results = append(results, item)
if succeeded != nil {
succeeded(item)
}
}
return results, failures
}
// writeBatchJSON writes an object for one selection (none if it failed), otherwise an array.
// writeBatchJSON writes, with --json, an object for one selection (none if it failed), otherwise an array.
func writeBatchJSON[T any](a *application, cmd *cobra.Command, selections int, results []T) error {
switch {
case a.options.json == "":
return nil
case selections != 1:
return a.writeJSON(cmd, results)
case len(results) == 1:
@@ -209,11 +221,7 @@ func writeBatchJSON[T any](a *application, cmd *cobra.Command, selections int, r
// line from report, such as "Closed issue alice/x#5 (Fix login)", and the results as JSON.
func batchDone[K, T any](a *application, cmd *cobra.Command, keys []K, label func(K) string, run func(K) (T, error), report func(T) string) error {
results, failures := applyBatch(cmd, keys, label, run, func(item T) { a.done(cmd, "%s", report(item)) })
var err error
if a.options.json != "" {
err = writeBatchJSON(a, cmd, len(keys), results)
}
return errors.Join(append(failures, err)...)
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(keys), results))...)
}
// stateColors colors issue, pull request and milestone states with the terminal's own palette.
+5 -1
View File
@@ -379,8 +379,12 @@ func TestMutationFeedback(t *testing.T) {
ref := refLabel("alice/x", 12, "Fix\x1b[2J login")
a.done(cmd, "Created issue %s", ref)
a.warn(cmd, "Issue %s is already closed", ref)
require.NoError(t, a.printURL(cmd, "https://example.org/12"))
require.NoError(t, a.created(cmd, map[string]int{"number": 12}, "https://example.org/12"))
if tc.json != "" {
require.JSONEq(t, `{"number":12}`, out.String())
} else {
require.Equal(t, tc.out, out.String())
}
require.Equal(t, tc.stderr, diagnostics.String())
})
}
+2 -8
View File
@@ -111,11 +111,8 @@ $ tea %[1]s attachment upload %[2]s screenshot.png --name before.png`, words.gro
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
a.done(cmd, "Uploaded %s (%s) to %s#%d", item.Name, terminal.Bytes(item.Size), t.Repo, n)
return a.printURL(cmd, item.URL)
return a.created(cmd, item, item.URL)
}}
upload.Flags().StringVar(&uploadName, "name", "", "File `name` of the attachment (default: the local file name)")
@@ -132,11 +129,8 @@ $ tea %[1]s attachment upload %[2]s screenshot.png --name before.png`, words.gro
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
a.done(cmd, "Renamed %s", attachmentName(t, n, item))
return nil
return a.jsonResult(cmd, item)
}}
edit.Flags().StringVar(&newName, "name", "", "New file `name`")
+7 -14
View File
@@ -317,7 +317,7 @@ $ tea issue create --title "Idea" --web`, Args: argsExact(0), RunE: func(cmd *co
failures = append(failures, fmt.Errorf("issue %d created; attachment %s upload failed: %w", item.Number, filepath.Base(file.Name()), err))
}
}
return errors.Join(append(failures, a.created(cmd, target, item))...)
return errors.Join(append(failures, a.issueCreated(cmd, target, item))...)
}}
flags := cmd.Flags()
flags.StringVarP(&title, "title", "t", "", "Issue title")
@@ -340,13 +340,10 @@ $ tea issue create --title "Idea" --web`, Args: argsExact(0), RunE: func(cmd *co
return cmd
}
// created reports a new issue: as JSON, or its URL on stdout after a ✓ line for people.
func (a *application) created(cmd *cobra.Command, t target, item services.Issue) error {
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
// issueCreated reports a new issue: as JSON, or its URL on stdout after a ✓ line for people.
func (a *application) issueCreated(cmd *cobra.Command, t target, item services.Issue) error {
a.done(cmd, "Created issue %s", refLabel(t.Repo, item.Number, item.Title))
return a.printURL(cmd, item.URL)
return a.created(cmd, item, item.URL)
}
func (a *application) createIssueInteractively(cmd *cobra.Command) (runErr error) {
@@ -379,7 +376,7 @@ func (a *application) createIssueInteractively(cmd *cobra.Command) (runErr error
if err != nil {
return err
}
return a.created(cmd, target, item)
return a.issueCreated(cmd, target, item)
}
// issueTemplateBody seeds a body from markdown content, or from the description of form templates.
@@ -445,12 +442,8 @@ $ tea issue %[1]s 12 13 --comment "Done in #14"`, verb), Annotations: map[string
}
a.done(cmd, "%s %s %s", past, discussionNoun(item.Kind), refLabel(target.Repo, n, item.Title))
return item, nil
}, func(services.Issue) {})
var err2 error
if a.options.json != "" {
err2 = writeBatchJSON(a, cmd, len(numbers), results)
}
return errors.Join(append(failures, err2)...)
}, nil)
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(numbers), results))...)
}}
cmd.Flags().StringVarP(&comment, "comment", "c", "", "Leave a comment before the issue is "+state)
cmd.ValidArgsFunction = a.completeIssueArgs(completeState, true)
+3 -12
View File
@@ -226,15 +226,12 @@ func (a *application) askLabelDetails(cmd *cobra.Command, opts *services.LabelOp
// 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 {
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
verb := "Created"
if updated {
verb = "Updated"
}
a.done(cmd, "%s %s", verb, labelName(s, item))
return nil
return a.jsonResult(cmd, item)
}
func (a *application) labelEditCommand(scope labelScope, complete cobra.CompletionFunc) *cobra.Command {
@@ -262,11 +259,8 @@ $ tea label edit old-stuff --archived`, Annotations: map[string]string{"tea.argu
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
a.done(cmd, "Edited %s", labelName(s, item))
return nil
return a.jsonResult(cmd, item)
}}
fields.register(cmd, "Rename the label")
cmd.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a label name rather than an ID")
@@ -359,10 +353,7 @@ func (a *application) createLabels(cmd *cobra.Command, s services.Labels, rows [
}, func(item services.Label) {
a.done(cmd, "%s %s", outcome[item.Name], labelName(s, item))
})
if a.options.json != "" {
failures = append(failures, writeBatchJSON(a, cmd, len(rows), results))
}
return errors.Join(failures...)
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(rows), results))...)
}
// completeScopedLabels completes the label names of the repository or, with --org, of the
+3 -12
View File
@@ -274,11 +274,8 @@ $ tea milestone create --title v2.0 --editor`, Args: usageArgs(cobra.MaximumNArg
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
a.done(cmd, "Created %s", milestoneName(t, item))
return a.printURL(cmd, milestoneURL(t, item))
return a.created(cmd, item, milestoneURL(t, item))
}}
fields.register(cmd)
enumFlag(cmd, &state, "state", "", "open", "State of the new milestone", "open", "closed")
@@ -338,11 +335,8 @@ $ tea milestone edit 3 --editor`, Annotations: map[string]string{"tea.arguments"
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
a.done(cmd, "Edited %s", milestoneName(t, item))
return nil
return a.jsonResult(cmd, item)
}}
fields.register(cmd)
cmd.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
@@ -369,11 +363,8 @@ $ tea milestone delete 7 --yes`, Annotations: map[string]string{"tea.confirm": "
if err := s.Delete(cmd.Context(), item.ID); err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
a.done(cmd, "Deleted milestone %q from %s", item.Title, t.Repo)
return nil
return a.jsonResult(cmd, item)
}}
cmd.Flags().BoolVar(&byName, "by-name", false, "Match a numeric argument as a milestone title rather than an ID")
cmd.ValidArgsFunction = a.completeMilestoneArgs(false)
+2 -5
View File
@@ -66,7 +66,7 @@ $ tea milestone issue %[1]s v1.0 12 13 '#14'`, verb), Annotations: map[string]st
item, err = service.Edit(cmd.Context(), n, services.IssueEdit{Milestone: &milestone.ID})
}
return item, itemError(err, target.Repo)
}, func(services.Issue) {})
}, nil)
if len(results) > 0 {
changed := make([]string, len(results))
for i, item := range results {
@@ -74,10 +74,7 @@ $ tea milestone issue %[1]s v1.0 12 13 '#14'`, verb), Annotations: map[string]st
}
a.done(cmd, "%s %s %s %s", past, strings.Join(changed, ", "), preposition, milestoneName(target, milestone))
}
if a.options.json != "" {
failures = append(failures, writeBatchJSON(a, cmd, len(numbers), results))
}
return errors.Join(failures...)
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(numbers), results))...)
}}
command.Flags().BoolVar(&byName, "by-name", false, "Match a numeric milestone argument as a title rather than an ID")
milestones, issues := a.completeMilestones(), a.completeIssues("open")
+2 -5
View File
@@ -50,11 +50,8 @@ $ tea milestone %[1]s v1.0 v1.1`, verb), Annotations: map[string]string{"tea.arg
a.done(cmd, "%s %s", past, milestoneName(t, item))
}
return item, err
}, func(services.Milestone) {})
if a.options.json != "" {
failures = append(failures, writeBatchJSON(a, cmd, len(selected), results))
}
return errors.Join(failures...)
}, nil)
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(selected), results))...)
}}
cmd.Flags().BoolVar(&byName, "by-name", false, "Match numeric arguments as milestone titles rather than IDs")
cmd.ValidArgsFunction = a.completeMilestoneArgs(true)
+1 -12
View File
@@ -23,14 +23,6 @@ var visibilities = []string{"public", "limited", "private"}
// visibilityColors color the visibility of organizations and accounts.
var visibilityColors = map[string]string{"public": "green", "limited": "yellow", "private": "red"}
// jsonResult writes the result of a mutation when --json asks for it; people get a done line instead.
func (a *application) jsonResult(cmd *cobra.Command, item any) error {
if a.options.json == "" {
return nil
}
return a.writeJSON(cmd, item)
}
// timeField shows an API timestamp relative to now on a TTY, and as RFC3339 for scripts.
func timeField(label, raw string, d terminal.Display) terminal.Field {
t := terminal.ParseTime(raw)
@@ -250,10 +242,7 @@ $ tea org create acme-internal --visibility private`,
return err
}
a.done(cmd, "Created organization %s", org.Name)
if err := a.printURL(cmd, webURL(target, org.Name)); err != nil {
return err
}
return a.jsonResult(cmd, org)
return a.created(cmd, org, webURL(target, org.Name))
}
return cmd
}
+1 -4
View File
@@ -103,9 +103,6 @@ func (a *application) pullCleanCommand() *cobra.Command {
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, result)
}
a.done(cmd, "Deleted local branch %s", result.LocalBranch)
switch {
case result.RemoteDeleted:
@@ -115,7 +112,7 @@ func (a *application) pullCleanCommand() *cobra.Command {
case !pull.HeadCanPush:
a.warn(cmd, "Kept remote branch %s: you cannot push to %s", pull.Head, pull.HeadRepo)
}
return nil
return a.jsonResult(cmd, result)
}}
cmd.Flags().BoolVar(&ignoreSHA, "ignore-sha", false, "Find the local branch by name instead of commit hash")
cmd.ValidArgsFunction = a.completePulls("closed")
+1 -4
View File
@@ -371,8 +371,5 @@ func (a *application) createPullInteractively(cmd *cobra.Command, snapshot setti
// reportCreatedPull reports a new pull request and prints its URL, or the pull request as JSON.
func (a *application) reportCreatedPull(cmd *cobra.Command, t target, item services.Pull) error {
a.done(cmd, "Created pull request %s", refLabel(t.Repo, item.Number, item.Title))
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return a.printURL(cmd, item.URL)
return a.created(cmd, item, item.URL)
}
+2 -8
View File
@@ -125,10 +125,7 @@ pull request, or mark it as a draft or ready for review.`, Annotations: pullArgu
return err
}
a.done(cmd, "Edited pull request %s", refLabel(t.Repo, n, item.Title))
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return nil
return a.jsonResult(cmd, item)
}}
cmd.Flags().StringVarP(&title, "title", "t", "", "Pull request title")
cmd.Flags().StringVar(&deadline, "deadline", "", "Due date: YYYY-MM-DD, RFC3339, or Unix timestamp; empty clears")
@@ -206,10 +203,7 @@ removes or adds that marker.`, Annotations: pullArgumentsAnnotation(nil), Args:
a.done(cmd, "Marked pull request %s as ready for review", refLabel(t.Repo, n, item.Title))
}
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return nil
return a.jsonResult(cmd, item)
}}
cmd.Flags().BoolVar(&undo, "undo", false, "Turn the pull request back into a draft")
cmd.ValidArgsFunction = a.completePulls("open")
+3 -12
View File
@@ -109,10 +109,7 @@ func (a *application) pullStateCommand(closing bool) *cobra.Command {
if deleteBranch {
a.deleteHead(cmd, service, item, false)
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return nil
return a.jsonResult(cmd, item)
}}
cmd.Flags().StringVarP(&comment, "comment", "c", "", "Leave a comment before changing the state")
cmd.ValidArgsFunction = a.completePulls(map[bool]string{true: "open", false: "closed"}[closing])
@@ -302,10 +299,7 @@ the base branch.`, Annotations: pullArgumentsAnnotation(map[string]string{"tea.c
switch {
case item.Merged:
a.warn(cmd, "Pull request %s is already merged", ref)
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return nil
return a.jsonResult(cmd, item)
case item.State == "closed":
return fmt.Errorf("pull request %s is closed; reopen it with: tea pr reopen %d", ref, n)
case item.Draft:
@@ -362,10 +356,7 @@ the base branch.`, Annotations: pullArgumentsAnnotation(map[string]string{"tea.c
a.deleteHead(cmd, service, merged, true)
}
}
if a.options.json != "" {
return a.writeJSON(cmd, merged)
}
return nil
return a.jsonResult(cmd, merged)
}}
enumFlag(cmd, &method, "method", "s", "", "Merge method (default: the repository's default merge style)", mergeMethods...)
cmd.Flags().StringVar(&method, "style", "", "Alias of --method")
+4 -10
View File
@@ -268,14 +268,11 @@ func ownReview(pull services.Pull, t target, state string) error {
// reportReview reports a submitted review, then prints its URL, or the review as JSON.
func (a *application) reportReview(cmd *cobra.Command, t target, pull services.Pull, item services.Review) error {
a.done(cmd, "%s pull request %s", reviewVerbs[item.State], refLabel(t.Repo, pull.Number, pull.Title))
switch {
case a.options.json != "":
return a.writeJSON(cmd, item)
case item.URL != "":
return a.printURL(cmd, item.URL)
}
if a.options.json == "" && item.URL == "" {
return nil
}
return a.created(cmd, item, item.URL)
}
// readInlineComments reads the inline comments of --comments-file, a JSON array.
func readInlineComments(path string) ([]services.InlineComment, error) {
@@ -625,10 +622,7 @@ func (a *application) pullReviewReplyCommand() *cobra.Command {
return err
}
a.done(cmd, "Replied to review comment %d on %s#%d", id, t.Repo, n)
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return a.printURL(cmd, item.URL)
return a.created(cmd, item, item.URL)
}}
cmd.Flags().StringVarP(&body, "body", "b", "", "Reply body")
cmd.Flags().StringVarP(&file, "body-file", "F", "", "Read the body from `file`, or - for stdin")
+1 -4
View File
@@ -204,10 +204,7 @@ func (a *application) pullReviewDismissCommand(dismiss bool) *cobra.Command {
} else {
a.done(cmd, "Restored %s", subject)
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return nil
return a.jsonResult(cmd, item)
}}
if dismiss {
cmd.Annotations["tea.confirm"] = "true"
+1 -4
View File
@@ -42,10 +42,7 @@ func (a *application) pullReviewRequestCommand(add bool) *cobra.Command {
names = append(names, "team "+team)
}
a.done(cmd, "%s %s on %s", verb, strings.Join(names, ", "), refLabel(t.Repo, item.Number, item.Title))
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return nil
return a.jsonResult(cmd, item)
}}
cmd.Flags().StringSliceVarP(&input.Users, "reviewer", "r", nil, "Reviewer usernames or email addresses; @me for yourself")
cmd.Flags().StringSliceVar(&input.Teams, "team", nil, "Teams of the repository's organization")
+1 -1
View File
@@ -352,7 +352,7 @@ func (a *application) assetEditCommand() *cobra.Command {
return err
}
a.done(cmd, "Renamed asset %s to %s in release %s", asset.Name, item.Name, release.Tag)
return a.writeMutationJSON(cmd, item)
return a.jsonResult(cmd, item)
},
}
command.Flags().StringVar(&name, "name", "", "New asset name")
+3 -11
View File
@@ -300,12 +300,7 @@ $ tea release create v1.1.0-rc1 --target release/1.1 --draft --prerelease --titl
item.Assets = append(item.Assets, asset)
a.done(cmd, "Uploaded %s (%s)", asset.Name, terminal.Bytes(asset.Size))
}
if a.options.json != "" {
failures = append(failures, a.writeJSON(cmd, item))
} else {
failures = append(failures, a.printURL(cmd, item.URL))
}
return errors.Join(failures...)
return errors.Join(append(failures, a.created(cmd, item, item.URL))...)
},
}
fields.register(a, command)
@@ -402,11 +397,8 @@ func (a *application) releasePublishCommand() *cobra.Command {
a.done(cmd, "Published release %s in %s", item.Tag, target.Repo)
}
return item, err
}, func(services.Release) {})
if a.options.json != "" {
failures = append(failures, writeBatchJSON(a, cmd, len(args), results))
}
return errors.Join(failures...)
}, nil)
return errors.Join(append(failures, writeBatchJSON(a, cmd, len(args), results))...)
},
}
command.ValidArgsFunction = a.completeReleases()
+5 -16
View File
@@ -278,7 +278,7 @@ $ tea repo clone alice/project -- --branch develop --recurse-submodules`,
if _, err := a.cloneRepository(cmd, t, item, opts); err != nil {
return err
}
return a.writeMutationJSON(cmd, item)
return a.jsonResult(cmd, item)
},
}
command.Flags().IntVarP(&opts.depth, "depth", "d", 0, "Number of commits to fetch (0: full history)")
@@ -352,10 +352,7 @@ $ tea repo fork alice/project --clone -- --depth 1`,
return err
}
}
if a.options.json != "" {
return a.writeJSON(cmd, fork)
}
return a.printURL(cmd, fork.URL)
return a.created(cmd, fork, fork.URL)
},
}
command.Flags().StringVar(&opts.Organization, "org", "", "Fork into this organization")
@@ -552,7 +549,7 @@ $ tea repo archive alice/old-project --yes`,
} else {
a.warn(cmd, "%s is not archived", item.FullName)
}
return a.writeMutationJSON(cmd, item)
return a.jsonResult(cmd, item)
}
if archive {
if err := a.confirmAction(cmd, terminal.Confirmation{Prompt: "Archive " + t.Repo + inferred + "? It becomes read-only.", NonTTY: "archive " + t.Repo}); err != nil {
@@ -568,20 +565,12 @@ $ tea repo archive alice/old-project --yes`,
} else {
a.done(cmd, "Unarchived repository %s", item.FullName)
}
return a.writeMutationJSON(cmd, item)
return a.jsonResult(cmd, item)
}
command.ValidArgsFunction = a.completeRepos()
return command
}
// writeMutationJSON writes the result of a mutation with --json; people get done lines instead.
func (a *application) writeMutationJSON(cmd *cobra.Command, item any) error {
if a.options.json == "" {
return nil
}
return a.writeJSON(cmd, item)
}
func (a *application) repoRenameCommand() *cobra.Command {
command := &cobra.Command{
Use: "rename <new-name>",
@@ -624,7 +613,7 @@ $ tea repo rename new-name -R alice/old-name`,
if remote, ok := strings.CutPrefix(t.RepoSource, "remote "); ok {
a.warn(cmd, "Git remote %s still points to %s; update it with git remote set-url", remote, t.Repo)
}
return a.writeMutationJSON(cmd, item)
return a.jsonResult(cmd, item)
},
}
return command
+1 -4
View File
@@ -159,10 +159,7 @@ $ tea repo create project --source . --push`,
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return a.printURL(cmd, item.URL)
return a.created(cmd, item, item.URL)
},
}
flags := command.Flags()
+1 -4
View File
@@ -143,10 +143,7 @@ $ tea repo migrate https://github.com/acme/tool --service github --issues --pull
detail = " (pull mirror)"
}
a.done(cmd, "Imported %s into %s%s", opts.CloneURL, item.FullName, detail)
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return a.printURL(cmd, item.URL)
return a.created(cmd, item, item.URL)
},
}
flags := command.Flags()
+3 -6
View File
@@ -91,11 +91,8 @@ $ tea repo sync bob/project`,
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, result)
}
a.reportSync(cmd, result, remote+"/"+result.Branch)
return nil
return a.jsonResult(cmd, result)
},
}
command.Flags().StringVarP(&branch, "branch", "b", "", "Branch to sync (default: the repository's default branch)")
@@ -118,7 +115,7 @@ func (a *application) syncOnServer(cmd *cobra.Command, t target, branch string)
return err
}
a.done(cmd, "Started updating the mirror %s from its source", item.FullName)
return a.writeMutationJSON(cmd, git.SyncResult{Remote: mirrorSourceURL(item)})
return a.jsonResult(cmd, git.SyncResult{Remote: mirrorSourceURL(item)})
case !item.Fork || item.Parent == nil:
return clierr.Wrap(clierr.Usage, fmt.Errorf("%s is neither a fork nor a mirror, and has no Git remote here; run tea repo sync inside a clone of it", item.FullName))
}
@@ -141,7 +138,7 @@ func (a *application) syncOnServer(cmd *cobra.Command, t target, branch string)
} else {
a.done(cmd, "Synced %s %s from %s (fast-forward %s..%s)", item.FullName, branch, item.Parent.FullName, shortSHA(result.Previous), shortSHA(result.Commit))
}
return a.writeMutationJSON(cmd, result)
return a.jsonResult(cmd, result)
}
// reportSync tells how a sync from source, such as origin/main, changed the branch.
+1 -4
View File
@@ -380,10 +380,7 @@ $ tea team create acme ops --permission admin --all-repositories`,
return err
}
a.done(cmd, "Created team %s (ID %d) with %s access", team.Slug(), team.ID, team.Access())
if err := a.printURL(cmd, teamURL(target, team)); err != nil {
return err
}
return a.jsonResult(cmd, team)
return a.created(cmd, team, teamURL(target, team))
},
}
flags.register(cmd, true)
+1 -4
View File
@@ -174,11 +174,8 @@ $ tea time log https://gitea.com/OWNER/REPO/issues/12 45m`, Annotations: map[str
if err != nil {
return err
}
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
a.done(cmd, "Logged %s on %s", spent(item.Seconds), strings.TrimSuffix(refLabel(target.Repo, n, item.IssueTitle), " ()"))
return nil
return a.jsonResult(cmd, item)
}}
}
+1 -4
View File
@@ -431,10 +431,7 @@ $ tea webhook create https://hooks.slack.com/services/T0/B0/X --org acme --type
return err
}
a.done(cmd, "Created %s in %s for %s", webhookLabel(hook), webhookScopeName(service.Scope), collapsedEvents(hook.Events))
if err := a.printURL(cmd, webhookSettingsURL(target, service.Scope, hook.ID)); err != nil {
return err
}
return a.jsonResult(cmd, hook)
return a.created(cmd, hook, webhookSettingsURL(target, service.Scope, hook.ID))
}
return command
}
+2 -5
View File
@@ -213,10 +213,7 @@ $ tea wiki create Home --editor`,
return err
}
a.done(cmd, "Created wiki page %q in %s", item.Title, target.Repo)
if a.options.json != "" {
return a.writeJSON(cmd, item)
}
return a.printURL(cmd, item.URL)
return a.created(cmd, item, item.URL)
},
}
content.register(command)
@@ -298,7 +295,7 @@ $ tea wiki edit Home --editor`,
} else {
a.done(cmd, "Edited wiki page %q in %s", item.Title, target.Repo)
}
return a.writeMutationJSON(cmd, item)
return a.jsonResult(cmd, item)
},
}
content.register(command)