jordanpartridge/github-client is a Laravel package for the GitHub REST API. It is built on Saloon and returns typed PHP objects instead of raw arrays. It requires PHP 8.2 or newer and Laravel 11, 12, or 13. CI runs the suite on PHP 8.2, 8.3, and 8.4.
Facade (Github::) -> Github client -> Resource (repos, pullRequests, issues, ...)
-> Request class (one per endpoint)
-> GithubConnector (base URL, headers, auth, errors)
<- createDtoFromResponse() -> typed Data object
| Layer | Responsibility | Example |
|---|---|---|
| Connector | Base URL, API version header, authentication, mapping HTTP errors to exceptions | src/Connectors/GithubConnector.php |
| Requests | One class per endpoint: method, path, query, and response mapping | src/Requests/Pulls/Index.php |
| Resources | Developer-facing methods grouped by API area | src/Resources/RepoResource.php |
| Data | Typed objects built from responses | src/Data/Repos/RepoData.php |
| Value objects and enums | Validated inputs and closed sets of options | src/ValueObjects/Repo.php, src/Enums/MergeMethod.php |
GithubConnector sets the base URL, the X-GitHub-Api-Version header, and authentication. Its getRequestException() maps status codes to specific exceptions with a match: 401 to AuthenticationException, 403 to a rate-limit or permission error, 404 to ResourceNotFoundException, 422 to ValidationException with field-level details, 429 to RateLimitException, and 5xx to NetworkException. Calling code catches a meaningful type instead of checking status codes.
Each endpoint is a small Saloon Request that knows its HTTP method, path, query, and how to turn the response into objects (createDtoFromResponse()). Resources such as RepoResource and PullRequestResource extend a readonly BaseResource and give callers methods like Github::pullRequests()->merge(...). Adding an endpoint means adding one request class and one resource method.
Responses map onto classes in src/Data with typed properties and Carbon dates, so IDEs and static analysis know what comes back. Inputs are validated at the edge: Repo::fromFullName('owner/repo') rejects malformed names before any HTTP call, and backed enums (MergeMethod, Visibility, Direction, Pulls\State) replace free-form strings for options.
AuthenticationStrategy is a small interface (getAuthorizationHeader, validate, needsRefresh, refresh). The connector accepts either a token string or a strategy. GitHubAppAuthentication signs an RS256 JWT with the App private key, exchanges it for an installation token, and refreshes that token before it expires. With no explicit credentials, TokenResolver tries config('github-client.token') (normally GITHUB_TOKEN), then config('github-client.gh_token') (normally GH_TOKEN), then gh auth token, and falls back to unauthenticated access for public data.
$github = Github::forInstallation($installationId);
$github->pullRequests()->all('owner', 'repo');GithubClientServiceProvider uses spatie/laravel-package-tools for the config file and an Artisan command, and registers the connector as a singleton in the container. The package is auto-discovered, and the Github facade carries @method annotations so IDEs autocomplete every resource. The same client can be injected by type for code that avoids facades.
- Pest tests use Saloon's
MockClient; unmocked Saloon network requests are blocked, and tests need no GitHub credentials. - The
Unitsuite runs without Testbench; thePackagesuite boots Laravel. See contributor commands for setup, filtering, and profiling. Process::fake()intests/Pest.phpkeeps the GitHub CLI out of the test run.- Architecture tests in
tests/ArchTest.phpenforce that resources extendBaseResource, requests extend SaloonRequest, and no debug calls ship. - GitHub Actions tests Laravel 12 on PHP 8.2/8.3/8.4 and Laravel 13 on PHP 8.3/8.4 (
run-tests.yml). Laravel 11 remains accepted by Composer for legacy consumers but is outside CI after its March 12, 2026 security EOL; security-advisory blocking stays enabled. - PHPStan runs once on PHP 8.2 with Laravel 12 and Larastan 3, alongside Composer validation and dependency auditing. Pint is a read-only check, not an auto-commit bot. All three workflows run on every PR and pushes to
master, with read-only repository permissions and cancellation of superseded runs. - Dependabot keeps Composer and Actions dependencies current. Minor and patch updates are set to auto-merge.
use JordanPartridge\GithubClient\Facades\Github;
use JordanPartridge\GithubClient\Enums\MergeMethod;
$repo = Github::getRepo('laravel/framework'); // RepoData
$prs = Github::pullRequests()->all('laravel', 'framework');
Github::pullRequests()->merge('owner', 'repo', 42, mergeMethod: MergeMethod::Squash);| Topic | File |
|---|---|
| Entry point | src/Github.php |
| HTTP, auth, error mapping | src/Connectors/GithubConnector.php |
| Endpoint example | src/Requests/Pulls/Index.php |
| Resource example | src/Resources/PullRequestResource.php |
| Typed response | src/Data/Repos/RepoData.php |
| Input validation | src/ValueObjects/Repo.php |
| GitHub App auth | src/Auth/GitHubAppAuthentication.php |
| Container wiring | src/GithubClientServiceProvider.php |
| Test conventions | tests/Pest.php, tests/ArchTest.php |
| CI matrix | .github/workflows/run-tests.yml |