Skip to content

fix(gitlab): drive self-hosted GitLab out-of-the-box with glab v1.5x#326

Closed
karotkriss wants to merge 2 commits into
kunchenguid:mainfrom
karotkriss:gitlab-selfhosted-glab-v15x
Closed

fix(gitlab): drive self-hosted GitLab out-of-the-box with glab v1.5x#326
karotkriss wants to merge 2 commits into
kunchenguid:mainfrom
karotkriss:gitlab-selfhosted-glab-v15x

Conversation

@karotkriss

Copy link
Copy Markdown
Contributor

Summary

Makes no-mistakes drive a self-hosted GitLab instance out of the box for the direct branch -> MR flow, working with the current glab v1.5x CLI. No manual configuration beyond a normal glab auth login.

Problem

On a machine with glab v1.5x and more than one configured glab host, the pipeline pushed the branch but then silently skipped MR creation and never read CI - the run still reported success, so it looked like it shipped. Three version-driven incompatibilities caused it:

  • Unscoped auth check. glab auth status (no host) checks every configured instance and exits non-zero if any has a stale token, so a healthy repo is judged unauthenticated and the MR step skips.
  • Removed flag. glab mr list no longer accepts --state opened (open is the default in v1.5x); the unknown flag fails the whole command.
  • Detached-HEAD worktree. The daemon checks out a commit, not a branch. glab ci get refuses to run there, so CI checks can never be read.

What this changes

  1. Host-scoped auth - pass --hostname <host> to glab auth status so an unrelated instance's stale token can't poison this repo's check. Unknown host falls back to the unscoped check (fail-safe).
  2. Drop removed --state - rely on glab mr list's open-by-default behavior instead of the flag that v1.5x removed.
  3. Read CI jobs via glab api (REST) - when the project path is known, list jobs through glab api projects/<group%2Fproject>/pipelines/<id>/jobs. This is branch-independent (works in the detached-HEAD worktree), paginated, and maps finished_at into Check.CompletedAt for CI re-run detection. The legacy glab ci get path stays as a fallback when no project path is known.

Plus:

  • Self-hosted detection - when a remote's hostname has no gitlab marker (e.g. git.example.com), consult glab's configured hosts (config.yml, honoring GLAB_CONFIG_DIR / XDG_CONFIG_HOME) and treat it as GitLab if the host matches a configured host or its api_host. Reads only user config, hardcodes nothing, and fails closed to unsupported.
  • Project-path parser next to the Host - the new gitlab.ProjectPath lives in the gitlab backend package, mirroring github.RepoSlug.
  • Positional constructor - gitlab.New(cmd, cliAvailable, host, projectPath), matching the GitHub backend's shape.

Compatibility

  • Constructor is positional: New(cmd, cliAvailable, host, projectPath). Passing "", "" reproduces the legacy unscoped behavior.
  • Unknown host -> unscoped auth check (fail-safe, unchanged behavior).
  • A corrupt later page of paginated glab api output surfaces as an error rather than a silent partial that could hide a failed job.
  • Fork MR routing for GitLab remains out of scope (unchanged).

Testing

  • go test ./..., go vet ./..., and gofmt are clean.
  • Verified live against a self-hosted GitLab with glab v1.53.0 and a multi-host glab config (one host carrying an unrelated stale token): the full push -> MR -> CI flow works end to end - host-scoped auth survives the stale token, the MR is created, and CI jobs are read via the paginated glab api path in the detached-HEAD worktree (MR mergeable, pipeline green).

Make the GitLab backend work against self-hosted instances and the current
glab CLI without manual configuration, for the direct branch -> MR flow.

Self-hosted detection:
- DetectProvider falls back to glab's configured hosts (config.yml, honoring
  GLAB_CONFIG_DIR / XDG_CONFIG_HOME) when a remote's hostname carries no
  "gitlab" marker, matching on the host key or its api_host. It reads only what
  the user configured, hardcodes no host, and fails closed to ProviderUnknown
  on any read/parse error.
- Add scm.ExtractHost to recover the host (sans port, lowercased) from
  scp-style, URL, and ssh:// remotes, including IPv6 literals and '@'-in-path.

glab v1.5x backend fixes:
- Scope `glab auth status` with --hostname <host>. Unscoped, it checks every
  configured instance and exits non-zero if any has a stale token, falsely
  reporting an authenticated repo as unauthenticated. Falls back to the
  unscoped check when the host is unknown (fail-safe).
- Drop the removed `--state opened` flag from `glab mr list`; open is the
  default in v1.5x and passing the unknown flag fails the whole command.
- Read pipeline jobs via the branch-independent REST endpoint
  (`glab api projects/<group%2Fproject>/pipelines/<id>/jobs`) so they work in
  the daemon's detached-HEAD worktree, where `glab ci get` refuses to run.
  --paginate walks every page; the decoder handles the resulting concatenated
  JSON documents and a corrupt later page surfaces as an error rather than a
  silent partial that could hide a failed job. Maps finished_at into
  Check.CompletedAt for CI re-run detection. The legacy `glab ci get` path
  remains as the fallback when no project path is known.

Structure, mirroring the GitHub backend:
- The GitLab project-path parser lives in the gitlab package as exported
  gitlab.ProjectPath, next to the Host that consumes it, mirroring
  github.RepoSlug.
- The Host is scoped via positional constructor params
  New(cmd, cliAvailable, host, projectPath); passing "", "" reproduces the
  legacy unscoped behavior.

Escapes each project-path segment with url.PathEscape (rejoined with %2F).
… glab v1.5x

Document that self-hosted GitLab is detected out of the box even when the
hostname carries no "gitlab" marker, by consulting glab's configured hosts
(with the GLAB_CONFIG_DIR / XDG_CONFIG_HOME precedence and fail-closed
behavior), and note that the backend is pinned against glab v1.5x.
@karotkriss

Copy link
Copy Markdown
Contributor Author

@kunchenguid I had some problem using no-mistakes with my self-hosted GitLab repos so I thought I'd take the initiative and fixed it in this PR rather than just creating an issue.

This is one of the best tools I've ever integrated into my SDLC at work, I thank you for open sourcing this.

@kunchenguid

Copy link
Copy Markdown
Owner

Thanks for the contribution, @karotkriss! One process note on this repo: PRs need to be raised through no-mistakes (git push no-mistakes), which runs the review/test/lint/CI pipeline and stamps the required signature into the PR body. This PR is currently failing the "PR must be raised via no-mistakes" check because it wasn't raised that way.

If working from a fork was the blocker, that's fixed as of v1.30.0 (#306). Per CONTRIBUTING.md: point origin at this parent repo, run no-mistakes init --fork-url <your-fork-url>, then git push no-mistakes.

I won't be merging PRs that bypass the gate going forward, but I'd genuinely love to land your work once it's re-raised. Thanks for understanding! 🙏

@karotkriss

Copy link
Copy Markdown
Contributor Author

Thanks for the contribution, @karotkriss! One process note on this repo: PRs need to be raised through no-mistakes (git push no-mistakes), which runs the review/test/lint/CI pipeline and stamps the required signature into the PR body. This PR is currently failing the "PR must be raised via no-mistakes" check because it wasn't raised that way.

If working from a fork was the blocker, that's fixed as of v1.30.0 (#306). Per CONTRIBUTING.md: point origin at this parent repo, run no-mistakes init --fork-url <your-fork-url>, then git push no-mistakes.

I won't be merging PRs that bypass the gate going forward, but I'd genuinely love to land your work once it's re-raised. Thanks for understanding! 🙏

Thank you for responding to my PR so quick, I will close this and reraise the pr to comply with the contribution guideline.

@karotkriss karotkriss closed this Jun 26, 2026
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