fix(glrepo): key subfolder config lookup on host with port
Description
glab mr create 404s on a self-managed instance served from a subdirectory on a non-standard port, while mr list and repo view work against the very same endpoint:
GET /gitlab/api/v4/projects/gitlab%2Fmygroup%2Fmyproject → 404
^^^^^^^^^ the subfolder leaked into the project pathRoot cause
glrepo.FromURL read the subfolder and api_host settings with cfg.Get(u.Hostname(), ...), which strips the port. Everything else keys on the port-bearing host:
auth loginwrites host entries keyed onu.Host— seesplitHostnameAndSubfolder, which comments "Use u.Host to preserve port information".--hostname localhost:9999/hostis an explicitly tested input.FromURLitself returnsRepoHost()built fromu.Host.api.NewClientFromConfigresolvesapi_host,subfolder,api_protocolandtokenunder that sameRepoHost.
So on a ported instance both lookups missed, the subfolder was never stripped, and the prefix stayed in the project path. There was no configuration that worked: keying the entry with the port authenticates correctly but resolves the wrong path; keying it without resolves the right path but finds no token and falls back to https. Adding the subfolder key did not help either — it was read with the same broken key.
This surfaced only in mr create because it resolves the head repo from git remotes through TranslateRemotes → FromURL. Commands driven by -R go through FromFullName, which never consults the subfolder settings, so they were unaffected and the failure looked command-specific.
Fix
Key both lookups on u.Host, so they address the same host entry the API client uses. This is the config-lookup half of !2481 (closed), which fixed all three call sites but was closed unmerged; the half that did land (7883dc24) corrected only the NewWithHost / NewWithGroup return values, which is what left the two sides disagreeing.
Test coverage
This reached a release with every command suite green, because command tests stub Factory.Remotes with repos that are already resolved and so never run FromURL. Coverage is added at the two layers that do run it:
FromURL— default and custom ports × root / single / nested subfolders × thesubfolderkey and the legacyapi_hostspelling, plus subgroups and a group whose name repeats the subfolder. Negative cases pin that an entry keyed without the port does not answer for a ported remote, and that an unrelated host's settings do not leak.remoteResolver— the single path from raw git remotes to resolved repos that every command inherits through the factory.
Both layers assert RepoHost alongside the project path, since that is the key the API client authenticates under. 13 subtests fail without the one-line change.
Out of scope
git.ParseURL deliberately drops the port from ssh://host:port/ URLs, asserted by its own TestParseURL "ssh with port" case. That is defensible — an SSH port is not the port the API is served on — but it means an SSH remote always resolves against the portless entry. Left alone here rather than flipping a tested contract inside a bug fix; the new SSH cases document the current behaviour.
Related Issues
Closes #8506 (closed) Related to #8022 (closed), #7920 (closed), #8146 (closed)
How has this been tested?
lefthook run pre-push (build, lint, full unit suite) passes. Each new case was verified to fail with the lookup reverted to u.Hostname().
Types of changes
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing functionality to change)
- Documentation
- Chore (Related to CI or Packaging to platforms)
- Test gap