Repository navigation
perf(list): resolve the GitLab project ID once per command - #4216
Conversation
`gitlab_project_id` shells out to `glab repo view`, a GitLab API call, and `detect_gitlab` runs once per branch — so `wt list --full` over N worktrees spent N round trips resolving one repo-level constant. Memoize it per worktree root for the process, keyed by path like the process-wide caches in `git::repository`, so in-process test runs can't read another repo's answer. The doc comment also pointed at `get_origin_owner`, which no longer exists; the GitHub side resolves its owner through `branch_owner_repo` from local git config.
worktrunk-bot
left a comment
There was a problem hiding this comment.
Self-review; two notes, neither blocking.
The None branch of the memo is the one part of GitLab CI detection that never retries. CachedCiStatus expires every 30–60 s, so a long-lived picker re-enters detect_gitlab — including on an explicit alt-r, which re-runs the collect pipeline in-process (PickerCollector::invoke, the if cmd.trim() == "refresh" branch) — and from now on gets the process-cached None back. The blast radius is narrow: with no project ID a branch with exactly one MR still resolves through the unambiguous-single-MR fallback, so only a branch carrying several same-named MRs goes dark. Leaving it as-is is defensible, but it's the maintainer's call: caching only Some would restore the retry at the cost of one extra failing glab repo view per row in a repo glab can't answer for.
Related, and the reason it's worth stating: the docstring's justification — "retrying it once per row is the cost this exists to remove" — holds for a successful lookup but overstates the failing one. When the project ID can't be resolved, detect_gitlab still issues its own per-row glab mr list, so caching the failure halves that repo's calls rather than removing the duplication.
The keying rationale describes a test shape this suite doesn't have. Nothing reaches gitlab_project_id in-process: integration tests spawn wt as a subprocess (the mocks are that same binary under another argv[0]), and this module's in-process tests cover only the parsers. Path-keying is still right, for the reason the # Caching section in src/git/repository/mod.rs gives for its own statics — "so two Repository instances pointed at the same path see the same answer" — which doesn't claim coverage that isn't there. Suggestion inline; I'll push it.
The keying rationale cited tests running many commands in one process, but nothing reaches gitlab_project_id in-process: integration tests spawn wt as a subprocess and this module's in-process tests cover only the parsers. Give the reason src/git/repository/mod.rs gives for its own path-keyed statics, and say what caching a failed lookup costs.
wt list --fullon a GitLab remote spends oneglab repo viewAPI call per row resolving a value that is the same for every row.gitlab_project_idis called fromdetect_gitlab, which runs once per branch, and the project ID it fetches is a repo-level constant used only to filter MRs by source project. This memoizes it for the process.wt listrenders progressively but cannot finish until every row's task returns, so each of those round trips extends the command the user is waiting on — the case CLAUDE.md's Network Access section calls out for run-to-completion commands. It also spends N times the GitLab API quota for one answer.The cache is a
LazyLock<DashMap<PathBuf, Option<u64>>>keyed by the worktree root, matching the path-keyed process-wide caches ingit::repositoryrather than a bare static — tests run many commands in one process, and a bare static would let one repo's answer leak into another's. TheentryAPI holds the shard lock across the fetch, so concurrent rows sharing the key wait on the first call instead of each spawning their own; a failed lookup caches asNone, since retrying it per row is exactly the cost being removed.The regression test asserts the spawn count through
mock_callsrather than the rendering, because the table looks identical either way. On this branch's parent it fails with 5glab repo viewcalls against an expected 1.A drive-by in the same doc comment: it described
gitlab_project_idas "the GitLab equivalent ofget_origin_ownerfor GitHub", andget_origin_ownerno longer exists — the GitHub side now resolves its owner throughbranch_owner_repo, from local git config with no network call at all.Verified locally:
cargo test --test integration ci_status(63 passed),cargo test --bins ci_status(42 passed),cargo clippy --all-targets --all-features,cargo fmt --check.