diff --git a/.env.development.example b/.env.development.example index 34236139eb..e892f92ba3 100644 --- a/.env.development.example +++ b/.env.development.example @@ -45,7 +45,3 @@ VITE_PORT=5173 DUSK_DRIVER_URL=http://selenium:4444 # Special Keys for Andras -# For cache purging -BUNNY_API_KEY= -# For asset uploads -BUNNY_STORAGE_API_KEY= diff --git a/app/Console/Commands/SyncBunny.php b/app/Console/Commands/SyncCdn.php similarity index 53% rename from app/Console/Commands/SyncBunny.php rename to app/Console/Commands/SyncCdn.php index 55acf38285..4f955f0d75 100644 --- a/app/Console/Commands/SyncBunny.php +++ b/app/Console/Commands/SyncCdn.php @@ -3,30 +3,27 @@ namespace App\Console\Commands; use Illuminate\Console\Command; -use Illuminate\Http\Client\PendingRequest; -use Illuminate\Http\Client\Pool; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Http; -use function Laravel\Prompts\confirm; use function Laravel\Prompts\multiselect; use function Laravel\Prompts\select; -class SyncBunny extends Command +class SyncCdn extends Command { /** * The name and signature of the console command. * * @var string */ - protected $signature = 'sync:bunny {--bunny}'; + protected $signature = 'sync:cdn'; /** * The console command description. * * @var string */ - protected $description = 'Sync files to BunnyCDN'; + protected $description = 'Sync CDN files to the coollabs-cdn GitHub repository'; protected function removeTemporaryDirectory(string $tmpDir): void { @@ -246,8 +243,6 @@ class SyncBunny extends Command */ public function handle() { - $that = $this; - $only_bunny = $this->option('bunny'); $nightly = select( label: 'Which environment would you like to sync?', options: [ @@ -256,9 +251,6 @@ class SyncBunny extends Command ], default: 'production', ) === 'nightly'; - $bunny_cdn = 'https://cdn.coollabs.io'; - $bunny_cdn_path = 'coolify'; - $bunny_cdn_storage_name = 'coolcdn'; $parent_dir = realpath(dirname(__FILE__).'/../../..'); @@ -280,34 +272,8 @@ class SyncBunny extends Command $service_template_location = "$parent_dir/templates/$service_template"; $versions_location = "$parent_dir/$versions"; - PendingRequest::macro('storage', function ($fileName) use ($that) { - $headers = [ - 'AccessKey' => config('constants.bunny.storage_api_key'), - 'Accept' => 'application/json', - 'Content-Type' => 'application/octet-stream', - ]; - $fileStream = fopen($fileName, 'r'); - $file = fread($fileStream, filesize($fileName)); - $that->info('Uploading: '.$fileName); - - return PendingRequest::baseUrl('https://storage.bunnycdn.com')->withHeaders($headers)->withBody($file)->throw(); - }); - PendingRequest::macro('purge', function ($url) use ($that) { - $headers = [ - 'AccessKey' => config('constants.bunny.api_key'), - 'Accept' => 'application/json', - ]; - $that->info('Purging: '.$url); - - return PendingRequest::withHeaders($headers)->get('https://api.bunny.net/purge', [ - 'url' => $url, - 'async' => false, - ]); - }); try { if ($nightly) { - $bunny_cdn_path = 'coolify-nightly'; - $compose_file_location = "$parent_dir/other/nightly/$compose_file"; $compose_file_prod_location = "$parent_dir/other/nightly/$compose_file_prod"; $production_env_location = "$parent_dir/other/nightly/$production_env"; @@ -316,150 +282,54 @@ class SyncBunny extends Command $install_script_location = "$parent_dir/other/nightly/$install_script"; $versions_location = "$parent_dir/other/nightly/$versions"; } - if ($only_bunny) { - $envLabel = $nightly ? 'NIGHTLY' : 'PRODUCTION'; - $this->info("About to sync $envLabel files to BunnyCDN."); - $this->newLine(); + $envLabel = $nightly ? 'NIGHTLY' : 'PRODUCTION'; + $this->info("About to sync $envLabel releases, versions, compose, and environment files to GitHub repository."); - // BunnyCDN file mapping (local file => CDN URL path) - $bunnyFileMapping = [ - $compose_file_location => "$bunny_cdn/$bunny_cdn_path/$compose_file", - $compose_file_prod_location => "$bunny_cdn/$bunny_cdn_path/$compose_file_prod", - $production_env_location => "$bunny_cdn/$bunny_cdn_path/$production_env", - $upgrade_script_location => "$bunny_cdn/$bunny_cdn_path/$upgrade_script", - $upgrade_postgres_script_location => "$bunny_cdn/$bunny_cdn_path/$upgrade_postgres_script", - $install_script_location => "$bunny_cdn/$bunny_cdn_path/$install_script", + if ($nightly) { + $files = [ + $versions_location => 'json/coolify/nightly/versions.json', + $compose_file_location => 'json/coolify/nightly/docker-compose.yml', + $compose_file_prod_location => 'json/coolify/nightly/docker-compose.prod.yml', + $production_env_location => 'json/coolify/nightly/.env.production', + $install_script_location => 'json/coolify/nightly/install.sh', + $upgrade_script_location => 'json/coolify/nightly/upgrade.sh', + $upgrade_postgres_script_location => 'json/coolify/nightly/upgrade-postgres.sh', + $service_template_location => 'json/coolify/nightly/service-templates-latest.json', + ]; + } else { + $files = [ + $versions_location => 'json/coolify/versions.json', + $compose_file_location => 'json/coolify/docker-compose.yml', + $compose_file_prod_location => 'json/coolify/docker-compose.prod.yml', + $production_env_location => 'json/coolify/.env.production', + $install_script_location => 'json/coolify/install.sh', + $upgrade_script_location => 'json/coolify/upgrade.sh', + $upgrade_postgres_script_location => 'json/coolify/upgrade-postgres.sh', + $service_template_location => 'json/coolify/service-templates-latest.json', ]; - - $diffTmpDir = sys_get_temp_dir().'/coollabs-cdn-diff-'.time(); - @mkdir($diffTmpDir, 0755, true); - $hasChanges = false; - - // Diff against BunnyCDN - $this->info('Fetching files from BunnyCDN to compare...'); - foreach ($bunnyFileMapping as $localFile => $cdnUrl) { - if (! file_exists($localFile)) { - $this->warn('Local file not found: '.$localFile); - - continue; - } - - $fileName = basename($cdnUrl); - $remoteTmp = "$diffTmpDir/bunny-$fileName"; - - try { - $response = Http::timeout(10)->get($cdnUrl); - if ($response->successful()) { - file_put_contents($remoteTmp, $response->body()); - $diffOutput = []; - exec('diff -u '.escapeshellarg($remoteTmp).' '.escapeshellarg($localFile).' 2>&1', $diffOutput, $diffCode); - if ($diffCode !== 0) { - $hasChanges = true; - $this->newLine(); - $this->info("--- BunnyCDN: $bunny_cdn_path/$fileName"); - $this->info("+++ Local: $fileName"); - foreach ($diffOutput as $line) { - if (str_starts_with($line, '---') || str_starts_with($line, '+++')) { - continue; - } - $this->line($line); - } - } - } else { - $this->info("NEW on BunnyCDN: $bunny_cdn_path/$fileName (HTTP {$response->status()})"); - $hasChanges = true; - } - } catch (\Throwable $e) { - $this->warn("Could not fetch $cdnUrl: {$e->getMessage()}"); - } - } - - $this->removeTemporaryDirectory($diffTmpDir); - - if (! $hasChanges) { - $this->newLine(); - $this->info('No differences found. All files are already up to date.'); - - return; - } - - $this->newLine(); - - $confirmed = confirm('Are you sure you want to sync?'); - if (! $confirmed) { - return; - } - } - if (! $only_bunny) { - $envLabel = $nightly ? 'NIGHTLY' : 'PRODUCTION'; - $this->info("About to sync $envLabel releases, versions, compose, and environment files to GitHub repository."); - - if ($nightly) { - $files = [ - $versions_location => 'json/coolify/nightly/versions.json', - $compose_file_location => 'json/coolify/nightly/docker-compose.yml', - $compose_file_prod_location => 'json/coolify/nightly/docker-compose.prod.yml', - $production_env_location => 'json/coolify/nightly/.env.production', - $install_script_location => 'json/coolify/nightly/install.sh', - $upgrade_script_location => 'json/coolify/nightly/upgrade.sh', - $upgrade_postgres_script_location => 'json/coolify/nightly/upgrade-postgres.sh', - $service_template_location => 'json/coolify/nightly/service-templates-latest.json', - ]; - } else { - $files = [ - $versions_location => 'json/coolify/versions.json', - $compose_file_location => 'json/coolify/docker-compose.yml', - $compose_file_prod_location => 'json/coolify/docker-compose.prod.yml', - $production_env_location => 'json/coolify/.env.production', - $install_script_location => 'json/coolify/install.sh', - $upgrade_script_location => 'json/coolify/upgrade.sh', - $upgrade_postgres_script_location => 'json/coolify/upgrade-postgres.sh', - $service_template_location => 'json/coolify/service-templates-latest.json', - ]; - } - - $releasesTarget = $nightly ? 'json/coolify/nightly/releases.json' : 'json/coolify/releases.json'; - $options = [$releasesTarget, ...array_values($files)]; - $selectedFiles = multiselect( - label: 'Which files would you like to sync?', - options: $options, - default: $options, - required: true, - scroll: count($options), - ); - - $includeReleases = in_array($releasesTarget, $selectedFiles, true); - $files = array_filter( - $files, - fn (string $targetPath) => in_array($targetPath, $selectedFiles, true), - ); - - if ($includeReleases) { - $this->syncReleasesToGitHubRepo($files, $nightly); - } else { - $this->syncFilesToGitHubRepo($files, $nightly); - } - - return; } - Http::pool(fn (Pool $pool) => [ - $pool->storage(fileName: "$compose_file_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file"), - $pool->storage(fileName: "$compose_file_prod_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$compose_file_prod"), - $pool->storage(fileName: "$production_env_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$production_env"), - $pool->storage(fileName: "$upgrade_script_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$upgrade_script"), - $pool->storage(fileName: "$upgrade_postgres_script_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$upgrade_postgres_script"), - $pool->storage(fileName: "$install_script_location")->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$install_script"), - ]); - Http::pool(fn (Pool $pool) => [ - $pool->purge("$bunny_cdn/$bunny_cdn_path/$compose_file"), - $pool->purge("$bunny_cdn/$bunny_cdn_path/$compose_file_prod"), - $pool->purge("$bunny_cdn/$bunny_cdn_path/$production_env"), - $pool->purge("$bunny_cdn/$bunny_cdn_path/$upgrade_script"), - $pool->purge("$bunny_cdn/$bunny_cdn_path/$upgrade_postgres_script"), - $pool->purge("$bunny_cdn/$bunny_cdn_path/$install_script"), - ]); - $this->info('All files uploaded & purged to BunnyCDN.'); + $releasesTarget = $nightly ? 'json/coolify/nightly/releases.json' : 'json/coolify/releases.json'; + $options = [$releasesTarget, ...array_values($files)]; + $selectedFiles = multiselect( + label: 'Which files would you like to sync?', + options: $options, + default: $options, + required: true, + scroll: count($options), + ); + + $includeReleases = in_array($releasesTarget, $selectedFiles, true); + $files = array_filter( + $files, + fn (string $targetPath) => in_array($targetPath, $selectedFiles, true), + ); + + if ($includeReleases) { + $this->syncReleasesToGitHubRepo($files, $nightly); + } else { + $this->syncFilesToGitHubRepo($files, $nightly); + } } catch (\Throwable $e) { $this->error('Error: '.$e->getMessage()); } diff --git a/config/constants.php b/config/constants.php index 865dbe4468..5d5d84c2d9 100644 --- a/config/constants.php +++ b/config/constants.php @@ -136,11 +136,6 @@ return [ 'dev_webhook' => env('SERVEO_URL'), ], - 'bunny' => [ - 'storage_api_key' => env('BUNNY_STORAGE_API_KEY'), - 'api_key' => env('BUNNY_API_KEY'), - ], - 'server_checks' => [ // Notification delay configuration for parallel server checks // Used for Traefik version checks and other future server check jobs diff --git a/scripts/run b/scripts/run index 701895c349..d605cfc574 100755 --- a/scripts/run +++ b/scripts/run @@ -27,8 +27,8 @@ function test { docker compose -f docker-compose.yml -f docker-compose.dev.yml exec -T coolify php artisan test --testsuite=Feature -p } -function sync:bunny { - php artisan sync:bunny --env=secrets +function sync:cdn { + php artisan sync:cdn --env=secrets } function db:reset { diff --git a/tests/Feature/SyncBunnyTest.php b/tests/Feature/SyncCdnTest.php similarity index 59% rename from tests/Feature/SyncBunnyTest.php rename to tests/Feature/SyncCdnTest.php index 9f4badad3d..395f1f08eb 100644 --- a/tests/Feature/SyncBunnyTest.php +++ b/tests/Feature/SyncCdnTest.php @@ -1,19 +1,19 @@ getDefinition(); +it('does not expose the removed sync options', function () { + $definition = Artisan::all()['sync:cdn']->getDefinition(); - expect($definition->hasOption('bunny'))->toBeTrue() + expect($definition->hasOption('bunny'))->toBeFalse() ->and($definition->hasOption('github-releases'))->toBeFalse() ->and($definition->hasOption('release'))->toBeFalse() ->and($definition->hasOption('nightly'))->toBeFalse() @@ -26,7 +26,7 @@ it('loads service templates from the Coollabs CDN', function () { }); it('only removes validated Coolify CDN temporary directories', function () { - $command = new class extends SyncBunny + $command = new class extends SyncCdn { public function removeDirectory(string $path): void { @@ -49,89 +49,28 @@ it('only removes validated Coolify CDN temporary directories', function () { rmdir($invalidDirectory); }); -it('syncs full files to BunnyCDN only when explicitly requested', function () { - Http::fake([ - 'https://cdn.coollabs.io/coolify/*' => Http::response('', 404), - 'https://storage.bunnycdn.com/*' => Http::response([], 201), - 'https://api.bunny.net/purge*' => Http::response([], 200), - ]); - - $binDir = sys_get_temp_dir().'/sync-bunny-bin-'.uniqid(); - $logFile = sys_get_temp_dir().'/sync-bunny-'.uniqid().'.log'; - - mkdir($binDir, 0755, true); - - createFakeSyncBunnyBinary($binDir, 'gh', <<<'SH' -#!/bin/sh -printf 'gh %s\n' "$*" >> "$SYNC_BUNNY_TEST_LOG" -if [ "$1" = "repo" ] && [ "$2" = "clone" ]; then - mkdir -p "$4/scripts" -fi -exit 0 -SH); - - createFakeSyncBunnyBinary($binDir, 'git', <<<'SH' -#!/bin/sh -printf 'git %s\n' "$*" >> "$SYNC_BUNNY_TEST_LOG" -if [ "$1" = "status" ]; then - printf 'M scripts/upgrade-postgres.sh\n' -fi -exit 0 -SH); - - $originalPath = getenv('PATH') ?: ''; - putenv("PATH={$binDir}:{$originalPath}"); - putenv("SYNC_BUNNY_TEST_LOG={$logFile}"); - - try { - $this->artisan('sync:bunny --bunny') - ->expectsChoice('Which environment would you like to sync?', 'production', [ - 'production' => 'Production', - 'nightly' => 'Nightly', - ]) - ->expectsConfirmation('Are you sure you want to sync?', 'yes') - ->assertExitCode(0); - } finally { - putenv("PATH={$originalPath}"); - putenv('SYNC_BUNNY_TEST_LOG'); - } - - $log = file_exists($logFile) ? file_get_contents($logFile) : ''; - - expect($log) - ->not->toContain('gh repo clone') - ->not->toContain('gh pr create') - ->not->toContain('coollabsio/coolify-cdn'); - - Http::assertSent(fn ($request) => $request->method() === 'PUT' - && $request->url() === 'https://storage.bunnycdn.com/coolcdn/coolify/upgrade-postgres.sh'); - - Http::assertSent(fn ($request) => str_starts_with($request->url(), 'https://api.bunny.net/purge') - && $request['url'] === 'https://cdn.coollabs.io/coolify/upgrade-postgres.sh'); -}); - it('selects the environment and release files to sync to GitHub', function (string $targetDirectory, string $environment, array $selectedBasenames) { Http::fake([ 'api.github.com/repos/coollabsio/coolify/releases*' => Http::response([], 200), ]); - $binDir = sys_get_temp_dir().'/sync-bunny-bin-'.uniqid(); - $logFile = sys_get_temp_dir().'/sync-bunny-'.uniqid().'.log'; + $binDir = sys_get_temp_dir().'/sync-cdn-bin-'.uniqid(); + $logFile = sys_get_temp_dir().'/sync-cdn-'.uniqid().'.log'; mkdir($binDir, 0755, true); - createFakeSyncBunnyBinary($binDir, 'gh', <<<'SH' + createFakeSyncCdnBinary($binDir, 'gh', <<<'SH' #!/bin/sh -printf 'gh %s\n' "$*" >> "$SYNC_BUNNY_TEST_LOG" +printf 'gh %s\n' "$*" >> "$SYNC_CDN_TEST_LOG" if [ "$1" = "repo" ] && [ "$2" = "clone" ]; then mkdir -p "$4" fi exit 0 SH); - createFakeSyncBunnyBinary($binDir, 'git', <<<'SH' + createFakeSyncCdnBinary($binDir, 'git', <<<'SH' #!/bin/sh -printf 'git %s\n' "$*" >> "$SYNC_BUNNY_TEST_LOG" +printf 'git %s\n' "$*" >> "$SYNC_CDN_TEST_LOG" if [ "$1" = "status" ]; then printf 'M json/releases.json\n' fi @@ -147,7 +86,7 @@ SH); $originalPath = getenv('PATH') ?: ''; putenv("PATH={$binDir}:{$originalPath}"); - putenv("SYNC_BUNNY_TEST_LOG={$logFile}"); + putenv("SYNC_CDN_TEST_LOG={$logFile}"); $allBasenames = [ 'releases.json', @@ -164,7 +103,7 @@ SH); $selectedTargets = array_map(fn (string $file) => "$targetDirectory/$file", $selectedBasenames); try { - $this->artisan('sync:bunny') + $this->artisan('sync:cdn') ->expectsChoice('Which environment would you like to sync?', $environment, [ 'production' => 'Production', 'nightly' => 'Nightly', @@ -173,7 +112,7 @@ SH); ->assertExitCode(0); } finally { putenv("PATH={$originalPath}"); - putenv('SYNC_BUNNY_TEST_LOG'); + putenv('SYNC_CDN_TEST_LOG'); } $log = file_get_contents($logFile);