Skip to content

feat(arcade-cli): remember login host for subsequent commands#847

Closed
EricGustin wants to merge 4 commits into
mainfrom
ericgustin/wizardly-einstein-3cbb77
Closed

feat(arcade-cli): remember login host for subsequent commands#847
EricGustin wants to merge 4 commits into
mainfrom
ericgustin/wizardly-einstein-3cbb77

Conversation

@EricGustin

@EricGustin EricGustin commented May 17, 2026

Copy link
Copy Markdown
Member

Summary

arcade login -h cloud.X.dev now persists the matching Engine URL so every subsequent CLI command (engine-side and coordinator-side) targets that environment by default. Today, users who log into a non-prod host have to repeat -h on every command, and confusingly some commands expect the Coordinator host (cloud.X.dev) while others expect the Engine host (api.X.dev).

Resolution order is now: explicit flags > saved URL > production default.

Resolves:

Design decisions

  • Stored both URLs explicitly. coordinator_url was already persisted but never used as a default; this PR adds engine_url next to it. Storing both is simpler and clearer than recomputing the engine URL on every command.
  • Convention-based derivation. derive_engine_url_from_coordinator swaps the cloud. prefix for api. and preserves the port; localhost gets localhost:9099. Unknown hostnames return None so the caller falls back to prod, matching today's behavior. This avoids inventing a parallel --engine-host flag at login time for the 99% case while leaving a clean follow-up if a non-conventional env ever needs it.
  • One resolution helper per concern (resolve_engine_url, resolve_coordinator_url) instead of magic inside each callback. Each typer.Option -h default flips from PROD_*_HOST to None, and the callback body becomes a one-liner.
  • Backward compatible. Pre-existing credentials.yaml files don't have engine_url set; commands fall back to api.arcade.dev exactly as before. Logged-out users see no behavior change.
  • whoami surfaces both URLs, with non-prod URLs highlighted in yellow so a glance confirms which environment is active. Login banner shows them too.

Scope

In scope:

  • Persistence layer (Config schema, save_credentials_from_whoami)
  • Login derives and persists the engine URL
  • Every CLI command with a -h flag resolves through the saved URL
  • whoami surfaces both URLs

Not in scope (handled separately):

  • Profile / environment switching (arcade env use staging) — bigger feature that can build on top of this
  • Explicit --engine-host flag on arcade login for non-conventional hosts — small follow-up if a real env stops following the cloud.X / api.X convention

Test plan

  • make check (ruff + mypy) clean
  • make test — 3605 passed, 1 skipped (evals)
  • 33 new unit tests covering derivation, persistence, resolution, every callback's URL choice, and whoami output
  • End-to-end smoke test: saved a real credentials.yaml with non-prod URLs to a tmp ARCADE_WORK_DIR, confirmed resolve_engine_url / resolve_coordinator_url return the saved URLs, and that explicit flags still override
  • Verified the no-credentials path still returns the production defaults (regression check for logged-out users)
  • Reviewer to dry-run arcade login -h <non-prod-coordinator> then arcade server list / arcade secret list / arcade org list with no -h and confirm each hits the right host

Risk note

Touches the CLI surface every internal user relies on. Blast radius:

  • Logged-out users: every command falls back to the prod default exactly as before. Covered by test_*_no_creds_falls_back_to_prod tests.
  • Logged-in users with pre-existing credentials.yaml: engine_url is None until they re-log in, so commands fall back to prod. Same behavior as today. No migration required.
  • Logged-in users on a non-prod env: after their next arcade login, commands stop needing -h. If derivation fails for some reason, engine_url stays None and they get the same behavior as today.
  • Explicit -h / -p / --tls / --no-tls always wins, so the escape hatch is preserved.

Author checklist

  • I understand every change in the diff
  • make check and make test green locally; CI is expected to pass
  • Pulled the branch fresh and reviewed my own diff top-to-bottom
  • I'd merge it myself if a teammate said LGTM right now

Note

Medium Risk
Touches host/URL selection logic across many CLI commands and changes default targeting behavior after login, so regressions could misroute requests to the wrong environment. Risk is mitigated by centralized resolution helpers plus extensive new unit tests and safe fallbacks to prod when credentials are missing or unreadable.

Overview
After arcade login, the CLI now persists both Coordinator and Engine base URLs (new Config.engine_url) so subsequent commands default to the same environment without repeatedly passing -h/--host.

Adds centralized URL resolution (resolve_engine_url, resolve_coordinator_url) that applies explicit flags > saved URL > prod defaults, including layering --port/--tls/--no-tls on top of the saved host when --host isn’t provided, and falling back safely if credentials.yaml is missing/corrupted.

Updates engine- and coordinator-backed commands (e.g., server, secret, org, project, show, deploy, dashboard) to use the new resolvers and makes --host optional, while login derives and saves the matching engine URL and whoami now prints both URLs (highlighting non-prod). Extensive new tests cover persistence, derivation, resolution precedence, and callbacks using saved defaults.

Reviewed by Cursor Bugbot for commit 0aa63d3. Bugbot is set up for automated code reviews on this repo. Configure here.

Persist the Coordinator and Engine URLs after `arcade login` so every
follow-up CLI command targets the same environment without repeating
the `-h` flag. Resolution order is explicit flags > saved URL >
production default.

- Add `engine_url` field to `Config` (saved alongside `coordinator_url`)
- Add `derive_engine_url_from_coordinator` for the `cloud.X` -> `api.X`
  convention (plus localhost mapping)
- Add `resolve_engine_url` / `resolve_coordinator_url` helpers used by
  every command callback
- `arcade login` derives and persists the Engine URL; banner shows both
- `arcade whoami` prints both URLs (non-prod highlighted)
- `server`, `secret`, `show`, `deploy`, `dashboard`, `org`, `project`
  default their `-h` flag to None and resolve through the saved URL
Comment thread libs/arcade-cli/arcade_cli/utils.py Outdated
Previously, passing only --port, --tls, or --no-tls (without -h) made
the resolver fall back to the production host and drop the host saved
at login. A user logged into a non-prod environment who ran
`arcade server list --no-tls` would silently hit the production engine.

Now: -h is a clean override (saved host ignored); --port / --tls /
--no-tls layer on top of the saved host so the connection stays in
the same environment. The saved scheme and port are preserved unless
explicitly overridden.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit dd97fb4. Configure here.

Comment thread libs/arcade-cli/arcade_cli/utils.py
…olver

URL resolution now runs on every CLI command, so a corrupted
credentials.yaml (malformed YAML, unreadable file) must not crash
unrelated commands. Widen the catch to include yaml.YAMLError and
OSError, log a warning so the cause is discoverable, and fall back to
production defaults.
The `arcade whoami` command goes through main_callback, which uses
the CREDENTIALS_FILE_PATH constant baked at module import time.
Pre-existing constants in arcade_core.constants do not honor
ARCADE_WORK_DIR after import, so the test passed locally only
because the user already had a real ~/.arcade/credentials.yaml.
Patch the imported constant in the fixture to point at the same
file Config writes to.
@codecov

codecov Bot commented May 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.33333% with 11 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
libs/arcade-cli/arcade_cli/main.py 58.33% 5 Missing ⚠️
libs/arcade-cli/arcade_cli/utils.py 89.79% 5 Missing ⚠️
libs/arcade-cli/arcade_cli/deploy.py 0.00% 1 Missing ⚠️
Files with missing lines Coverage Δ
libs/arcade-cli/arcade_cli/authn.py 77.38% <ø> (+12.20%) ⬆️
libs/arcade-cli/arcade_cli/org.py 36.36% <100.00%> (+15.46%) ⬆️
libs/arcade-cli/arcade_cli/project.py 38.46% <100.00%> (+17.24%) ⬆️
libs/arcade-cli/arcade_cli/secret.py 68.85% <100.00%> (+2.18%) ⬆️
libs/arcade-cli/arcade_cli/server.py 33.88% <100.00%> (+1.47%) ⬆️
libs/arcade-cli/arcade_cli/show.py 60.00% <ø> (ø)
libs/arcade-core/arcade_core/config_model.py 77.19% <100.00%> (+3.08%) ⬆️
libs/arcade-cli/arcade_cli/deploy.py 47.01% <0.00%> (ø)
libs/arcade-cli/arcade_cli/main.py 38.51% <58.33%> (+6.06%) ⬆️
libs/arcade-cli/arcade_cli/utils.py 60.77% <89.79%> (+3.71%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@EricGustin EricGustin marked this pull request as draft May 18, 2026 20:00
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has had no activity for 14 days. It will be closed in 14 days if no further activity occurs. If this is still relevant, please leave a comment or remove the stale label.

@github-actions github-actions Bot added stale and removed stale labels Jun 2, 2026
@github-actions

Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has had no activity for 14 days. It will be closed in 14 days if no further activity occurs. If this is still relevant, please leave a comment or remove the stale label.

@github-actions github-actions Bot added the stale label Jun 18, 2026
@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

This pull request has been closed due to inactivity. Feel free to reopen it if it is still relevant.

@github-actions github-actions Bot closed this Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant