graham-campbell/gitlab
A Laravel integration for the GitLab API v4 client, providing a service provider, facade, and simple configuration so you can query projects, issues, merge requests, and other GitLab resources from your PHP applications.
Architecture fit. The package is a thin Laravel service-provider bridge over the official gitlabphp/api-client (Guzzle-based, GitLab API v4). It contributes container bindings, a publishable config file, a facade, a manager with named connections, and an extend() hook — nothing more. That is the correct shape for a Laravel codebase that already uses the container and config idiom, and it is architecturally neutral: it does not impose queues, caching, retries, or domain modeling. As TPM, the important read is that this is plumbing, not a product. The package removes days of HTTP-client scaffolding; every workflow rule, backoff policy, pagination strategy, and webhook handler remains ours to design, own, and staff.
Integration feasibility. Low friction on the happy path: composer require, auto-discovery, vendor:publish, two env vars (GITLAB_TOKEN, GITLAB_URL). The realistic engineering effort is not installation but the boundary work — an application-owned adapter interface expressing domain verbs (openMergeRequests, failingPipelines, fileIssue) rather than GitLab resources, so the package namespace appears in exactly one class. Endpoint coverage is inherited, not negotiated: we cannot ship a feature the upstream client hasn't implemented, so any roadmap item touching recently released GitLab endpoints needs a spike against the client source before it enters a sprint. The highest-leverage capability for our roadmap is multi-connection support, which makes "self-managed GitLab for enterprise customers" a configuration exercise rather than a bespoke integration project.
Technical risk. Ranked by roadmap impact:
composer update pass, not mid-release.Key questions.
Stack fit. Laravel or Lumen, PHP and Laravel versions matching the package's current release line, with the container and config already in use. If we are not on Laravel, this package adds nothing and we should use gitlabphp/api-client directly. Two configuration facts drive everything downstream: credentials and base URL are config-driven (enabling multi-tenant and self-hosted), and php artisan config:cache freezes env() calls at cache time — the number-one "works locally, 401 in prod" cause.
Migration path. There is no data migration; this is an additive integration. The meaningful "migration" is organizational: from ad-hoc Guzzle calls or scattered API code to a single adapter with a domain interface. Sequence it as (1) adapter interface + one read-only method, (2) facade wired only inside the adapter, (3) feature surfaces consume the adapter, never the facade. If we already have hand-rolled GitLab calls, port them one verb at a time so the diff stays reviewable.
Compatibility. Three constraints to verify before committing a sprint:
composer update pass.GitLab::connection()->getHttpClient() or GitLab::extend() gets us a raw request or custom driver without abandoning the config plumbing. GraphQL is out of scope entirely.Sequencing. Read-only list → cached read → queued bulk sync → single write action → batch writes. Concretely: ship a pipeline-status widget and an open-MR list against a scratch project first (failure mode: a blank widget), then cache slow-moving reads (project metadata, members, labels) with short TTLs keyed by connection + project, then move bulk syncs into jobs with RateLimited / WithoutOverlapping middleware, and only then introduce mutations — idempotent where possible (search before create), dry-run capable, and recording returned iid/id for audit. Never let a bulk loop iterate over production projects in a request cycle.
Maintenance. Small surface, small maintenance load — but single-maintainer upstream. Pin the version, let Dependabot surface bumps, and treat Laravel major upgrades as scheduled work rather than reactive firefighting. The adapter boundary is the maintenance strategy; without it, abandonment is a multi-week problem instead of a multi-day one.
Support. No commercial support contract and no vendor SLA. Internal support means our own runbook: how to rotate a token, how to force a config re-cache, how to read a 429, and who to page when a dashboard goes dark. Logging discipline matters here — log the connection name and the rate-limit / request-ID headers on failure, never the config array, never the token. When a production dashboard dies, GitLab-side admins will ask for the request ID; without it we are blind.
Scaling. Two axes:
GitLab::connection($tenant->gitlab_connection)), which scales the addressable customer set cheaply and is the single highest-leverage decision this package enables.Retry-After, push bulk work to the queue, and set per_page explicitly on every list call. GitLab.com's limits are materially stricter than self-managed instances, so capacity planning must name which target we are sizing for.Failure modes. Enumerated so on-call has a lookup table:
->all() returns 20 rows when 300 were expected. The classic bug; use explicit per_page and ResultPager when "all" means all.GitLab\Exception\RuntimeException, Guzzle RequestException / ConnectException escaping into controllers. Catch and translate at the adapter boundary..env or cached bootstrap files. Scope minimally: read_api for dashboards, api only where we genuinely write.Ramp-up. A new engineer needs roughly fifteen minutes to understand the whole bridge — config/gitlab.php, src/GitLabManager.php, the facade — and then must be pointed at the upstream client docs, which is where endpoint coverage, method names, and pagination semantics actually live. Budget the real ramp-up time for the adapter interface and our own conventions (domain verbs, idempotency, dry-run, error translation), because that is the part we own and the part that determines whether this dependency stays cheap to leave.
How can I help you explore Laravel packages today?