File: /home/wbwebdes/domains/uren-registratie.blankevoort.net/public_html/src/Utils/ReleaseVersion.php
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Utils;
use App\Constants;
use Composer\Semver\Semver;
use Composer\Semver\VersionParser;
/**
* Code inspired by https://github.com/consolidation/self-update (MIT license - 03 Sept. 2022)
*/
final class ReleaseVersion
{
/**
* Get all releases from GitHub.
*
* @throws \Exception
* @return array|null
* @return array<string, array{'version': string, 'date': \DateTimeInterface, 'url': string, 'download': string, 'content': string}>
* @return array
*/
private function getReleasesFromGithub(): array
{
$versionParser = new VersionParser();
$opts = [
'http' => [
'method' => 'GET',
'header' => [
'User-Agent: ' . Constants::SOFTWARE . ' ' . Constants::VERSION . ' Update-Check (PHP)',
],
],
];
$context = stream_context_create($opts);
$releases = file_get_contents('https://api.github.com/repos/' . Constants::GITHUB_REPO . '/releases', false, $context);
$releases = json_decode($releases);
if (!isset($releases[0])) {
throw new \Exception('API error - no release found at GitHub repository: ' . Constants::GITHUB_REPO);
}
$parsed = [];
foreach ($releases as $release) {
if ($release->draft || $release->prerelease) {
continue;
}
try {
$normalized = $versionParser->normalize($release->tag_name);
} catch (\UnexpectedValueException $e) {
continue;
}
if (VersionParser::parseStability($normalized) !== 'stable') {
continue;
}
$date = $release->published_at;
try {
$date = new \DateTimeImmutable($date);
} catch (\Exception $ex) {
// can be ignored, we return a string
}
$parsed[$normalized] = [
'version' => $release->tag_name,
'date' => $date,
'url' => $release->html_url,
'download' => $release->zipball_url,
'content' => $release->body,
];
}
$versions = Semver::rsort(array_keys($parsed));
$releases = [];
foreach ($versions as $version) {
$releases[$version] = $parsed[$version];
}
return $releases;
}
/**
* Returns an array with the keys:
* - version (string, tag name)
* - date (string, release date)
* - url (string, web address)
* - download (string, ZIP URL)
* - content (string, release notes)
*
* @param bool $compatible
* @return array{'version': string, 'date': \DateTimeInterface, 'url': string, 'download': string, 'content': string}|null
* @throws \Exception
*/
public function getLatestReleaseFromGithub(bool $compatible): ?array
{
foreach ($this->getReleasesFromGithub() as $release) {
$releaseVersion = $release['version'];
if ($compatible && !$this->satisfiesMajorVersionConstraint($releaseVersion)) {
continue;
}
return $release;
}
return null;
}
private function satisfiesMajorVersionConstraint(string $releaseVersion): bool
{
if (preg_match('/^v?(\d+)/', Constants::VERSION, $matches)) {
return Semver::satisfies($releaseVersion, '^' . $matches[1]);
}
return false;
}
}