mirror of
https://github.com/rudrankriyam/App-Store-Connect-CLI.git
synced 2026-04-25 15:45:48 +03:00
[GH-ISSUE #594] feat: Add gh-style stderr spinner (no color) #168
Labels
No labels
bug
bug
documentation
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/App-Store-Connect-CLI#168
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @rudrankriyam on GitHub (Feb 17, 2026).
Original GitHub issue: https://github.com/rudrankriyam/App-Store-Connect-CLI/issues/594
Summary
Add a GitHub CLI-style indeterminate spinner (the revolving dots/braille frames) for short-running operations.
Key goals:
GH_SPINNER_DISABLED)This is explicitly the spinner style from
gh:⣾ ⣽ ⣻ ⢿ ⡿ ⣟ ⣯ ⣷(spinner charset 11)Why this matters
A subtle spinner makes the CLI feel “alive” while it’s:
It’s especially valuable for dashboard-style commands (like the planned
asc status) where:Current state (verified)
shared.ProgressEnabled():noProgress) but no consistent spinner primitiveschollz/progressbar) for byte-based downloads.Proposed approach (Option A)
1) Build a shared spinner primitive
Add a small shared helper (stdlib only; no new deps) under
internal/cli/shared/.Proposed API (example; bikeshed ok):
Implementation rules:
os.Stderronly\rcarriage return for in-place updategh)2) Add env var kill switch
Add an env var similar to GitHub CLI:
ASC_SPINNER_DISABLEDSemantics (match
ghstyle):0,false,no, or empty) → spinner allowedThis “invalid => disabled” behavior is intentional: it makes it hard to accidentally enable spinners in CI.
3) TTY gating
Spinner should only render when BOTH:
Rationale: if stdout is being piped to a file/another process, we should be maximally quiet.
4) Adopt in safe places first
Do not blanket-wrap every command.
Initial adoption target:
asc status(issue #585)Avoid using spinner in commands that:
--debug,--api-debug, retry logs)Follow-ups (future):
UX details
No output changes
Optional label
Support a short label prefix like:
Fetching…orWorking…But keep the default label empty to match
gh statusbehavior.Implementation notes
shared.ProgressEnabled(). Consider adding:shared.SpinnerEnabled()(checksProgressEnabled+ stdout TTY + env var)Test plan (TDD-first)
Unit tests
SpinnerEnabled()behavior matrix:ASC_SPINNER_DISABLED=1|true|yes|garbageASC_SPINNER_DISABLED=0|false|no|""Cmdtests (once
asc statusexists)asc status --output jsonstdout remains valid JSONASC_SPINNER_DISABLED=1Acceptance criteria
gh-style frames (charset 11) and no ANSI color.ASC_SPINNER_DISABLEDdisables it reliably.asc status(and any other explicitly chosen, quiet commands).make testpasses.@rudrankriyam commented on GitHub (Feb 17, 2026):
Where to use this next (pagination-first)
Agree: the biggest perceived latency today is
--paginatelist flows (e.g.asc apps list --paginate). These commands often do many sequential HTTP requests and otherwise look “stuck” in the terminal.Recommendation: after the shared spinner primitive lands, adopt it in every command path that:
--paginate, andasc.PaginateAll(...)(or otherwise loops overlinks.next), andKey constraint: spinner must remain stderr-only + TTY-gated (stdout+stderr) and be disabled when output is piped.
Concrete adoption list (high priority)
These are the places that already expose
--paginateand are common/slow in real use:asc apps list --paginate(internal/cli/apps/apps.go)internal/cli/builds/builds_commands.go(builds list)internal/cli/builds/builds_related.gointernal/cli/builds/builds_relationships.gointernal/cli/builds/builds_individual_testers.gointernal/cli/builds/build_test_notes.gointernal/cli/builds/builds_uploads.gointernal/cli/testflight/testflight.go(apps/builds/groups lists)internal/cli/testflight/beta_testers.gointernal/cli/testflight/beta_groups.gointernal/cli/testflight/*relationships.go+*related.gointernal/cli/analytics/analytics_instances.gointernal/cli/analytics/analytics_reports.gointernal/cli/analytics/analytics_requests.go(explicitly recommends--paginate)internal/cli/reviews/reviews.gointernal/cli/reviews/review_submissions.gointernal/cli/reviews/review_items.gointernal/cli/reviews/review_attachments.gointernal/cli/reviews/reviews_summarizations.gointernal/cli/certificates/certificates.gointernal/cli/profiles/profiles.gointernal/cli/xcodecloud/*.go(workflows/build-runs/artifacts/test-results/scm/issues/actions/extras)Implementation note (keep it low-effort per command)
The mechanical pattern should be:
--paginateis true, wrap theasc.PaginateAll(...)call inshared.WithSpinner("", fn)This keeps the spinner:
Add to acceptance criteria (for rollout beyond
asc status)--paginate, spinner runs only when--paginateis set.--api-debug/ retry logs (disable spinner when those are enabled).@cursor please implement pagination-first adoption after the shared spinner lands.