adachsoft/gitlib

Lightweight, framework-agnostic Git library with flat facade and action dispatcher for PHP.

1.0.0 2025-09-12 05:28 UTC

This package is not auto-updated.

Last update: 2025-09-13 02:04:14 UTC


README

Lightweight, framework-agnostic Git library with a flat facade and a name-based action dispatcher. Built for PHP 8.3+, PSR-compliant, easily extensible with plugin-like operation handlers.

Requirements

  • PHP 8.3+
  • Composer

Installation

composer require adachsoft/gitlib

Quick start

<?php

use Adachsoft\CommandExecutor\SimpleCommandExecutor;
use Adachsoft\GitLab\Internal\Adapter\CommandExecutorProcessRunner;
use Adachsoft\GitLab\Internal\Operation\HandlerLocator;
use Adachsoft\GitLab\Internal\Operation\OperationRegistry;
use Adachsoft\GitLab\Internal\GitRepository;
use Adachsoft\GitLab\DTO\Options\PullOptions;
use Adachsoft\GitLab\DTO\Options\PushOptions;
use Adachsoft\GitLab\Exception\ProcessFailedException;
use Adachsoft\GitLab\Exception\ValidationException;

$executor = new SimpleCommandExecutor();
$runner   = new CommandExecutorProcessRunner($executor);

$locator  = new HandlerLocator();
$registry = (new OperationRegistry())
    ->discoverAndRegisterHandlers($locator, $runner, __DIR__);

$repo = new GitRepository($runner, $registry, __DIR__); // working directory

try {
    // 1) Using the facade methods
    $status = $repo->status();
    $repo->add(['file1.php', 'file2.php']);
    $repo->commit('Initial commit');

    $repo->pull(new PullOptions(remote: 'origin', branch: 'main', rebase: true));
    $repo->push(new PushOptions(remote: 'origin', branch: 'main', forceWithLease: true));

    // 2) Using the action dispatcher
    $repo->execute('getRemotes', ['verbose' => true]);
    $repo->execute('rebase', ['branch' => 'feature/xyz']);
    $repo->execute('push', [
        'remote' => 'origin',
        'branch' => 'main',
        'setUpstream' => true,
    ]);
} catch (ValidationException|ProcessFailedException $e) {
    // Handle invalid arguments or failed git processes
    echo $e->getMessage();
}

Concepts

  • Facade: GitRepositoryInterface exposes a full set of explicit Git operations (no magic execute() here).
  • Dispatcher: GitActionExecutorInterface::execute(string $action, array $args) allows dynamic invocation by action name.
  • Handlers: Each action is handled by a class implementing OperationHandlerInterface and marked with #[GitOperation('actionName')].
  • Process execution: Abstracted via ProcessRunnerInterface with the default adapter CommandExecutorProcessRunner (wraps adachsoft/command-executor-lib).
  • DTOs: Simple final readonly objects (no getters) for structured results.

Auto-discovery of handlers

HandlerLocator discovers and instantiates handlers marked with #[GitOperation] in the Adachsoft\GitLab\Extensions namespace (filesystem defaults to src/Extensions). You can customize the directory and namespace if needed.

$registry->discoverAndRegisterHandlers($locator, $runner, $workingDirectory);

Adding a custom action

1) Create a handler in src/Extensions:

<?php

namespace Adachsoft\GitLab\Extensions;

use Adachsoft\GitLab\Attributes\GitOperation;
use Adachsoft\GitLab\Contracts\ProcessRunnerInterface;
use Adachsoft\GitLab\Contracts\OperationHandlerInterface;

#[GitOperation('hello')]
final class HelloHandler extends AbstractOperationHandler implements OperationHandlerInterface
{
    public function name(): string { return 'hello'; }
    public function handle(array $arguments)
    {
        $this->processRunner->run('git status', $this->workingDirectory);
        return 'world';
    }
}

2) Let the locator discover it (nothing else to change).

Exceptions

  • ValidationException – invalid arguments/options passed to operations/handlers.
  • ProcessFailedException – underlying git command failed (non-zero exit, etc.).

Notes

  • Framework-agnostic: no container required; wire objects manually.
  • PSR style; PHPDoc/comments in English.
  • See docs/tasks/task001-plan-v1.md for the original design plan and acceptance criteria.