NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Git for Laravel

Data model & raw payloads

Every resource object is provider-agnostic: it carries the ProviderName it came from, a normalized ResourceState enum instead of a raw open/opened/OPEN string, and a raw() accessor returning the exact decoded provider payload for any field the object doesn’t model. raw is never serialized into toArray() or toJson():

use RoundlyConsulting\Git\Enums\ResourceState;

$pr = Git::github()->repo('acme/api')->pullRequest(1)->get();

$pr->state;                          // ResourceState::Open — identical across GitHub/GitLab/Bitbucket
$pr->state === ResourceState::Merged;
$pr->draft;                          // bool
$pr->provider;                       // ProviderName::Github
$pr->raw()['mergeable'];             // any unmodelled provider field, still reachable

$pr->toArray();                      // canonical shape — raw is never serialized
$pr->toJson();

State mapping

Pull requests and issues normalize their state the same way on every forge; unmatched values resolve to Unknown rather than throwing, and the original string stays reachable through raw():

ResourceStateGitHubGitLabBitbucket
OpenopenopenedOPEN
Closedclosedclosed, lockedDECLINED, SUPERSEDED
MergedmergedmergedMERGED
Unknownanything elseanything elseanything else

Draft status is its own boolean — PullRequest::$draft, read from the forge’s draft field on all three forges, REST and webhooks alike — rather than a state.

Head commit, visibility and links

PullRequest::$headSha and $headRepository (owner/name of the head branch’s repository — a fork’s, for a pull request from a fork) and Repository::$private, $language and $webUrl are nullable and filled from REST and webhook payloads alike. They come after raw in the constructor, so positional new PullRequest(…) and new Repository(…) calls keep working, and each one is in toArray() and JSON:

FieldGitHubGitLabBitbucket
PullRequest::$headShahead.shasha (REST), last_commit.id (hook)source.commit.hash — a 12-character short hash
PullRequest::$headRepositoryhead.repo.full_name (null for a deleted fork)null — only a project id is carriedsource.repository.full_name
Repository::$privateprivatevisibility other than public — internal counts as private; a hook’s visibility_level is read the same wayis_private
Repository::$languagelanguagenull — not in the project payloadlanguage (empty → null)
Repository::$webUrlhtml_urlweb_urllinks.html.href

Enums

Every enum — Feature, ProviderName, ResourceState, MergeMethod, ReviewEvent, DiffSide, CommentTarget, ComparisonStatus, ActivityType, WorkflowStatus and WorkflowConclusion — shares the enums-for-laravel helpers: values(), labels(), options(), validationRule() and case lookups:

use RoundlyConsulting\Git\Enums\ProviderName;

ProviderName::values();           // Collection: github, gitlab, bitbucket
ProviderName::options();          // {value, label, name} options for a select
ProviderName::validationRule();   // "in:github,gitlab,bitbucket"
ProviderName::Github->label();    // "GitHub"

$request->validate(['provider' => ['required', ProviderName::validationRule()]]);

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.