197 lines
5.6 KiB
PHP
197 lines
5.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App;
|
|
|
|
use App\Enums\ReleaseChannel;
|
|
use DateTime;
|
|
use DateTimeZone;
|
|
use Dotenv\Dotenv;
|
|
use Psr\SimpleCache\CacheInterface;
|
|
use Symfony\Component\Process\Process;
|
|
use Throwable;
|
|
|
|
/**
|
|
* App Core Framework Version
|
|
*
|
|
* @phpstan-type VersionDetails array{
|
|
* commit: string|null,
|
|
* commit_short: string,
|
|
* commit_timestamp: int,
|
|
* commit_date: string,
|
|
* branch: string|null,
|
|
* }
|
|
*/
|
|
final class Version
|
|
{
|
|
/** @var string The current latest stable version. */
|
|
public const STABLE_VERSION = '0.19.5';
|
|
|
|
private string $repoDir;
|
|
|
|
public function __construct(
|
|
private readonly CacheInterface $cache,
|
|
private readonly Environment $environment
|
|
) {
|
|
$this->repoDir = $environment->getBaseDirectory();
|
|
}
|
|
|
|
public function getReleaseChannelEnum(): ReleaseChannel
|
|
{
|
|
if ($this->environment->isDocker()) {
|
|
return $this->environment->getReleaseChannelEnum();
|
|
}
|
|
|
|
$details = $this->getDetails();
|
|
return ('stable' === $details['branch'])
|
|
? ReleaseChannel::Stable
|
|
: ReleaseChannel::RollingRelease;
|
|
}
|
|
|
|
/**
|
|
* Load cache or generate new repository details from the underlying Git repository.
|
|
*
|
|
* @return VersionDetails
|
|
*/
|
|
public function getDetails(): array
|
|
{
|
|
static $details;
|
|
|
|
if (!$details) {
|
|
$details = $this->cache->get('app_version_details');
|
|
|
|
if (empty($details)) {
|
|
$rawDetails = $this->getRawDetails();
|
|
|
|
$details = [
|
|
'commit' => $rawDetails['commit'],
|
|
'commit_short' => substr($rawDetails['commit'] ?? '', 0, 7),
|
|
'branch' => $rawDetails['branch'],
|
|
];
|
|
|
|
if (!empty($rawDetails['commit_date_raw'])) {
|
|
$commitDate = new DateTime($rawDetails['commit_date_raw']);
|
|
$commitDate->setTimezone(new DateTimeZone('UTC'));
|
|
|
|
$details['commit_timestamp'] = $commitDate->getTimestamp();
|
|
$details['commit_date'] = $commitDate->format('Y-m-d G:i');
|
|
} else {
|
|
$details['commit_timestamp'] = 0;
|
|
$details['commit_date'] = 'N/A';
|
|
}
|
|
|
|
$ttl = $this->environment->isProduction() ? 86400 : 600;
|
|
|
|
$this->cache->set('app_version_details', $details, $ttl);
|
|
}
|
|
}
|
|
|
|
return $details;
|
|
}
|
|
|
|
/**
|
|
* Generate new repository details from the underlying Git repository.
|
|
*
|
|
* @return array{
|
|
* commit: string|null,
|
|
* commit_date_raw: string|null,
|
|
* branch: string|null
|
|
* }
|
|
*/
|
|
private function getRawDetails(): array
|
|
{
|
|
if (is_file($this->repoDir . '/.gitinfo')) {
|
|
$fileContents = file_get_contents($this->repoDir . '/.gitinfo');
|
|
if (!empty($fileContents)) {
|
|
try {
|
|
$gitInfo = Dotenv::parse($fileContents);
|
|
return [
|
|
'commit' => $gitInfo['COMMIT_LONG'] ?? null,
|
|
'commit_date_raw' => $gitInfo['COMMIT_DATE'] ?? null,
|
|
'branch' => $gitInfo['BRANCH'] ?? null,
|
|
];
|
|
} catch (Throwable) {
|
|
// Noop
|
|
}
|
|
}
|
|
}
|
|
|
|
if (is_dir($this->repoDir . '/.git')) {
|
|
return [
|
|
'commit' => $this->runProcess(['git', 'log', '--pretty=%H', '-n1', 'HEAD']),
|
|
'commit_date_raw' => $this->runProcess(['git', 'log', '-n1', '--pretty=%ci', 'HEAD']),
|
|
'branch' => $this->runProcess(['git', 'rev-parse', '--abbrev-ref', 'HEAD'], 'main'),
|
|
];
|
|
}
|
|
|
|
return [
|
|
'commit' => null,
|
|
'commit_date_raw' => null,
|
|
'branch' => null,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Run the specified process and return its output.
|
|
*/
|
|
private function runProcess(array $proc, string $default = ''): string
|
|
{
|
|
$process = new Process($proc);
|
|
$process->setWorkingDirectory($this->repoDir);
|
|
$process->run();
|
|
|
|
if (!$process->isSuccessful()) {
|
|
return $default;
|
|
}
|
|
|
|
return trim($process->getOutput());
|
|
}
|
|
|
|
/**
|
|
* @return string A textual representation of the current installed version.
|
|
*/
|
|
public function getVersionText(): string
|
|
{
|
|
$details = $this->getDetails();
|
|
$releaseChannel = $this->getReleaseChannelEnum();
|
|
|
|
if (ReleaseChannel::RollingRelease === $releaseChannel) {
|
|
$commitLink = 'https://github.com/AzuraCast/AzuraCast/commit/' . $details['commit'];
|
|
$commitText = sprintf(
|
|
'#<a href="%s" target="_blank">%s</a> (%s)',
|
|
$commitLink,
|
|
$details['commit_short'],
|
|
$details['commit_date']
|
|
);
|
|
|
|
return 'Rolling Release ' . $commitText;
|
|
}
|
|
|
|
return 'v' . self::STABLE_VERSION . ' Stable';
|
|
}
|
|
|
|
/**
|
|
* @return string|null The long-form Git hash that represents the current commit of this installation.
|
|
*/
|
|
public function getCommitHash(): ?string
|
|
{
|
|
$details = $this->getDetails();
|
|
return $details['commit'];
|
|
}
|
|
|
|
/**
|
|
* @return string The shortened Git hash corresponding to the current commit.
|
|
*/
|
|
public function getCommitShort(): string
|
|
{
|
|
$details = $this->getDetails();
|
|
return $details['commit_short'];
|
|
}
|
|
|
|
public function getVersion(): string
|
|
{
|
|
return self::STABLE_VERSION;
|
|
}
|
|
}
|