Skip to content

feat(advisor): resolve --repo by name via the connected-repos API#806

Merged
benw5483 merged 4 commits into
mainfrom
feat/advisor-repo-by-name
Jul 14, 2026
Merged

feat(advisor): resolve --repo by name via the connected-repos API#806
benw5483 merged 4 commits into
mainfrom
feat/advisor-repo-by-name

Conversation

@benw5483

Copy link
Copy Markdown
Contributor

What

actual advisor --repo <value> now accepts a connected repository's name, not only its UUID. A UUID still works exactly as before. A name is resolved to a repository id via the connected-repos API, matching on the repo name (or owner/name to disambiguate a name shared by two owners). An unrecognized or ambiguous name fails with a clear message listing the repositories you can pick from.

Quality

  • 100% per-file line coverage on every changed file; clippy -D warnings clean; cargo fmt clean; full test suite green.
  • Five files changed: the API client (a new list_connected_repos method plus response types), a new RepoNotFound error, the advisor command wiring, and the --repo help text.

Draft for review.

`actual advisor --repo <value>` now accepts a connected repository's name
in addition to a UUID. A value that parses as a UUID is used directly, as
before. Any other value is resolved to a repo id by listing the
organization's connected repositories (GET /v1/connected-repos) and
matching on name, or on `owner/name` to disambiguate a name shared across
owners. An unrecognized or ambiguous name fails with a clear message that
lists the repositories to choose from.

- api: add `ActualApiClient::list_connected_repos` plus the
  `ConnectedRepository` / `GetConnectedReposResponse` types. This endpoint
  returns a flat `{error, message}` error body, so it gets its own error
  mapper, distinct from the advisor routes' nested `{error:{code,message}}`.
- error: add `RepoNotFound`, carrying the listed-repositories message and
  an actionable fix hint.
- advisor: resolve `--repo` before building the query. A 403 during the
  lookup gets the same cross-org guidance as the query itself.

Per-file line coverage stays at 100%.

Generated by the operator's software factory.
City: factory-main · Agent: local-core.builder-1
On behalf of: @benw5483
Co-Authored-By: <operator-factory-bot> <factory-bot@<operator-domain>.invalid>
@benw5483 benw5483 marked this pull request as ready for review July 13, 2026 18:22

@backlineint backlineint 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.

Nice, tightly-scoped change with unusually thorough error-path coverage. Three suggestions, none blocking:

  1. Case-sensitive name matching (resolve_repo_name, src/cli/commands/advisor.rs). GitHub owner/repo names are case-insensitive in practice, but the match uses ==. A user typing --repo Actual-CLI for a repo named actual-cli gets a confusing "no match" error that then lists the very repo they typed. Suggested fix: compare with eq_ignore_ascii_case (still surfacing ambiguity if two repos differ only by case).

  2. Required-but-unused url field (ConnectedRepository, src/api/types.rs). url is never read (only name, external_owner, and repo_unique_id are used), yet it's a required field — a server response that omits or renames it fails the entire deserialization and breaks name resolution. Either drop the field or give it #[serde(default)].

  3. Static hint reads wrong for an empty org (RepoNotFound hint, src/error.rs). The hint always says "Pass one of the connected repository names to --repo", which is contradictory when the message just said the organization has no connected repositories. Minor; could vary the hint or reword it to cover both cases.

backlineint
backlineint previously approved these changes Jul 14, 2026
benw5483 and others added 3 commits July 14, 2026 14:11
GitHub owner/repo names are case-insensitive in practice, so match
connected repositories with eq_ignore_ascii_case instead of ==. A value
like --repo ACTUAL-CLI now resolves to actual-cli; a bare name shared
across owners still surfaces as ambiguous.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
url is never read by name resolution, yet it was a required field, so a
server response that omits or renames it failed the whole deserialization
and broke --repo resolution. Mark it #[serde(default)], matching the
tolerant sibling fields in the same module.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The RepoNotFound hint always said "Pass one of the connected repository
names", which contradicts the message when the organization has none
connected. Reword to "Pass a connected repository name to --repo, or omit
--repo to query the whole organization" so it reads correctly in both the
wrong-name and empty-org cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@benw5483

Copy link
Copy Markdown
Contributor Author

Thanks for the review @backlineint — addressed all three suggestions:

  1. Case-sensitive name matching: resolve_repo_name now compares with eq_ignore_ascii_case, so --repo ACTUAL-CLI resolves to actual-cli (a bare name shared across owners still surfaces as ambiguous). — 523c737
  2. Required-but-unused url: marked #[serde(default)] so a response that omits or renames it no longer fails deserialization and breaks name resolution. — bb0bf5e
  3. Empty-org hint: reworded to "Pass a connected repository name to --repo, or omit --repo to query the whole organization" so it reads correctly whether or not the org has connected repositories. — 05cc4bf

Each has a test; CI is green. Re-requesting your review.

@benw5483 benw5483 requested a review from backlineint July 14, 2026 18:30
@benw5483 benw5483 added this pull request to the merge queue Jul 14, 2026
Merged via the queue into main with commit ff87c80 Jul 14, 2026
10 checks passed
@benw5483 benw5483 deleted the feat/advisor-repo-by-name branch July 14, 2026 20:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants