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;
+ }
+}