Files
Atomcms-edit/app/Services/GitHubService.php
T
root 0bb35d6c8a 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
2026-05-19 21:07:16 +02:00

152 lines
4.5 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Process;
class GitHubService
{
public function parseUrl(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'];
}
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;
}
}