Summary
Define comprehensive interface contracts for the entire package following interface-first design pattern, ensuring clean architecture and testability.
Acceptance Criteria
Core Query Interfaces
Create src/Contracts/ directory with all interface definitions:
namespace ConduitUI\Pr\Contracts;
use Illuminate\Support\Collection;
use ConduitUI\Pr\Data\PullRequest;
/**
* Contract for querying pull requests
*/
interface PullRequestQueryInterface
{
public function whereOpen(): self;
public function whereClosed(): self;
public function whereMerged(): self;
public function whereState(string $state): self;
public function whereBase(string $branch): self;
public function whereHead(string $branch): self;
public function whereAuthor(string $username): self;
public function whereLabel(string $label): self;
public function whereLabels(array $labels): self;
public function whereDraft(bool $draft = true): self;
public function orderByCreated(string $direction = 'desc'): self;
public function orderByUpdated(string $direction = 'desc'): self;
public function perPage(int $count): self;
public function page(int $page): self;
public function get(): Collection;
public function first(): ?PullRequest;
public function count(): int;
public function exists(): bool;
}
/**
* Contract for managing pull requests
*/
interface PullRequestManagerInterface
{
public function find(int $number): PullRequest;
public function get(int $number): PullRequest;
public function query(): PullRequestQueryInterface;
public function create(): PullRequestBuilderInterface;
}
/**
* Contract for creating pull requests
*/
interface PullRequestBuilderInterface
{
public function title(string $title): self;
public function body(string $body): self;
public function head(string $branch): self;
public function base(string $branch): self;
public function draft(bool $draft = true): self;
public function maintainerCanModify(bool $allowed = true): self;
public function create(): PullRequest;
}
Review Interfaces
namespace ConduitUI\Pr\Contracts;
use ConduitUI\Pr\Data\Review;
use Illuminate\Support\Collection;
/**
* Contract for creating reviews
*/
interface ReviewBuilderInterface
{
public function approve(string $comment = null): self;
public function requestChanges(string $comment = null): self;
public function comment(string $body): self;
public function addInlineComment(string $path, int $line, string $comment): self;
public function addSuggestion(string $path, int $startLine, int $endLine, string $suggestion): self;
public function submit(): Review;
}
/**
* Contract for querying reviews
*/
interface ReviewQueryInterface
{
public function get(): Collection;
public function whereApproved(): Collection;
public function whereChangesRequested(): Collection;
public function wherePending(): Collection;
public function byUser(string $username): Collection;
public function latest(): ?Review;
}
Check Run Interfaces
namespace ConduitUI\Pr\Contracts;
use ConduitUI\Pr\Data\CheckRun;
use ConduitUI\Pr\Data\CheckSummary;
use Illuminate\Support\Collection;
/**
* Contract for querying check runs
*/
interface CheckRunQueryInterface
{
public function get(): Collection;
public function wherePassing(): Collection;
public function whereFailing(): Collection;
public function wherePending(): Collection;
public function whereNeutral(): Collection;
public function whereSkipped(): Collection;
public function latest(): ?CheckRun;
public function byName(string $name): ?CheckRun;
public function summary(): CheckSummary;
}
Merge Interfaces
namespace ConduitUI\Pr\Contracts;
use ConduitUI\Pr\Data\PullRequest;
/**
* Contract for merge operations
*/
interface MergeManagerInterface
{
public function merge(?string $commitTitle = null, ?string $commitMessage = null): PullRequest;
public function squash(?string $commitTitle = null, ?string $commitMessage = null): PullRequest;
public function rebase(): PullRequest;
public function canMerge(): bool;
public function deleteBranch(): bool;
}
File Interfaces
namespace ConduitUI\Pr\Contracts;
use ConduitUI\Pr\Data\FileChange;
use ConduitUI\Pr\Data\FileStats;
use Illuminate\Support\Collection;
/**
* Contract for querying changed files
*/
interface FileQueryInterface
{
public function get(): Collection;
public function whereAdded(): Collection;
public function whereModified(): Collection;
public function whereRemoved(): Collection;
public function whereRenamed(): Collection;
public function wherePath(string $pattern): Collection;
public function whereExtension(string $extension): Collection;
public function stats(): FileStats;
}
Action Interfaces
namespace ConduitUI\Pr\Contracts;
use ConduitUI\Pr\Data\PullRequest;
/**
* Contract for PR state actions
*/
interface PullRequestActionsInterface
{
public function close(string $comment = null): PullRequest;
public function reopen(): PullRequest;
public function markDraft(): PullRequest;
public function markReady(): PullRequest;
public function addLabel(string $label): self;
public function addLabels(array $labels): self;
public function removeLabel(string $label): self;
public function setLabels(array $labels): self;
public function requestReview(string $username): self;
public function requestReviews(array $usernames): self;
public function requestTeamReview(string $teamSlug): self;
public function assign(string $username): self;
public function unassign(string $username): self;
public function comment(string $body): PullRequest;
}
Comment Interfaces
namespace ConduitUI\Pr\Contracts;
use ConduitUI\Pr\Data\Comment;
use Illuminate\Support\Collection;
/**
* Contract for managing comments
*/
interface CommentManagerInterface
{
public function get(): Collection;
public function create(string $body): Comment;
public function update(int $commentId, string $body): Comment;
public function delete(int $commentId): bool;
}
Interface Design Principles
1. Fluent Chainability
All builder/action interfaces return self for chainable methods:
->title('foo')
->body('bar')
->draft()
->create()
2. Query Segregation
Separate query interfaces from command interfaces:
*QueryInterface - Read operations returning Collections
*BuilderInterface - Creation operations
*ManagerInterface - CRUD operations
*ActionsInterface - State-changing operations
3. Type Safety
All interfaces use strict typing:
public function find(int $number): PullRequest;
public function get(): Collection;
public function exists(): bool;
4. Nullable Returns
Use nullable types where operations may not return data:
public function first(): ?PullRequest;
public function latest(): ?Review;
public function byName(string $name): ?CheckRun;
5. Collection Returns
Query operations return Laravel Collections for filtering/mapping:
public function get(): Collection; // Collection<PullRequest>
public function whereApproved(): Collection; // Collection<Review>
Implementation Requirements
Directory Structure
src/
├── Contracts/
│ ├── PullRequestQueryInterface.php
│ ├── PullRequestManagerInterface.php
│ ├── PullRequestBuilderInterface.php
│ ├── PullRequestActionsInterface.php
│ ├── ReviewBuilderInterface.php
│ ├── ReviewQueryInterface.php
│ ├── CheckRunQueryInterface.php
│ ├── MergeManagerInterface.php
│ ├── FileQueryInterface.php
│ └── CommentManagerInterface.php
├── Services/
│ ├── PullRequestQuery.php (implements PullRequestQueryInterface)
│ ├── PullRequestManager.php (implements PullRequestManagerInterface)
│ ├── PullRequestBuilder.php (implements PullRequestBuilderInterface)
│ ├── PullRequestActions.php (implements PullRequestActionsInterface)
│ ├── ReviewBuilder.php (implements ReviewBuilderInterface)
│ ├── ReviewQuery.php (implements ReviewQueryInterface)
│ ├── CheckRunQuery.php (implements CheckRunQueryInterface)
│ ├── MergeManager.php (implements MergeManagerInterface)
│ ├── FileQuery.php (implements FileQueryInterface)
│ └── CommentManager.php (implements CommentManagerInterface)
└── Data/
├── PullRequest.php
├── Review.php
├── CheckRun.php
├── CheckSummary.php
├── FileChange.php
├── FileStats.php
├── Comment.php
├── User.php
└── Label.php
Service Provider Bindings
namespace ConduitUI\Pr;
use Illuminate\Support\ServiceProvider;
class PrServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->bind(
Contracts\PullRequestManagerInterface::class,
Services\PullRequestManager::class
);
$this->app->bind(
Contracts\PullRequestQueryInterface::class,
Services\PullRequestQuery::class
);
// ... bind all other interfaces
}
}
Testing Requirements
Interface Compliance Tests
it('implements PullRequestQueryInterface')
->expect(PullRequestQuery::class)
->toImplement(PullRequestQueryInterface::class);
it('implements ReviewBuilderInterface')
->expect(ReviewBuilder::class)
->toImplement(ReviewBuilderInterface::class);
// Test all service classes implement their interfaces
Type Testing
it('returns Collection from query')
->expect(fn() => PullRequests::forRepo('test/repo')->query()->get())
->toBeInstanceOf(Collection::class);
it('returns PullRequest from find')
->expect(fn() => PullRequests::find('test/repo', 1))
->toBeInstanceOf(PullRequest::class);
Benefits
- Testability: Easy to mock interfaces for testing
- Extensibility: Swap implementations without changing consumer code
- Documentation: Interfaces serve as contracts and documentation
- Type Safety: IDE autocomplete and static analysis support
- Dependency Injection: Clean DI with interface bindings
- Architecture: Clear separation of concerns
Related Issues
References
Labels
- enhancement
- architecture
- contracts
- high-priority
Summary
Define comprehensive interface contracts for the entire package following interface-first design pattern, ensuring clean architecture and testability.
Acceptance Criteria
Core Query Interfaces
Create
src/Contracts/directory with all interface definitions:Review Interfaces
Check Run Interfaces
Merge Interfaces
File Interfaces
Action Interfaces
Comment Interfaces
Interface Design Principles
1. Fluent Chainability
All builder/action interfaces return
selffor chainable methods:2. Query Segregation
Separate query interfaces from command interfaces:
*QueryInterface- Read operations returning Collections*BuilderInterface- Creation operations*ManagerInterface- CRUD operations*ActionsInterface- State-changing operations3. Type Safety
All interfaces use strict typing:
4. Nullable Returns
Use nullable types where operations may not return data:
5. Collection Returns
Query operations return Laravel Collections for filtering/mapping:
Implementation Requirements
Directory Structure
Service Provider Bindings
Testing Requirements
Interface Compliance Tests
Type Testing
Benefits
Related Issues
References
Labels