clusev/app/Livewire/Versions/Index.php

110 lines
3.4 KiB
PHP

<?php
namespace App\Livewire\Versions;
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');
$this->dispatch('notify', message: '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' => config('clusev.channel'),
'repository' => config('clusev.repository'),
'license' => config('clusev.license'),
'build' => $this->build(),
'groups' => $this->changelog(),
]);
}
}