From 0bb35d6c8a53aabfb7dda00bb55b03c6d2bad587 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 19 May 2026 21:07:16 +0200 Subject: [PATCH] refactor: centralize GitHub logic into GitHubService - Create GitHubService with parseUrl, extractRepo, getBranches, getLatestCommit, getLatestRelease, hasUpdates - Replace duplicated GitHub parsing in EmulatorConfiguration with GitHubService - Replace fetchGitHubBranches, extractGitHubRepo, getEmulatorRemoteVersion in Commandocentrum - Reduce code duplication across services and controllers --- .../Pages/Monitoring/Commandocentrum.php | 119 ++------------ .../Emulator/EmulatorConfiguration.php | 25 +-- app/Services/GitHubService.php | 151 ++++++++++++++++++ 3 files changed, 163 insertions(+), 132 deletions(-) create mode 100755 app/Services/GitHubService.php diff --git a/app/Filament/Pages/Monitoring/Commandocentrum.php b/app/Filament/Pages/Monitoring/Commandocentrum.php index 624b969..33a2fe8 100755 --- a/app/Filament/Pages/Monitoring/Commandocentrum.php +++ b/app/Filament/Pages/Monitoring/Commandocentrum.php @@ -13,6 +13,7 @@ use App\Services\AutoDetectService; use App\Services\CatalogService; use App\Services\Diagnostics\DiagnosticRunner; use App\Services\EmulatorUpdateService; +use App\Services\GitHubService; use App\Services\RconService; use App\Services\SettingsService; use App\Services\UpdateHistoryService; @@ -715,7 +716,7 @@ final class Commandocentrum extends Page implements HasForms $githubUrl = $this->getSetting('emulator_github_url', ''); $currentBranch = $this->data['emulator_github_branch'] ?? 'main'; - $branches = $this->fetchGitHubBranches($githubUrl); + $branches = app(GitHubService::class)->getBranches($githubUrl); $html = ''; foreach ($branches as $branch) { @@ -731,7 +732,7 @@ final class Commandocentrum extends Page implements HasForms $githubUrl = $this->getSetting('nitro_github_url', ''); $currentBranch = $this->data['nitro_github_branch'] ?? 'main'; - $branches = $this->fetchGitHubBranches($githubUrl); + $branches = app(GitHubService::class)->getBranches($githubUrl); $html = ''; foreach ($branches as $branch) { @@ -742,68 +743,6 @@ final class Commandocentrum extends Page implements HasForms return $html; } - private function fetchGitHubBranches(string $githubUrl): array - { - if ($githubUrl === '' || $githubUrl === '0' || ! str_contains($githubUrl, 'github.com')) { - return []; - } - - try { - $repo = $this->extractGitHubRepo($githubUrl); - $gitUrl = "https://github.com/{$repo}.git"; - - // Use git ls-remote to get all branches (doesn't hit rate limit) - $result = $this->runCommand('git ls-remote --heads ' . escapeshellarg($gitUrl) . ' 2>/dev/null', 30); - if ($result) { - $branches = []; - foreach (explode("\n", trim($result)) as $line) { - $parts = explode("\t", $line); - if (isset($parts[1]) && ($parts[1] !== '' && $parts[1] !== '0') && str_starts_with($parts[1], 'refs/heads/')) { - $branches[] = str_replace('refs/heads/', '', $parts[1]); - } - } - - return $branches; - } - - // Fallback to GitHub API - $response = Http::timeout(10)->get("https://api.github.com/repos/{$repo}/branches"); - if ($response->successful()) { - $data = $response->json(); - - return array_column($data, 'name'); - } - } catch (Exception) { - // Ignore - } - - return []; - } - - private function extractGitHubRepo(string $url): string - { - $url = trim($url, '/'); - - // Handle GitHub URLs with /tree/ or /blob/ - if (str_contains($url, 'github.com/')) { - $parts = explode('github.com/', $url); - if (isset($parts[1])) { - $path = trim($parts[1], '/'); - // Remove /tree/... or /blob/... - if (str_contains($path, '/tree/')) { - $path = explode('/tree/', $path)[0]; - } - if (str_contains($path, '/blob/')) { - $path = explode('/blob/', $path)[0]; - } - - return $path; - } - } - - return $url; - } - private function renderAlertForm(): HtmlString { return new HtmlString(<<<'HTML' @@ -941,7 +880,7 @@ final class Commandocentrum extends Page implements HasForms $jarExists = $this->fileExists($jarPath); $sourceCommit = $this->getGitCommit($sourcePath); - $remoteVersion = $githubUrl !== '' && $githubUrl !== '0' ? $this->getEmulatorRemoteVersion($githubUrl) : 'N/A'; + $remoteVersion = $githubUrl !== '' && $githubUrl !== '0' ? $this->getRemoteCommit($githubUrl, $this->getSetting('emulator_github_branch', 'main')) : 'N/A'; $canBuild = false; $pomPath = ''; @@ -1028,51 +967,11 @@ final class Commandocentrum extends Page implements HasForms } } - private function getEmulatorRemoteVersion(string $githubUrl): string + private function getRemoteCommit(string $githubUrl, string $branch = 'main'): string { - try { - if ($githubUrl === '' || $githubUrl === '0') { - return 'N/A'; - } + $commit = app(GitHubService::class)->getLatestCommit($githubUrl, $branch); - // Try to get latest commit using git ls-remote (doesn't hit rate limit) - $repo = $this->extractGitHubRepo($githubUrl); - // Use nitro branch if it's a nitro repo, otherwise use emulator branch - $isNitroRepo = str_contains($githubUrl, 'Nitro'); - $branch = $isNitroRepo - ? $this->getSetting('nitro_github_branch', 'main') - : $this->getSetting('emulator_github_branch', 'main'); - $gitUrl = "https://github.com/{$repo}.git"; - - $result = $this->runCommand('git ls-remote ' . escapeshellarg($gitUrl) . ' ' . escapeshellarg($branch) . ' 2>/dev/null', 30); - if ($result) { - $parts = explode("\t", trim($result)); - if ($parts[0] !== '' && $parts[0] !== '0') { - return substr($parts[0], 0, 7); - } - } - - // Fallback to GitHub API - $response = Http::timeout(10)->get("https://api.github.com/repos/{$repo}/releases/latest"); - if ($response->successful()) { - $data = $response->json(); - if (! empty($data['tag_name'])) { - return $data['tag_name']; - } - } - - $response = Http::timeout(10)->get("https://api.github.com/repos/{$repo}/commits?per_page=1"); - if ($response->successful()) { - $data = $response->json(); - if (! empty($data[0]['sha'])) { - return substr((string) $data[0]['sha'], 0, 7); - } - } - } catch (Exception) { - // Ignore - } - - return 'N/A'; + return $commit ?? 'N/A'; } private function renderNitroSettings(): HtmlString @@ -1153,8 +1052,8 @@ final class Commandocentrum extends Page implements HasForms $clientCommit = $this->getGitCommit($clientPath); $rendererCommit = $this->getGitCommit($rendererPath); - $clientRemote = $clientGithubUrl !== '' && $clientGithubUrl !== '0' ? $this->getEmulatorRemoteVersion($clientGithubUrl) : 'N/A'; - $rendererRemote = $rendererGithubUrl !== '' && $rendererGithubUrl !== '0' ? $this->getEmulatorRemoteVersion($rendererGithubUrl) : 'N/A'; + $clientRemote = $clientGithubUrl !== '' && $clientGithubUrl !== '0' ? $this->getRemoteCommit($clientGithubUrl, $this->getSetting('nitro_github_branch', 'main')) : 'N/A'; + $rendererRemote = $rendererGithubUrl !== '' && $rendererGithubUrl !== '0' ? $this->getRemoteCommit($rendererGithubUrl, $this->getSetting('nitro_renderer_github_branch', 'main')) : 'N/A'; // Compare only first 7 characters (short hash) $clientCommitShort = substr($clientCommit, 0, 7); diff --git a/app/Services/Emulator/EmulatorConfiguration.php b/app/Services/Emulator/EmulatorConfiguration.php index 6e6ad83..f3a72b6 100755 --- a/app/Services/Emulator/EmulatorConfiguration.php +++ b/app/Services/Emulator/EmulatorConfiguration.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Services\Emulator; +use App\Services\GitHubService; use App\Services\SettingsService; use Illuminate\Support\Facades\Process; @@ -134,38 +135,18 @@ trait EmulatorConfiguration private function parseGitHubUrl(string $url): void { - $parsed = $this->parseGithubRepoUrl($url); + $parsed = app(GitHubService::class)->parseUrl($url); $this->githubRepo = $parsed['repo']; $this->githubBranch = $parsed['branch']; } private function parseSourceRepo(string $url): void { - $parsed = $this->parseGithubRepoUrl($url); + $parsed = app(GitHubService::class)->parseUrl($url); $this->sourceRepo = $parsed['repo']; $this->sourceBranch = $parsed['branch']; } - private function parseGithubRepoUrl(string $url): array - { - if ($url === '' || $url === '0') { - return ['repo' => null, 'branch' => 'main']; - } - - if (preg_match('/github\.com\/([^\/]+)\/([^\/\?#]+)/', $url, $matches)) { - $repo = $matches[1] . '/' . $matches[2]; - $branch = 'main'; - - if (preg_match('/\/tree\/([^\/]+)/', $url, $branchMatch)) { - $branch = $branchMatch[1]; - } - - return ['repo' => $repo, 'branch' => $branch]; - } - - return ['repo' => null, 'branch' => 'main']; - } - protected function extractVersionFromFilename(string $filename): string { $filename = basename($filename, '.jar'); diff --git a/app/Services/GitHubService.php b/app/Services/GitHubService.php new file mode 100755 index 0000000..2892618 --- /dev/null +++ b/app/Services/GitHubService.php @@ -0,0 +1,151 @@ + null, 'branch' => 'main']; + } + + if (preg_match('/github\.com\/([^\/]+)\/([^\/\?#]+)/', $url, $matches)) { + $repo = $matches[1] . '/' . $matches[2]; + $branch = 'main'; + + if (preg_match('/\/tree\/([^\/]+)/', $url, $branchMatch)) { + $branch = $branchMatch[1]; + } + + return ['repo' => $repo, 'branch' => $branch]; + } + + return ['repo' => null, 'branch' => 'main']; + } + + public function extractRepo(string $url): string + { + $url = trim($url, '/'); + + if (str_contains($url, 'github.com/')) { + $parts = explode('github.com/', $url); + if (isset($parts[1])) { + $path = trim($parts[1], '/'); + $path = explode('/tree/', $path)[0]; + $path = explode('/blob/', $path)[0]; + + return $path; + } + } + + return $url; + } + + public function getBranches(string $githubUrl): array + { + if ($githubUrl === '' || $githubUrl === '0' || ! str_contains($githubUrl, 'github.com')) { + return []; + } + + try { + $repo = $this->extractRepo($githubUrl); + $gitUrl = "https://github.com/{$repo}.git"; + + $result = Process::timeout(30)->run('git ls-remote --heads ' . escapeshellarg($gitUrl) . ' 2>/dev/null'); + if ($result->successful() && trim($result->output())) { + $branches = []; + foreach (explode("\n", trim($result->output())) as $line) { + $parts = explode("\t", $line); + if (isset($parts[1]) && str_starts_with($parts[1], 'refs/heads/')) { + $branches[] = str_replace('refs/heads/', '', $parts[1]); + } + } + + return $branches; + } + + $response = Http::timeout(10)->get("https://api.github.com/repos/{$repo}/branches"); + if ($response->successful()) { + $data = $response->json(); + + return array_column($data, 'name'); + } + } catch (\Exception) { + // Ignore + } + + return []; + } + + public function getLatestCommit(string $githubUrl, string $branch = 'main'): ?string + { + if ($githubUrl === '' || $githubUrl === '0') { + return null; + } + + try { + $repo = $this->extractRepo($githubUrl); + $gitUrl = "https://github.com/{$repo}.git"; + + $result = Process::timeout(30)->run('git ls-remote ' . escapeshellarg($gitUrl) . ' ' . escapeshellarg($branch) . ' 2>/dev/null'); + if ($result->successful() && trim($result->output())) { + $parts = explode("\t", trim($result->output())); + if ($parts[0] !== '' && $parts[0] !== '0') { + return substr($parts[0], 0, 7); + } + } + + $response = Http::timeout(10)->get("https://api.github.com/repos/{$repo}/commits?per_page=1"); + if ($response->successful()) { + $data = $response->json(); + if (! empty($data[0]['sha'])) { + return substr($data[0]['sha'], 0, 7); + } + } + } catch (\Exception) { + // Ignore + } + + return null; + } + + public function getLatestRelease(string $githubUrl): ?string + { + if ($githubUrl === '' || $githubUrl === '0') { + return null; + } + + try { + $repo = $this->extractRepo($githubUrl); + + $response = Http::timeout(10)->get("https://api.github.com/repos/{$repo}/releases/latest"); + if ($response->successful()) { + $data = $response->json(); + if (! empty($data['tag_name'])) { + return $data['tag_name']; + } + } + } catch (\Exception) { + // Ignore + } + + return null; + } + + public function hasUpdates(string $githubUrl, string $localCommit, string $branch = 'main'): bool + { + $remoteCommit = $this->getLatestCommit($githubUrl, $branch); + + if ($remoteCommit === null || $localCommit === 'N/A') { + return false; + } + + return $localCommit !== $remoteCommit; + } +}