Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 24 additions & 170 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,186 +1,40 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Notes for working in this repository.

## Project Overview
## What this package is

A Laravel package providing a strongly-typed GitHub API client built on Saloon. This package integrates with Laravel's service container and configuration system while providing resource-based access to GitHub's API endpoints.
A Laravel package that calls the GitHub REST API with Saloon. Resources live in `src/Resources` and build request classes in `src/Requests`. Responses are mapped by `createDtoFromResponse()` onto plain PHP objects in `src/Data`. Those objects are not Spatie Laravel Data objects.

## Key Commands
The facade `JordanPartridge\GithubClient\Facades\Github` resolves `JordanPartridge\GithubClient\Github`. Inject that class. There is no `GithubConnectorInterface`.

### Testing
```bash
# Run all tests
vendor/bin/pest

# Run specific test file
vendor/bin/pest tests/Feature/ReposTest.php
The connector is `JordanPartridge\GithubClient\Connectors\GithubConnector`. Its base URL is `https://api.github.com`.

# Run with coverage
vendor/bin/pest --coverage
## Commands

# Run tests matching pattern
vendor/bin/pest --filter="it can get a repository"
```

### Code Quality
```bash
# Format code with Laravel Pint
vendor/bin/pint

# Check formatting without fixing
vendor/bin/pint --test

# Run static analysis
vendor/bin/phpstan analyse
composer test
composer analyse
composer format
```

### Development
```bash
# Install dependencies
composer install

# Update dependencies
composer update

# Run tests in CI environment
GITHUB_TOKEN=dummy-token-for-testing vendor/bin/pest
```

## Architecture

### Core Components

**Resource Pattern**: All API endpoints are organized as resources extending `BaseResource`:
- Resources live in `src/Resources/` and handle high-level API operations
- Each resource maps to a GitHub API entity (repos, pulls, issues, etc.)
- Resources use request classes in `src/Requests/` for actual API calls
- Resources return strongly-typed DTOs from `src/Data/`

**Request/Response Flow**:
1. User calls method on resource (e.g., `Github::repos()->get()`)
2. Resource creates appropriate request object from `src/Requests/`
3. Request is sent via Saloon connector (`ConduitUi\GitHubConnector\GithubConnector`)
4. Response is transformed into DTO using `spatie/laravel-data`
5. Typed DTO is returned to user

**Authentication System**:
- Uses `ConduitUi\GitHubConnector\GithubConnector` with token authentication
- Token configured via `GITHUB_TOKEN` environment variable
- OAuth support available through `GithubOAuth` class for user authentication flows

### Directory Structure

```
src/
├── Auth/ # Authentication strategies
├── Commands/ # Artisan commands
├── Concerns/ # Shared traits
├── Contracts/ # Interfaces
├── Data/ # DTOs for API responses
│ ├── Commits/
│ ├── Issues/
│ ├── Pulls/
│ ├── Releases/
│ └── Repos/
├── Enums/ # Type-safe enums for API parameters
├── Exceptions/ # Custom exception classes
├── Facades/ # Laravel facades
├── Requests/ # Saloon request classes
│ ├── Actions/
│ ├── Commits/
│ ├── Files/
│ ├── Issues/
│ ├── Pulls/
│ ├── Releases/
│ └── Repos/
├── Resources/ # Resource classes for API entities
└── ValueObjects/ # Value objects (e.g., Repo)
```
Tests are Pest. HTTP is faked with Saloon's `MockClient`. `GITHUB_TOKEN` is set in `tests/Pest.php` so token resolution does not call the GitHub CLI.

### Key Design Patterns

**Value Objects**: The `Repo` value object validates and parses repository identifiers:
- `Repo::fromFullName("owner/repo")` - Creates from full name
- `Repo::fromUrl("https://github.com/owner/repo")` - Creates from URL
- Provides `owner()` and `name()` accessors

**Enum-Based Validation**: All API parameters use PHP enums for type safety:
- `Visibility` (PUBLIC, PRIVATE, ALL)
- `Sort` (CREATED, UPDATED, PUSHED, FULL_NAME)
- `Direction` (ASC, DESC)
- `MergeMethod` (MERGE, SQUASH, REBASE)
- Issue/PR specific enums in their respective namespaces

**DTO Pattern**: All API responses are mapped to DTOs using `spatie/laravel-data`:
- Provides type safety and IDE autocompletion
- Handles nullable fields gracefully
- Supports nested data structures

## Testing Approach

Tests use Pest PHP with Laravel testing helpers. Key patterns:
- Mock Saloon responses using `MockClient`
- Test both success and failure scenarios
- Validate DTO structure and data transformation
- Test enum validation and parameter handling

## Known Issues & TODOs

### ReleasesResource Bug
The `ReleasesResource` class incorrectly calls `Repo::fromOwnerAndRepo()` which doesn't exist. Should use `Repo::fromFullName()` instead. Affected lines: ~77, ~106, ~122

### Authentication Enhancement Needed
- Make authentication optional for public repositories
- Support GitHub CLI token reuse (`gh auth token`)
- Better error messages for missing tokens
- Check authentication sources in order: GitHub CLI → env vars → config

### Missing Helper Method
Add `Repo::fromOwnerAndRepo(string $owner, string $repo)` convenience method that internally calls `fromFullName()`.

## Integration Points

### Laravel Service Provider
`GithubClientServiceProvider` registers:
- GitHub facade binding
- Configuration publishing
- Service container bindings

### Configuration
Published via `config/github-client.php`:
- Token configuration
- OAuth settings
- API endpoint customization

### Facade Usage
```php
use JordanPartridge\GithubClient\Facades\Github;

$repos = Github::repos()->all();
```

### Dependency Injection
```php
use JordanPartridge\GithubClient\Contracts\GithubConnectorInterface;

public function __construct(GithubConnectorInterface $github) {
$this->github = $github;
}
```
## Public API shape

## Error Handling
- `Github::repos()->all()` returns a Saloon response. Call `dto()`.
- `Github::repos()->get()` takes `Repo::fromFullName('owner/repo')`.
- `Github::getRepo('owner/repo')` is the string helper.
- `Github::issues()->forRepo()` returns a Saloon response. `dto()` drops items that include a `pull_request` key.
- `Github::pullRequests()->merge()` returns a boolean.
- `Github::commits()->get($repo, $sha)` and `Github::files()->all($repo, $sha)` require a 40 character SHA.
- `Github::files()` has `all` only.
- `Github::releases()` has `all`, `get`, and `latest`.
- `Github::actions()` methods are `listWorkflows`, `getWorkflowRuns`, and `triggerWorkflow`.
- Token order is `github-client.token`, then `github-client.gh_token`, then `gh auth token`.

Custom exceptions provide context-specific error information:
- `ApiException` - API request failures
- `AuthenticationException` - Auth issues
- `RateLimitException` - Rate limit exceeded
- `ValidationException` - Input validation failures
- `NetworkException` - Connectivity issues
`Github::forInstallation()`, `Github::withApp()`, and `installations()` are on the default branch. They are not in the Packagist `v3.0.0` tag.

## Performance Considerations
## Tests and docs

- Auto-pagination available via `allWithPagination()` methods
- Rate limit checking via `getRateLimitStatus()`
- Response caching handled by Saloon
- Lazy loading of resources to minimize memory usage
README examples are exercised in `tests/DocumentationExamplesTest.php`. If a signature changes, update that test and the README together.
9 changes: 8 additions & 1 deletion .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ on:
paths:
- '**.php'
- 'phpstan.neon.dist'
- 'phpstan-baseline.neon'
- '.github/workflows/phpstan.yml'
pull_request:
paths:
- '**.php'
- 'phpstan.neon.dist'
- 'phpstan-baseline.neon'
- '.github/workflows/phpstan.yml'

jobs:
Expand All @@ -17,7 +24,7 @@ jobs:
matrix:
php: ['8.2', '8.3', '8.4']
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Setup PHP
uses: shivammathur/setup-php@v2
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ on:
- 'phpunit.xml.dist'
- 'composer.json'
- 'composer.lock'
pull_request:
paths:
- '**.php'
- '.github/workflows/run-tests.yml'
- 'phpunit.xml.dist'
- 'composer.json'
- 'composer.lock'

jobs:
test:
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ _ide_helper_models.php
phpunit.xml
phpstan.neon
testbench.yaml
/docs
/coverage

**/.claude/settings.local.json
Expand Down
34 changes: 20 additions & 14 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to `github-client` will be documented in this file.

## Unreleased

* Documentation matches the public methods and return types
* Removed the unused skeleton migration, factory, and view
* OAuth throws `AuthenticationException` when the client id, secret, or redirect URL is missing, and `getAuthorizationUrl()` accepts a state value
* Tokens are read from config (`GITHUB_TOKEN`, then `GH_TOKEN`) before the GitHub CLI
* PHPStan baseline no longer ignores errors the analyser does not report
* The test badge tracks the `master` branch

## v2.5.0 - Complete GitHub Issues API - 2025-01-19

### Major New Features
Expand Down Expand Up @@ -43,29 +50,29 @@ All notable changes to `github-client` will be documented in this file.
#### Key Features

```php
// List user issues
$issues = GitHub::issues()->index(
// List user issues. all() returns a Saloon response.
$issues = Github::issues()->all(
state: State::OPEN,
labels: 'bug,enhancement',
sort: Sort::CREATED,
direction: Direction::DESC
);
direction: Direction::DESC,
)->dto();

// Get specific issue
$issue = GitHub::issues()->get('owner', 'repo', 42);
$issue = Github::issues()->get('owner', 'repo', 42);

// Create new issue
$newIssue = GitHub::issues()->create('owner', 'repo', 'Bug Report',
bodyText: 'Detailed description...',
$newIssue = Github::issues()->create('owner', 'repo', 'Bug Report',
body: 'Detailed description...',
labels: ['bug', 'priority-high'],
assignees: ['username']
);

// Add comment
$comment = GitHub::issues()->createComment('owner', 'repo', 42, 'Thanks for reporting!');
$comment = Github::issues()->addComment('owner', 'repo', 42, 'Thanks for reporting!');

// Auto-pagination support
$allIssues = GitHub::issues()->index()->collect();
$allIssues = Github::issues()->allForRepo('owner', 'repo');
```

#### Quality Improvements
Expand Down Expand Up @@ -113,7 +120,7 @@ $allIssues = GitHub::issues()->index()->collect();
* Added support for retrieving individual commits by SHA

```php
GitHub::commits()->get('sha-hash');
Github::commits()->get('owner/repo', '0123456789abcdef0123456789abcdef01234567');

```
#### Details
Expand All @@ -130,10 +137,9 @@ The new commit endpoint provides authenticated access to detailed commit informa
#### Usage Example

```php
$commit = GitHub::commits()->get('abc123def456...');
// Access commit data
$author = $commit->author;
$message = $commit->message;
$commit = Github::commits()->get('owner/repo', '0123456789abcdef0123456789abcdef01234567');
$author = $commit->commit->author->name;
$message = $commit->commit->message;
$changes = $commit->files;

```
Expand Down
Loading
Loading