fix(glrepo): recognize an authenticated host with a port in --repo

Description

glab --repo HOST/OWNER/REPO (and GITLAB_REPO) ignores an authenticated host that has a port but no dot, such as localhost:3000 for a local development instance. After glab auth login --hostname localhost:3000, glab issue list -R localhost:3000/OWNER/REPO asks gitlab.com for a project named localhost:3000/OWNER/REPO instead of asking localhost:3000 for OWNER/REPO.

The cause is in FromFullName. Dots are allowed in group paths, so it compares the first segment with the authenticated hosts only when that segment contains a dot. A host with a port and no dot never reaches that comparison and falls through to the GROUP/NAMESPACE/REPO case on the default host.

This MR runs the same authenticated host check when the first segment contains a dot or a colon. A colon cannot appear in a GitLab group or project path (PATH_REGEX_STR allows letters, digits, _, - and .), so no valid group name changes meaning. The host still has to be in the authenticated list: a segment with a colon that does not match an authenticated host is read exactly as before.

Behavior change: a --repo or GITLAB_REPO value whose first segment contains a colon and matches an authenticated host now targets that host. Before, it was sent to the default host as a project path that GitLab cannot have.

A dotless host without a port (for example an intranet host named gitlab) is still not recognized, because its name can also be a valid group. I kept that out of this MR: checking every first segment against the authenticated hosts would cover it, but it would change how a group whose name matches an authenticated host is read, which seems a decision for the maintainers. !4188, open, proposes that rule for glab repo clone paths, where a configured host takes precedence over a group of the same name; it changes other files.

Closes #8679 (closed)

!3757 (merged) is related: it keyed the subfolder config lookup on the host with its port, in the same file.

How has this been tested?

I added two cases to the existing TestFromFullName table, with localhost:3000 added to its test config: an authenticated host with a port and no dot (localhost:3000/OWNER/REPO must resolve to host localhost:3000, project OWNER/REPO), and an unauthenticated host with a port (localhost:4000/OWNER/REPO must keep resolving to gitlab.com, project localhost:4000/OWNER/REPO, as it does today).

  • Without the fix, the first case fails with expected host "localhost:3000", got "gitlab.com"; the second passes.
  • With the fix, make test-race (the tests:unit job) passes: 6720 tests, 18 skipped, none failed.
  • golangci-lint run and golangci-lint fmt --diff (v2.14.0, the version of the lint job) report nothing for the whole repository. scripts/comment-overlap reports 0 findings, make generate and make gen-docs change no file, make check-embed and make check-args pass, and scripts/commit-lint/lint.js accepts the title and the commit.
  • Reverting the condition to the dot-only check, checking only the colon, or accepting any segment with a colon without the authenticated list each makes a case of TestFromFullName fail.

End to end, I built glab from main and from this branch and ran glab issue list -R localhost:3123/OWNER/REPO with a configuration holding one authenticated host, localhost:3123, against a stub of the issues route on that port. HTTPS_PROXY pointed at a second stub that logs every CONNECT and refuses it, so nothing reached gitlab.com:

  • main: glab asked https://gitlab.com/api/v4/projects/localhost:3123%2FOWNER%2FREPO/issues and failed with the proxy stub's Forbidden; the proxy stub logged CONNECT gitlab.com:443, and the stub on localhost:3123 saw nothing.
  • This branch: the stub on localhost:3123 received GET /api/v4/projects/OWNER%2FREPO/issues, and glab printed No open issues match your search in OWNER/REPO.
  • GITLAB_REPO=localhost:3123/OWNER/REPO glab issue list gave the same two results.

This comes from maintaining gitlab-mcp-server; its upstream-bugs.md records everything done on its dependencies and sibling projects.

Test output before and after the fix

Before (main at a6fd50ce, with the new test cases):

    repo_test.go:454: expected host "localhost:3000", got "gitlab.com"
    repo_test.go:457: expected owner "OWNER", got "localhost:3000/OWNER"
    repo_test.go:463: expected group "", got "localhost:3000"
    repo_test.go:466: expected fullname "OWNER/REPO", got "localhost:3000/OWNER/REPO"
    --- FAIL: TestFromFullName/authenticated_hostname_with_port_and_no_dot (0.00s)
FAIL
FAIL	gitlab.com/gitlab-org/cli/internal/glrepo	0.016s
FAIL

After:

    --- PASS: TestFromFullName/authenticated_hostname_with_port_and_no_dot (0.00s)
    --- PASS: TestFromFullName/unauthenticated_hostname_with_port (0.00s)
ok  	gitlab.com/gitlab-org/cli/internal/glrepo	0.021s
ok  	gitlab.com/gitlab-org/cli/internal/glrepo	0.572s
ok  	gitlab.com/gitlab-org/cli/internal/cmdutils	2.606s

make test-race:

DONE 6720 tests, 18 skipped in 269.359s

What the two stubs logged in the end-to-end run, main first:

proxy CONNECT gitlab.com:443 (refused)

This branch:

instance GET /api/v4/projects/OWNER%2FREPO/issues?in=title%2Cdescription&order_by=created_at&page=1&per_page=30&sort=desc&state=opened Host=localhost:3123

Environment: go1.27.3 linux/amd64, golangci-lint 2.14.0, Node.js 25 for the commit lint.

Screenshots (if appropriate):

Not applicable: no change to the output.

Merge request reports

Loading
Loading