diff --git a/.gitignore b/.gitignore index 49bedc5..514ed00 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ vendor node_modules build tests/BranchViewer/test_git/HEAD +tests/BranchViewer/test_dep/releases_log diff --git a/src/BranchViewer/BranchViewer.php b/src/BranchViewer/BranchViewer.php index bf487b2..4722d4c 100644 --- a/src/BranchViewer/BranchViewer.php +++ b/src/BranchViewer/BranchViewer.php @@ -4,18 +4,25 @@ namespace Yard\ConfigExpander\BranchViewer; +use DateTime; +use DateTimeZone; use DomainException; +use InvalidArgumentException; use LogicException; class BranchViewer { protected string $branchname; + protected ?string $releaseInfo; private string $gitPath; + private string $releasePath; - public function __construct(string $gitPath) + public function __construct(string $gitPath, string $releasePath) { $this->gitPath = $gitPath; + $this->releasePath = $releasePath; $this->branchname = $this->constructBranchname(); + $this->releaseInfo = $this->constructReleaseInfo(); } public function getBranchname(): string @@ -23,6 +30,11 @@ public function getBranchname(): string return trim($this->branchname); } + public function getReleaseInfo(): ?string + { + return $this->releaseInfo; + } + protected function constructBranchname(): string { $branches = file($this->getGitDirectory(), FILE_USE_INCLUDE_PATH); // output: 'ref: refs/heads/feature/branchname' @@ -33,6 +45,17 @@ protected function constructBranchname(): string return $this->extractBranchname($branches); } + protected function constructReleaseInfo(): ?string + { + $releases = file($this->getReleaseLog(), FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + + if (false === $releases) { + $releases = []; + } + + return $this->extractReleaseInfo($releases); + } + protected function getGitDirectory(): string { if (! file_exists($this->gitPath)) { @@ -42,6 +65,15 @@ protected function getGitDirectory(): string return $this->gitPath; } + protected function getReleaseLog(): string + { + if (! file_exists($this->releasePath)) { + throw new DomainException('Release log does not exist'); + } + + return $this->releasePath; + } + /** * Extracts the branchname from the array - input: 'ref: refs/heads/feature/branchname' * 1) Converts the array to a string @@ -77,4 +109,42 @@ private function handlePossibleCommit(string $branch): string // Return the first 7 characters of the commit hash. return sprintf('%s (commit)', substr($branch, 0, 7)); } + + /** + * @param array $releases + */ + private function extractReleaseInfo(array $releases): ?string + { + $release = end($releases); + + if (! is_string($release) || '' === trim($release)) { + return null; + } + + $data = json_decode($release, true); + + if (json_last_error() !== JSON_ERROR_NONE || ! is_array($data) || ! is_string($data['created_at']) || ! is_string($data['user'])) { + throw new InvalidArgumentException('Invalid release JSON'); + } + + $timezone = 'Europe/Amsterdam'; + + if (function_exists('get_option')) { + $timezoneOption = get_option('timezone_string', 'Europe/Amsterdam'); + + if (is_string($timezoneOption)) { + $timezone = $timezoneOption; + } + } + + $date = new DateTime($data['created_at']); + $date->setTimezone(new DateTimeZone($timezone)); + $formattedDate = $date->format('d-m-Y - H:i:s'); + + return sprintf( + 'Deployed on %s by %s', + $formattedDate, + trim($data['user']) + ); + } } diff --git a/src/BranchViewer/BranchViewerServiceProvider.php b/src/BranchViewer/BranchViewerServiceProvider.php index 61f495e..01bb5f3 100644 --- a/src/BranchViewer/BranchViewerServiceProvider.php +++ b/src/BranchViewer/BranchViewerServiceProvider.php @@ -7,6 +7,7 @@ use DomainException; use Illuminate\Support\ServiceProvider; use LogicException; +use RuntimeException; use WP_Admin_Bar; class BranchViewerServiceProvider extends ServiceProvider @@ -28,9 +29,11 @@ public function addBranchViewer(WP_Admin_Bar $adminBar): void } try { - $branch = new BranchViewer(\ABSPATH.'../../.git/HEAD'); + $branch = new BranchViewer(\ABSPATH.'../../.git/HEAD', \ABSPATH.'../../../../.dep/releases_log'); $title = sprintf('Branch: %s', $branch->getBranchname()); - } catch (DomainException | LogicException $e) { + $releaseInfo = $branch->getReleaseInfo(); + } catch (DomainException | LogicException | RuntimeException $e) { + $releaseInfo = null; $title = $e->getMessage(); } @@ -38,5 +41,13 @@ public function addBranchViewer(WP_Admin_Bar $adminBar): void 'id' => 'yard-git-branch', 'title' => $title, ]); + + if ($releaseInfo) { + $adminBar->add_menu([ + 'id' => 'yard-release-info', + 'parent' => 'yard-git-branch', + 'title' => $releaseInfo, + ]); + } } } diff --git a/tests/BranchViewer/BranchViewerServiceProviderTest.php b/tests/BranchViewer/BranchViewerServiceProviderTest.php index 8f8cb7d..09c47dd 100644 --- a/tests/BranchViewer/BranchViewerServiceProviderTest.php +++ b/tests/BranchViewer/BranchViewerServiceProviderTest.php @@ -11,10 +11,15 @@ beforeEach(function () { $this->app->instance('path.public', __DIR__); $this->validGitPath = __DIR__ . '/test_git/HEAD'; + $this->validReleasePath = __DIR__ . '/test_dep/releases_log'; if (! file_exists(dirname($this->validGitPath))) { mkdir(dirname($this->validGitPath), 0777, true); } + + if (! file_exists(dirname($this->validReleasePath))) { + mkdir(dirname($this->validReleasePath), 0777, true); + } }); /** diff --git a/tests/BranchViewer/BranchViewerTest.php b/tests/BranchViewer/BranchViewerTest.php index 6adb9d1..69e2881 100644 --- a/tests/BranchViewer/BranchViewerTest.php +++ b/tests/BranchViewer/BranchViewerTest.php @@ -5,16 +5,23 @@ namespace Yard\ConfigExpander\Tests\BranchViewer; use DomainException; +use InvalidArgumentException; use LogicException; use Yard\ConfigExpander\BranchViewer\BranchViewer; beforeEach(function () { $this->validGitPath = __DIR__ . '/test_git/HEAD'; + $this->validReleasePath = __DIR__ . '/test_dep/releases_log'; $this->invalidGitPath = __DIR__ . '/invalid_git/HEAD'; + $this->invalidReleasePath = __DIR__ . '/invalid_dep/releases_log'; if (! file_exists(dirname($this->validGitPath))) { mkdir(dirname($this->validGitPath), 0777, true); } + + if (! file_exists(dirname($this->validReleasePath))) { + mkdir(dirname($this->validReleasePath), 0777, true); + } }); /** @@ -23,7 +30,7 @@ * @preserveGlobalState disabled */ test('constructBranchname throws DomainException if git directory does not exist', function () { - expect(fn () => new BranchViewer($this->invalidGitPath)) + expect(fn () => new BranchViewer($this->invalidGitPath, $this->invalidReleasePath)) ->toThrow(DomainException::class, 'Git directory does not exist'); }); @@ -34,8 +41,9 @@ */ test('constructBranchname throws LogicException if no branch name is found', function () { file_put_contents($this->validGitPath, ''); + file_put_contents($this->validReleasePath, '{"created_at":"2026-02-20T15:54:49+0000","release_name":"466","user":"rivanuff","target":"chore\/deployment-info"}'); - expect(fn () => new BranchViewer($this->validGitPath)) + expect(fn () => new BranchViewer($this->validGitPath, $this->validReleasePath)) ->toThrow(LogicException::class, 'No branchname found'); }); @@ -46,7 +54,47 @@ */ test('getBranchname returns the branch name', function () { file_put_contents($this->validGitPath, 'ref: refs/heads/feature/branchname'); + file_put_contents($this->validReleasePath, '{"created_at":"2026-02-20T15:54:49+0000","release_name":"466","user":"rivanuff","target":"chore\/deployment-info"}'); - $branchViewer = new BranchViewer($this->validGitPath); + $branchViewer = new BranchViewer($this->validGitPath, $this->validReleasePath); expect($branchViewer->getBranchname())->toBe('feature/branchname'); }); + +/** + * @runInSeparateProcess + * + * @preserveGlobalState disabled + */ +test('constructReleaseInfo to be null if no release is found', function () { + file_put_contents($this->validGitPath, 'ref: refs/heads/feature/branchname'); + file_put_contents($this->validReleasePath, ''); + + $branchViewer = new BranchViewer($this->validGitPath, $this->validReleasePath); + expect($branchViewer->getReleaseInfo())->toBe(null); +}); + +/** + * @runInSeparateProcess + * + * @preserveGlobalState disabled + */ +test('getReleaseInfo returns InvalidArgumentException when release JSON invalid', function () { + file_put_contents($this->validGitPath, 'ref: refs/heads/feature/branchname'); + file_put_contents($this->validReleasePath, '{"created_at"|"2026-02-20T15:54:49+0000""release_name":"466","user":"rivanuff","target":"chore\/deployment-info"}'); + + expect(fn () => new BranchViewer($this->validGitPath, $this->validReleasePath)) + ->toThrow(InvalidArgumentException::class, 'Invalid release JSON'); +}); + +/** + * @runInSeparateProcess + * + * @preserveGlobalState disabled + */ +test('getReleaseInfo returns the release info', function () { + file_put_contents($this->validGitPath, 'ref: refs/heads/feature/branchname'); + file_put_contents($this->validReleasePath, '{"created_at":"2026-02-20T15:54:49+0000","release_name":"466","user":"rivanuff","target":"chore\/deployment-info"}'); + + $branchViewer = new BranchViewer($this->validGitPath, $this->validReleasePath); + expect($branchViewer->getReleaseInfo())->toBe('Deployed on 20-02-2026 - 16:54:49 by rivanuff'); +});