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
52 changes: 48 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,28 @@ A Symfony bundle that fetches commit history from GitLab or GitHub repositories
- **Standalone Page**: Ready-to-use page with embedded CSS
- **Embeddable Fragment**: Include the timeline in your own layouts

## Architecture

This project is split into two packages:

- **[spiriitlabs/commit-history](https://github.com/SpiriitLabs/commit-history)** - A standalone, framework-agnostic PHP library containing all the core logic (providers, DTOs, services, diff parsers)
- **spiriitlabs/commit-history-bundle** (this package) - A Symfony bundle providing controllers, commands, Twig templates, and adapters to integrate the library with Symfony

This separation allows you to use the core library in any PHP project (Laravel, plain PHP, etc.) while Symfony users get a ready-to-use bundle with full integration.

### Bundle Components

The bundle provides Symfony-specific integrations:

| Component | Description |
|-----------|-------------|
| `SymfonyCacheAdapter` | Bridges Symfony's cache to the library's `CacheInterface` |
| `SymfonyHttpClientAdapter` | Bridges Symfony's HTTP client to the library's `HttpClientInterface` |
| `TimelineController` | Renders the timeline page |
| `DependenciesChangesController` | JSON API for dependency details |
| `RefreshCacheCommand` | CLI command to refresh cache |
| `ClearCacheCommand` | CLI command to clear cache |

## Requirements

- PHP 8.2 or higher
Expand Down Expand Up @@ -143,7 +165,7 @@ You can embed the timeline in your own templates by injecting the `FeedFetcherIn

namespace App\Controller;

use Spiriit\Bundle\CommitHistoryBundle\Service\FeedFetcherInterface;
use Spiriit\CommitHistory\Service\FeedFetcherInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
Expand Down Expand Up @@ -246,15 +268,15 @@ spiriit_commit_history:

The bundle uses a tagged service pattern for diff parsers. You can add support for additional dependency file formats by creating your own parser.

1. Create a parser class implementing `DiffParserInterface`:
1. Create a parser class implementing `DiffParserInterface` from the library:

```php
<?php

namespace App\Service\DiffParser;

use Spiriit\Bundle\CommitHistoryBundle\DTO\DependencyChange;
use Spiriit\Bundle\CommitHistoryBundle\Service\DiffParser\DiffParserInterface;
use Spiriit\CommitHistory\DTO\DependencyChange;
use Spiriit\CommitHistory\DiffParser\DiffParserInterface;

class GemfileDiffParser implements DiffParserInterface
{
Expand Down Expand Up @@ -359,6 +381,28 @@ The templates use BEM naming convention:
| `.timeline__dependencies-type--updated` | Updated dependency (orange) |
| `.timeline__dependencies-type--removed` | Removed dependency (red) |

## Using the Standalone Library

If you're not using Symfony, you can use the standalone library directly. See the [spiriitlabs/commit-history](https://github.com/SpiriitLabs/commit-history) repository for documentation.

```bash
composer require spiriitlabs/commit-history
```

The library provides:

- `Spiriit\CommitHistory\Provider\Github\GithubProvider` - GitHub API client
- `Spiriit\CommitHistory\Provider\Gitlab\GitlabProvider` - GitLab API client
- `Spiriit\CommitHistory\Service\FeedFetcher` - Caching wrapper for providers
- `Spiriit\CommitHistory\DTO\Commit` - Commit data transfer object
- `Spiriit\CommitHistory\DTO\DependencyChange` - Dependency change DTO
- `Spiriit\CommitHistory\DiffParser\*` - Diff parsers for dependency detection

You'll need to provide your own implementations of:

- `Spiriit\CommitHistory\Contract\CacheInterface` - Cache abstraction
- `Spiriit\CommitHistory\Contract\HttpClientInterface` - HTTP client abstraction

## Testing

Run the test suite:
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
],
"require": {
"php": ">=8.2",
"spiriitlabs/commit-history": "^1.0",
"symfony/cache": "^6.4|^7.0",
"symfony/console": "^6.4|^7.0",
"symfony/framework-bundle": "^6.4|^7.0",
Expand Down
41 changes: 41 additions & 0 deletions src/Adapter/SymfonyHttpClientAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

/*
* This file is part of the spiriitlabs/commit-history-bundle package.
* Copyright (c) SpiriitLabs <https://www.spiriit.com/>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Spiriit\Bundle\CommitHistoryBundle\Adapter;

use Spiriit\CommitHistory\Contract\HttpClientInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface as SymfonyHttpClientInterface;

final class SymfonyHttpClientAdapter implements HttpClientInterface
{
public function __construct(
private readonly SymfonyHttpClientInterface $httpClient,
) {
}

/**
* @param array<string, string> $headers
*
* @return array{status: int, headers: array<string, list<string>>, body: string}
*/
public function request(string $method, string $url, array $headers = []): array
{
$response = $this->httpClient->request($method, $url, [
'headers' => $headers,
]);

return [
'status' => $response->getStatusCode(),
'headers' => $response->getHeaders(),
'body' => $response->getContent(),
];
}
}
8 changes: 4 additions & 4 deletions src/Command/ClearCacheCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
namespace Spiriit\Bundle\CommitHistoryBundle\Command;

use Spiriit\Bundle\CommitHistoryBundle\Controller\DependenciesChangesController;
use Spiriit\Bundle\CommitHistoryBundle\Service\DependencyDetectionService;
use Spiriit\Bundle\CommitHistoryBundle\Service\FeedFetcherInterface;
use Spiriit\Bundle\CommitHistoryBundle\Service\CachingDependencyDetectionService;
use Spiriit\Bundle\CommitHistoryBundle\Service\CachingFeedFetcherInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand All @@ -31,7 +31,7 @@ class ClearCacheCommand extends Command
{
public function __construct(
private readonly CacheInterface $cache,
private readonly FeedFetcherInterface $feedFetcher,
private readonly CachingFeedFetcherInterface $feedFetcher,
) {
parent::__construct();
}
Expand Down Expand Up @@ -101,7 +101,7 @@ private function doClearYear(int $year): int
private function clearDependencyCaches(string $commitId): void
{
// Clear dependency detection cache (badge)
$hasDepsKey = DependencyDetectionService::getCacheKeyPrefix().$commitId;
$hasDepsKey = CachingDependencyDetectionService::getCacheKeyPrefix().$commitId;
$this->cache->delete($hasDepsKey);

// Clear dependency changes cache (list)
Expand Down
10 changes: 5 additions & 5 deletions src/Command/RefreshCacheCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@

namespace Spiriit\Bundle\CommitHistoryBundle\Command;

use Spiriit\Bundle\CommitHistoryBundle\Service\DependencyDetectionService;
use Spiriit\Bundle\CommitHistoryBundle\Service\FeedFetcherInterface;
use Spiriit\Bundle\CommitHistoryBundle\Service\CachingDependencyDetectionService;
use Spiriit\Bundle\CommitHistoryBundle\Service\CachingFeedFetcherInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand All @@ -29,7 +29,7 @@
class RefreshCacheCommand extends Command
{
public function __construct(
private readonly FeedFetcherInterface $feedFetcher,
private readonly CachingFeedFetcherInterface $feedFetcher,
private readonly CacheInterface $cache,
) {
parent::__construct();
Expand Down Expand Up @@ -72,7 +72,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
}

/**
* @return \Spiriit\Bundle\CommitHistoryBundle\DTO\Commit[]
* @return \Spiriit\CommitHistory\DTO\Commit[]
*/
private function refreshYear(int $year): array
{
Expand All @@ -81,7 +81,7 @@ private function refreshYear(int $year): array

// Clear dependency detection cache for existing commits
foreach ($existingCommits as $commit) {
$hasDepsKey = DependencyDetectionService::getCacheKeyPrefix().$commit->id;
$hasDepsKey = CachingDependencyDetectionService::getCacheKeyPrefix().$commit->id;
$this->cache->delete($hasDepsKey);
}

Expand Down
6 changes: 3 additions & 3 deletions src/Controller/DependenciesChangesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

namespace Spiriit\Bundle\CommitHistoryBundle\Controller;

use Spiriit\Bundle\CommitHistoryBundle\DTO\DependencyChange;
use Spiriit\Bundle\CommitHistoryBundle\Provider\ProviderInterface;
use Spiriit\Bundle\CommitHistoryBundle\Service\DiffParser\DiffParserRegistry;
use Spiriit\CommitHistory\DiffParser\DiffParserRegistry;
use Spiriit\CommitHistory\DTO\DependencyChange;
use Spiriit\CommitHistory\Provider\ProviderInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Cache\CacheInterface;
Expand Down
2 changes: 1 addition & 1 deletion src/Controller/TimelineController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Spiriit\Bundle\CommitHistoryBundle\Controller;

use Spiriit\Bundle\CommitHistoryBundle\Service\FeedFetcherInterface;
use Spiriit\CommitHistory\Service\FeedFetcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;
Expand Down
39 changes: 0 additions & 39 deletions src/DTO/Commit.php

This file was deleted.

28 changes: 0 additions & 28 deletions src/DTO/DependencyChange.php

This file was deleted.

21 changes: 20 additions & 1 deletion src/DependencyInjection/SpiriitCommitHistoryExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Spiriit\Bundle\CommitHistoryBundle\DependencyInjection;

use Spiriit\Bundle\CommitHistoryBundle\Provider\ProviderInterface;
use Spiriit\CommitHistory\Provider\ProviderInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
Expand Down Expand Up @@ -47,6 +47,10 @@ public function load(array $configs, ContainerBuilder $container): void
$container->setParameter('spiriit_commit_history.github.token', $github['token'] ?? null);
$container->setParameter('spiriit_commit_history.github.ref', $github['ref'] ?? null);

// Compute provider hash for unique cache keys
$providerHash = $this->computeProviderHash($config);
$container->setParameter('spiriit_commit_history.provider_hash', $providerHash);

// Load services
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.php');
Expand All @@ -66,4 +70,19 @@ private function configureProvider(ContainerBuilder $container, string $provider
$container->setAlias('spiriit_commit_history.provider', $providerServiceId);
$container->setAlias(ProviderInterface::class, $providerServiceId);
}

/**
* Compute a unique hash for the provider configuration.
* Used to create unique cache keys per provider instance.
*
* @param array<string, mixed> $config
*/
private function computeProviderHash(array $config): string
{
return match ($config['provider']) {
'gitlab' => md5($config['gitlab']['base_url'].'_'.$config['gitlab']['project_id']),
'github' => md5($config['github']['base_url'].'_'.$config['github']['owner'].'_'.$config['github']['repo']),
default => md5($config['provider']),
};
}
}
22 changes: 0 additions & 22 deletions src/Provider/CommitParserInterface.php

This file was deleted.

Loading