117 lines
3.6 KiB
PHP
117 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Versions;
|
|
|
|
use App\Models\Setting;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Attributes\Title;
|
|
use Livewire\Component;
|
|
|
|
/**
|
|
* Version & releases page. Everything shown here is real: the version comes from
|
|
* config, the build hash is read from .git at runtime, and the changelog is the
|
|
* project's own CHANGELOG.md. There is no in-app updater (Clusev ships as a Docker
|
|
* image) — the page states the actual update path instead of faking one.
|
|
*/
|
|
#[Layout('layouts.app')]
|
|
#[Title('Version — Clusev')]
|
|
class Index extends Component
|
|
{
|
|
public ?string $lastChecked = null;
|
|
|
|
/** Honest "check": there is no release server yet — report the real status. */
|
|
public function checkUpdates(): void
|
|
{
|
|
$this->lastChecked = now()->format('H:i');
|
|
|
|
$channel = Setting::get('release_channel', config('clusev.channel'));
|
|
$repository = config('clusev.repository');
|
|
|
|
$this->dispatch('notify', message: $repository
|
|
? 'Kanal: '.$channel.' — Quelle: '.$repository
|
|
: 'Entwicklungsversion — kein Release-Kanal konfiguriert.');
|
|
}
|
|
|
|
/** Resolve the current commit from .git without needing the git binary. */
|
|
private function build(): array
|
|
{
|
|
$root = base_path('.git');
|
|
$head = @file_get_contents($root.'/HEAD');
|
|
|
|
if ($head === false) {
|
|
return ['sha' => null, 'branch' => config('clusev.channel')];
|
|
}
|
|
|
|
$head = trim($head);
|
|
|
|
if (! str_starts_with($head, 'ref: ')) {
|
|
return ['sha' => substr($head, 0, 7), 'branch' => config('clusev.channel')];
|
|
}
|
|
|
|
$ref = substr($head, 5);
|
|
$branch = preg_replace('#^refs/heads/#', '', $ref);
|
|
$sha = @file_get_contents($root.'/'.$ref);
|
|
|
|
if ($sha === false) {
|
|
// packed-refs fallback
|
|
foreach (preg_split('/\R/', (string) @file_get_contents($root.'/packed-refs')) as $line) {
|
|
if (str_ends_with(trim($line), ' '.$ref)) {
|
|
$sha = explode(' ', trim($line))[0];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ['sha' => $sha ? substr(trim($sha), 0, 7) : null, 'branch' => $branch];
|
|
}
|
|
|
|
/**
|
|
* Parse CHANGELOG.md into dated groups for the timeline.
|
|
*
|
|
* @return array<int, array{date:string, items:array<int, array{type:string, text:string}>}>
|
|
*/
|
|
private function changelog(): array
|
|
{
|
|
$path = base_path('CHANGELOG.md');
|
|
if (! is_file($path)) {
|
|
return [];
|
|
}
|
|
|
|
$groups = [];
|
|
$date = null;
|
|
|
|
foreach (preg_split('/\R/', (string) file_get_contents($path)) as $line) {
|
|
if (preg_match('/^###\s+(.+)$/', $line, $m)) {
|
|
$date = trim($m[1]);
|
|
$groups[$date] = [];
|
|
|
|
continue;
|
|
}
|
|
if ($date !== null && preg_match('/^-\s*(\w+)\s*·\s*(.+)$/u', trim($line), $m)) {
|
|
$groups[$date][] = ['type' => strtolower($m[1]), 'text' => trim($m[2])];
|
|
}
|
|
}
|
|
|
|
$out = [];
|
|
foreach ($groups as $d => $items) {
|
|
if ($items !== []) {
|
|
$out[] = ['date' => $d, 'items' => $items];
|
|
}
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
public function render()
|
|
{
|
|
return view('livewire.versions.index', [
|
|
'version' => config('clusev.version'),
|
|
'channel' => Setting::get('release_channel', config('clusev.channel')),
|
|
'repository' => config('clusev.repository'),
|
|
'license' => config('clusev.license'),
|
|
'build' => $this->build(),
|
|
'groups' => $this->changelog(),
|
|
]);
|
|
}
|
|
}
|