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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ vendor
node_modules
build
tests/BranchViewer/test_git/HEAD
tests/BranchViewer/test_dep/releases_log
72 changes: 71 additions & 1 deletion src/BranchViewer/BranchViewer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,37 @@

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
{
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'
Expand All @@ -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)) {
Expand All @@ -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
Expand Down Expand Up @@ -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<string> $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');
}

Comment thread
rivanuff marked this conversation as resolved.
$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'])
);
}
}
15 changes: 13 additions & 2 deletions src/BranchViewer/BranchViewerServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use DomainException;
use Illuminate\Support\ServiceProvider;
use LogicException;
use RuntimeException;
use WP_Admin_Bar;

class BranchViewerServiceProvider extends ServiceProvider
Expand All @@ -28,15 +29,25 @@ 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();
}

$adminBar->add_menu([
'id' => 'yard-git-branch',
'title' => $title,
]);

if ($releaseInfo) {
$adminBar->add_menu([
'id' => 'yard-release-info',
'parent' => 'yard-git-branch',
'title' => $releaseInfo,
]);
}
}
}
5 changes: 5 additions & 0 deletions tests/BranchViewer/BranchViewerServiceProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});

/**
Expand Down
54 changes: 51 additions & 3 deletions tests/BranchViewer/BranchViewerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});

/**
Expand All @@ -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');
});

Expand All @@ -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');
});

Expand All @@ -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');
});