mirror of
https://github.com/coollabsio/coolify.git
synced 2026-06-13 19:09:50 +00:00
chore(sync-bunny): remove GitHub release sync paths
Drop the unused GitHub release and version sync options from sync:bunny, leaving the command focused on BunnyCDN template, release, and nightly syncs. Update the nightly test to assert it does not invoke gh or git.
This commit is contained in:
@@ -16,7 +16,7 @@ class SyncBunny extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'sync:bunny {--templates} {--release} {--github-releases} {--github-versions} {--nightly}';
|
||||
protected $signature = 'sync:bunny {--templates} {--release} {--nightly}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
@@ -25,651 +25,6 @@ class SyncBunny extends Command
|
||||
*/
|
||||
protected $description = 'Sync files to BunnyCDN';
|
||||
|
||||
/**
|
||||
* Fetch GitHub releases and sync to GitHub repository
|
||||
*/
|
||||
private function syncReleasesToGitHubRepo(): bool
|
||||
{
|
||||
$this->info('Fetching releases from GitHub...');
|
||||
try {
|
||||
$response = Http::timeout(30)
|
||||
->get('https://api.github.com/repos/coollabsio/coolify/releases', [
|
||||
'per_page' => 30, // Fetch more releases for better changelog
|
||||
]);
|
||||
|
||||
if (! $response->successful()) {
|
||||
$this->error('Failed to fetch releases from GitHub: '.$response->status());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$releases = $response->json();
|
||||
$timestamp = time();
|
||||
$tmpDir = sys_get_temp_dir().'/coolify-cdn-'.$timestamp;
|
||||
$branchName = 'update-releases-'.$timestamp;
|
||||
|
||||
// Clone the repository
|
||||
$this->info('Cloning coolify-cdn repository...');
|
||||
$output = [];
|
||||
exec('gh repo clone coollabsio/coolify-cdn '.escapeshellarg($tmpDir).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to clone repository: '.implode("\n", $output));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create feature branch
|
||||
$this->info('Creating feature branch...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git checkout -b '.escapeshellarg($branchName).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to create branch: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write releases.json
|
||||
$this->info('Writing releases.json...');
|
||||
$releasesPath = "$tmpDir/json/releases.json";
|
||||
$releasesDir = dirname($releasesPath);
|
||||
|
||||
// Ensure directory exists
|
||||
if (! is_dir($releasesDir)) {
|
||||
$this->info("Creating directory: $releasesDir");
|
||||
if (! mkdir($releasesDir, 0755, true)) {
|
||||
$this->error("Failed to create directory: $releasesDir");
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$jsonContent = json_encode($releases, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
$bytesWritten = file_put_contents($releasesPath, $jsonContent);
|
||||
|
||||
if ($bytesWritten === false) {
|
||||
$this->error("Failed to write releases.json to: $releasesPath");
|
||||
$this->error('Possible reasons: permission denied or disk full.');
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stage and commit
|
||||
$this->info('Committing changes...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git add json/releases.json 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to stage changes: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->info('Checking for changes...');
|
||||
$statusOutput = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git status --porcelain json/releases.json 2>&1', $statusOutput, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to check repository status: '.implode("\n", $statusOutput));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty(array_filter($statusOutput))) {
|
||||
$this->info('Releases are already up to date. No changes to commit.');
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$commitMessage = 'Update releases.json with latest releases - '.date('Y-m-d H:i:s');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git commit -m '.escapeshellarg($commitMessage).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to commit changes: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Push to remote
|
||||
$this->info('Pushing branch to remote...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git push origin '.escapeshellarg($branchName).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to push branch: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create pull request
|
||||
$this->info('Creating pull request...');
|
||||
$prTitle = 'Update releases.json - '.date('Y-m-d H:i:s');
|
||||
$prBody = 'Automated update of releases.json with latest '.count($releases).' releases from GitHub API';
|
||||
$prCommand = 'gh pr create --repo coollabsio/coolify-cdn --title '.escapeshellarg($prTitle).' --body '.escapeshellarg($prBody).' --base main --head '.escapeshellarg($branchName).' 2>&1';
|
||||
$output = [];
|
||||
exec($prCommand, $output, $returnCode);
|
||||
|
||||
// Clean up
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to create PR: '.implode("\n", $output));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->info('Pull request created successfully!');
|
||||
if (! empty($output)) {
|
||||
$this->info('PR Output: '.implode("\n", $output));
|
||||
}
|
||||
$this->info('Total releases synced: '.count($releases));
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
$this->error('Error syncing releases: '.$e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync both releases.json and versions.json to GitHub repository in one PR
|
||||
*/
|
||||
private function syncReleasesAndVersionsToGitHubRepo(string $versionsLocation, bool $nightly = false): bool
|
||||
{
|
||||
$this->info('Syncing releases.json and versions.json to GitHub repository...');
|
||||
try {
|
||||
// 1. Fetch releases from GitHub API
|
||||
$this->info('Fetching releases from GitHub API...');
|
||||
$response = Http::timeout(30)
|
||||
->get('https://api.github.com/repos/coollabsio/coolify/releases', [
|
||||
'per_page' => 30,
|
||||
]);
|
||||
|
||||
if (! $response->successful()) {
|
||||
$this->error('Failed to fetch releases from GitHub: '.$response->status());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$releases = $response->json();
|
||||
|
||||
// 2. Read versions.json
|
||||
if (! file_exists($versionsLocation)) {
|
||||
$this->error("versions.json not found at: $versionsLocation");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$file = file_get_contents($versionsLocation);
|
||||
$versionsJson = json_decode($file, true);
|
||||
$actualVersion = data_get($versionsJson, 'coolify.v4.version');
|
||||
|
||||
$timestamp = time();
|
||||
$tmpDir = sys_get_temp_dir().'/coolify-cdn-combined-'.$timestamp;
|
||||
$branchName = 'update-releases-and-versions-'.$timestamp;
|
||||
$versionsTargetPath = $nightly ? 'json/nightly/versions.json' : 'json/versions.json';
|
||||
$releasesTargetPath = $nightly ? 'json/nightly/releases.json' : 'json/releases.json';
|
||||
|
||||
// 3. Clone the repository
|
||||
$this->info('Cloning coolify-cdn repository...');
|
||||
$output = [];
|
||||
exec('gh repo clone coollabsio/coolify-cdn '.escapeshellarg($tmpDir).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to clone repository: '.implode("\n", $output));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. Create feature branch
|
||||
$this->info('Creating feature branch...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git checkout -b '.escapeshellarg($branchName).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to create branch: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5. Write releases.json
|
||||
$this->info('Writing releases.json...');
|
||||
$releasesPath = "$tmpDir/$releasesTargetPath";
|
||||
$releasesDir = dirname($releasesPath);
|
||||
|
||||
if (! is_dir($releasesDir)) {
|
||||
if (! mkdir($releasesDir, 0755, true)) {
|
||||
$this->error("Failed to create directory: $releasesDir");
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$releasesJsonContent = json_encode($releases, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
if (file_put_contents($releasesPath, $releasesJsonContent) === false) {
|
||||
$this->error("Failed to write releases.json to: $releasesPath");
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 6. Write versions.json
|
||||
$this->info('Writing versions.json...');
|
||||
$versionsPath = "$tmpDir/$versionsTargetPath";
|
||||
$versionsDir = dirname($versionsPath);
|
||||
|
||||
if (! is_dir($versionsDir)) {
|
||||
if (! mkdir($versionsDir, 0755, true)) {
|
||||
$this->error("Failed to create directory: $versionsDir");
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$versionsJsonContent = json_encode($versionsJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
if (file_put_contents($versionsPath, $versionsJsonContent) === false) {
|
||||
$this->error("Failed to write versions.json to: $versionsPath");
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 7. Stage both files
|
||||
$this->info('Staging changes...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git add '.escapeshellarg($releasesTargetPath).' '.escapeshellarg($versionsTargetPath).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to stage changes: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 8. Check for changes
|
||||
$this->info('Checking for changes...');
|
||||
$statusOutput = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git status --porcelain 2>&1', $statusOutput, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to check repository status: '.implode("\n", $statusOutput));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty(array_filter($statusOutput))) {
|
||||
$this->info('Both files are already up to date. No changes to commit.');
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 9. Commit changes
|
||||
$envLabel = $nightly ? 'NIGHTLY' : 'PRODUCTION';
|
||||
$commitMessage = "Update releases.json and $envLabel versions.json to $actualVersion - ".date('Y-m-d H:i:s');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git commit -m '.escapeshellarg($commitMessage).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to commit changes: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 10. Push to remote
|
||||
$this->info('Pushing branch to remote...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git push origin '.escapeshellarg($branchName).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to push branch: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 11. Create pull request
|
||||
$this->info('Creating pull request...');
|
||||
$prTitle = "Update releases.json and $envLabel versions.json to $actualVersion - ".date('Y-m-d H:i:s');
|
||||
$prBody = "Automated update:\n- releases.json with latest ".count($releases)." releases from GitHub API\n- $envLabel versions.json to version $actualVersion";
|
||||
$prCommand = 'gh pr create --repo coollabsio/coolify-cdn --title '.escapeshellarg($prTitle).' --body '.escapeshellarg($prBody).' --base main --head '.escapeshellarg($branchName).' 2>&1';
|
||||
$output = [];
|
||||
exec($prCommand, $output, $returnCode);
|
||||
|
||||
// 12. Clean up
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to create PR: '.implode("\n", $output));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->info('Pull request created successfully!');
|
||||
if (! empty($output)) {
|
||||
$this->info('PR URL: '.implode("\n", $output));
|
||||
}
|
||||
$this->info("Version synced: $actualVersion");
|
||||
$this->info('Total releases synced: '.count($releases));
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
$this->error('Error syncing to GitHub: '.$e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync install.sh, docker-compose, and env files to GitHub repository via PR
|
||||
*/
|
||||
private function syncFilesToGitHubRepo(array $files, bool $nightly = false): bool
|
||||
{
|
||||
$envLabel = $nightly ? 'NIGHTLY' : 'PRODUCTION';
|
||||
$this->info("Syncing $envLabel files to GitHub repository...");
|
||||
try {
|
||||
$timestamp = time();
|
||||
$tmpDir = sys_get_temp_dir().'/coolify-cdn-files-'.$timestamp;
|
||||
$branchName = 'update-files-'.$timestamp;
|
||||
|
||||
// Clone the repository
|
||||
$this->info('Cloning coolify-cdn repository...');
|
||||
$output = [];
|
||||
exec('gh repo clone coollabsio/coolify-cdn '.escapeshellarg($tmpDir).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to clone repository: '.implode("\n", $output));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create feature branch
|
||||
$this->info('Creating feature branch...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git checkout -b '.escapeshellarg($branchName).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to create branch: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy each file to its target path in the CDN repo
|
||||
$copiedFiles = [];
|
||||
foreach ($files as $sourceFile => $targetPath) {
|
||||
if (! file_exists($sourceFile)) {
|
||||
$this->warn("Source file not found, skipping: $sourceFile");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$destPath = "$tmpDir/$targetPath";
|
||||
$destDir = dirname($destPath);
|
||||
|
||||
if (! is_dir($destDir)) {
|
||||
if (! mkdir($destDir, 0755, true)) {
|
||||
$this->error("Failed to create directory: $destDir");
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (copy($sourceFile, $destPath) === false) {
|
||||
$this->error("Failed to copy $sourceFile to $destPath");
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$copiedFiles[] = $targetPath;
|
||||
$this->info("Copied: $targetPath");
|
||||
}
|
||||
|
||||
if (empty($copiedFiles)) {
|
||||
$this->warn('No files were copied. Nothing to commit.');
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stage all copied files
|
||||
$this->info('Staging changes...');
|
||||
$output = [];
|
||||
$stageCmd = 'cd '.escapeshellarg($tmpDir).' && git add '.implode(' ', array_map('escapeshellarg', $copiedFiles)).' 2>&1';
|
||||
exec($stageCmd, $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to stage changes: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for changes
|
||||
$this->info('Checking for changes...');
|
||||
$statusOutput = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git status --porcelain 2>&1', $statusOutput, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to check repository status: '.implode("\n", $statusOutput));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty(array_filter($statusOutput))) {
|
||||
$this->info('All files are already up to date. No changes to commit.');
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Commit changes
|
||||
$commitMessage = "Update $envLabel files (install.sh, docker-compose, env) - ".date('Y-m-d H:i:s');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git commit -m '.escapeshellarg($commitMessage).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to commit changes: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Push to remote
|
||||
$this->info('Pushing branch to remote...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git push origin '.escapeshellarg($branchName).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to push branch: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create pull request
|
||||
$this->info('Creating pull request...');
|
||||
$prTitle = "Update $envLabel files - ".date('Y-m-d H:i:s');
|
||||
$fileList = implode("\n- ", $copiedFiles);
|
||||
$prBody = "Automated update of $envLabel files:\n- $fileList";
|
||||
$prCommand = 'gh pr create --repo coollabsio/coolify-cdn --title '.escapeshellarg($prTitle).' --body '.escapeshellarg($prBody).' --base main --head '.escapeshellarg($branchName).' 2>&1';
|
||||
$output = [];
|
||||
exec($prCommand, $output, $returnCode);
|
||||
|
||||
// Clean up
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to create PR: '.implode("\n", $output));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->info('Pull request created successfully!');
|
||||
if (! empty($output)) {
|
||||
$this->info('PR URL: '.implode("\n", $output));
|
||||
}
|
||||
$this->info('Files synced: '.count($copiedFiles));
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
$this->error('Error syncing files to GitHub: '.$e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync versions.json to GitHub repository via PR
|
||||
*/
|
||||
private function syncVersionsToGitHubRepo(string $versionsLocation, bool $nightly = false): bool
|
||||
{
|
||||
$this->info('Syncing versions.json to GitHub repository...');
|
||||
try {
|
||||
if (! file_exists($versionsLocation)) {
|
||||
$this->error("versions.json not found at: $versionsLocation");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$file = file_get_contents($versionsLocation);
|
||||
$json = json_decode($file, true);
|
||||
$actualVersion = data_get($json, 'coolify.v4.version');
|
||||
|
||||
$timestamp = time();
|
||||
$tmpDir = sys_get_temp_dir().'/coolify-cdn-versions-'.$timestamp;
|
||||
$branchName = 'update-versions-'.$timestamp;
|
||||
$targetPath = $nightly ? 'json/nightly/versions.json' : 'json/versions.json';
|
||||
|
||||
// Clone the repository
|
||||
$this->info('Cloning coolify-cdn repository...');
|
||||
exec('gh repo clone coollabsio/coolify-cdn '.escapeshellarg($tmpDir).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to clone repository: '.implode("\n", $output));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create feature branch
|
||||
$this->info('Creating feature branch...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git checkout -b '.escapeshellarg($branchName).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to create branch: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write versions.json
|
||||
$this->info('Writing versions.json...');
|
||||
$versionsPath = "$tmpDir/$targetPath";
|
||||
$versionsDir = dirname($versionsPath);
|
||||
|
||||
// Ensure directory exists
|
||||
if (! is_dir($versionsDir)) {
|
||||
$this->info("Creating directory: $versionsDir");
|
||||
if (! mkdir($versionsDir, 0755, true)) {
|
||||
$this->error("Failed to create directory: $versionsDir");
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$jsonContent = json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||
$bytesWritten = file_put_contents($versionsPath, $jsonContent);
|
||||
|
||||
if ($bytesWritten === false) {
|
||||
$this->error("Failed to write versions.json to: $versionsPath");
|
||||
$this->error('Possible reasons: permission denied or disk full.');
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stage and commit
|
||||
$this->info('Committing changes...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git add '.escapeshellarg($targetPath).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to stage changes: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->info('Checking for changes...');
|
||||
$statusOutput = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git status --porcelain '.escapeshellarg($targetPath).' 2>&1', $statusOutput, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to check repository status: '.implode("\n", $statusOutput));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty(array_filter($statusOutput))) {
|
||||
$this->info('versions.json is already up to date. No changes to commit.');
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$envLabel = $nightly ? 'NIGHTLY' : 'PRODUCTION';
|
||||
$commitMessage = "Update $envLabel versions.json to $actualVersion - ".date('Y-m-d H:i:s');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git commit -m '.escapeshellarg($commitMessage).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to commit changes: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Push to remote
|
||||
$this->info('Pushing branch to remote...');
|
||||
$output = [];
|
||||
exec('cd '.escapeshellarg($tmpDir).' && git push origin '.escapeshellarg($branchName).' 2>&1', $output, $returnCode);
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to push branch: '.implode("\n", $output));
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create pull request
|
||||
$this->info('Creating pull request...');
|
||||
$prTitle = "Update $envLabel versions.json to $actualVersion - ".date('Y-m-d H:i:s');
|
||||
$prBody = "Automated update of $envLabel versions.json to version $actualVersion";
|
||||
$output = [];
|
||||
$prCommand = 'gh pr create --repo coollabsio/coolify-cdn --title '.escapeshellarg($prTitle).' --body '.escapeshellarg($prBody).' --base main --head '.escapeshellarg($branchName).' 2>&1';
|
||||
exec($prCommand, $output, $returnCode);
|
||||
|
||||
// Clean up
|
||||
exec('rm -rf '.escapeshellarg($tmpDir));
|
||||
|
||||
if ($returnCode !== 0) {
|
||||
$this->error('Failed to create PR: '.implode("\n", $output));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->info('Pull request created successfully!');
|
||||
if (! empty($output)) {
|
||||
$this->info('PR URL: '.implode("\n", $output));
|
||||
}
|
||||
$this->info("Version synced: $actualVersion");
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
$this->error('Error syncing versions.json: '.$e->getMessage());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
@@ -678,8 +33,6 @@ class SyncBunny extends Command
|
||||
$that = $this;
|
||||
$only_template = $this->option('templates');
|
||||
$only_version = $this->option('release');
|
||||
$only_github_releases = $this->option('github-releases');
|
||||
$only_github_versions = $this->option('github-versions');
|
||||
$nightly = $this->option('nightly');
|
||||
$bunny_cdn = 'https://cdn.coollabs.io';
|
||||
$bunny_cdn_path = 'coolify';
|
||||
@@ -737,30 +90,11 @@ class SyncBunny extends Command
|
||||
$install_script_location = "$parent_dir/other/nightly/$install_script";
|
||||
$versions_location = "$parent_dir/other/nightly/$versions";
|
||||
}
|
||||
if (! $only_template && ! $only_version && ! $only_github_releases && ! $only_github_versions) {
|
||||
if (! $only_template && ! $only_version) {
|
||||
$envLabel = $nightly ? 'NIGHTLY' : 'PRODUCTION';
|
||||
$this->info("About to sync $envLabel files to BunnyCDN and create a GitHub PR for coolify-cdn.");
|
||||
$this->info("About to sync $envLabel files to BunnyCDN.");
|
||||
$this->newLine();
|
||||
|
||||
// Build file mapping for diff
|
||||
if ($nightly) {
|
||||
$fileMapping = [
|
||||
$compose_file_location => 'docker/nightly/docker-compose.yml',
|
||||
$compose_file_prod_location => 'docker/nightly/docker-compose.prod.yml',
|
||||
$production_env_location => 'environment/nightly/.env.production',
|
||||
$upgrade_script_location => 'scripts/nightly/upgrade.sh',
|
||||
$install_script_location => 'scripts/nightly/install.sh',
|
||||
];
|
||||
} else {
|
||||
$fileMapping = [
|
||||
$compose_file_location => 'docker/docker-compose.yml',
|
||||
$compose_file_prod_location => 'docker/docker-compose.prod.yml',
|
||||
$production_env_location => 'environment/.env.production',
|
||||
$upgrade_script_location => 'scripts/upgrade.sh',
|
||||
$install_script_location => 'scripts/install.sh',
|
||||
];
|
||||
}
|
||||
|
||||
// BunnyCDN file mapping (local file => CDN URL path)
|
||||
$bunnyFileMapping = [
|
||||
$compose_file_location => "$bunny_cdn/$bunny_cdn_path/$compose_file",
|
||||
@@ -813,44 +147,6 @@ class SyncBunny extends Command
|
||||
}
|
||||
}
|
||||
|
||||
// Diff against GitHub coolify-cdn repo
|
||||
$this->newLine();
|
||||
$this->info('Fetching coolify-cdn repo to compare...');
|
||||
$output = [];
|
||||
exec('gh repo clone coollabsio/coolify-cdn '.escapeshellarg("$diffTmpDir/repo").' -- --depth 1 2>&1', $output, $returnCode);
|
||||
|
||||
if ($returnCode === 0) {
|
||||
foreach ($fileMapping as $localFile => $cdnPath) {
|
||||
$remotePath = "$diffTmpDir/repo/$cdnPath";
|
||||
if (! file_exists($localFile)) {
|
||||
continue;
|
||||
}
|
||||
if (! file_exists($remotePath)) {
|
||||
$this->info("NEW on GitHub: $cdnPath (does not exist in coolify-cdn yet)");
|
||||
$hasChanges = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$diffOutput = [];
|
||||
exec('diff -u '.escapeshellarg($remotePath).' '.escapeshellarg($localFile).' 2>&1', $diffOutput, $diffCode);
|
||||
if ($diffCode !== 0) {
|
||||
$hasChanges = true;
|
||||
$this->newLine();
|
||||
$this->info("--- GitHub: $cdnPath");
|
||||
$this->info("+++ Local: $cdnPath");
|
||||
foreach ($diffOutput as $line) {
|
||||
if (str_starts_with($line, '---') || str_starts_with($line, '+++')) {
|
||||
continue;
|
||||
}
|
||||
$this->line($line);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$this->warn('Could not fetch coolify-cdn repo for diff.');
|
||||
}
|
||||
|
||||
exec('rm -rf '.escapeshellarg($diffTmpDir));
|
||||
|
||||
if (! $hasChanges) {
|
||||
@@ -882,9 +178,9 @@ class SyncBunny extends Command
|
||||
return;
|
||||
} elseif ($only_version) {
|
||||
if ($nightly) {
|
||||
$this->info('About to sync NIGHTLY versions.json to BunnyCDN and create GitHub PR.');
|
||||
$this->info('About to sync NIGHTLY versions.json to BunnyCDN.');
|
||||
} else {
|
||||
$this->info('About to sync PRODUCTION versions.json to BunnyCDN and create GitHub PR.');
|
||||
$this->info('About to sync PRODUCTION versions.json to BunnyCDN.');
|
||||
}
|
||||
$file = file_get_contents($versions_location);
|
||||
$json = json_decode($file, true);
|
||||
@@ -892,8 +188,7 @@ class SyncBunny extends Command
|
||||
|
||||
$this->info("Version: {$actual_version}");
|
||||
$this->info('This will:');
|
||||
$this->info(' 1. Sync versions.json to BunnyCDN (deprecated but still supported)');
|
||||
$this->info(' 2. Create ONE GitHub PR with both releases.json and versions.json');
|
||||
$this->info(' 1. Sync versions.json to BunnyCDN');
|
||||
$this->newLine();
|
||||
|
||||
$confirmed = confirm('Are you sure you want to proceed?');
|
||||
@@ -901,8 +196,7 @@ class SyncBunny extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Sync versions.json to BunnyCDN (deprecated but still needed)
|
||||
$this->info('Step 1/2: Syncing versions.json to BunnyCDN...');
|
||||
$this->info('Syncing versions.json to BunnyCDN...');
|
||||
Http::pool(fn (Pool $pool) => [
|
||||
$pool->storage(fileName: $versions_location)->put("/$bunny_cdn_storage_name/$bunny_cdn_path/$versions"),
|
||||
$pool->purge("$bunny_cdn/$bunny_cdn_path/$versions"),
|
||||
@@ -910,46 +204,8 @@ class SyncBunny extends Command
|
||||
$this->info('✓ versions.json uploaded & purged to BunnyCDN');
|
||||
$this->newLine();
|
||||
|
||||
// 2. Create GitHub PR with both releases.json and versions.json
|
||||
$this->info('Step 2/2: Creating GitHub PR with releases.json and versions.json...');
|
||||
$githubSuccess = $this->syncReleasesAndVersionsToGitHubRepo($versions_location, $nightly);
|
||||
if ($githubSuccess) {
|
||||
$this->info('✓ GitHub PR created successfully with both files');
|
||||
} else {
|
||||
$this->error('✗ Failed to create GitHub PR');
|
||||
}
|
||||
$this->newLine();
|
||||
|
||||
$this->info('=== Summary ===');
|
||||
$this->info('BunnyCDN sync: ✓ Complete');
|
||||
$this->info('GitHub PR: '.($githubSuccess ? '✓ Created (releases.json + versions.json)' : '✗ Failed'));
|
||||
|
||||
return;
|
||||
} elseif ($only_github_releases) {
|
||||
$this->info('About to sync GitHub releases to GitHub repository.');
|
||||
$confirmed = confirm('Are you sure you want to sync GitHub releases?');
|
||||
if (! $confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync releases to GitHub repository
|
||||
$this->syncReleasesToGitHubRepo();
|
||||
|
||||
return;
|
||||
} elseif ($only_github_versions) {
|
||||
$envLabel = $nightly ? 'NIGHTLY' : 'PRODUCTION';
|
||||
$file = file_get_contents($versions_location);
|
||||
$json = json_decode($file, true);
|
||||
$actual_version = data_get($json, 'coolify.v4.version');
|
||||
|
||||
$this->info("About to sync $envLabel versions.json ($actual_version) to GitHub repository.");
|
||||
$confirmed = confirm('Are you sure you want to sync versions.json via GitHub PR?');
|
||||
if (! $confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync versions.json to GitHub repository
|
||||
$this->syncVersionsToGitHubRepo($versions_location, $nightly);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -971,31 +227,8 @@ class SyncBunny extends Command
|
||||
$this->info('All files uploaded & purged to BunnyCDN.');
|
||||
$this->newLine();
|
||||
|
||||
// Sync files to GitHub CDN repository via PR
|
||||
$this->info('Creating GitHub PR for coolify-cdn repository...');
|
||||
if ($nightly) {
|
||||
$files = [
|
||||
$compose_file_location => 'docker/nightly/docker-compose.yml',
|
||||
$compose_file_prod_location => 'docker/nightly/docker-compose.prod.yml',
|
||||
$production_env_location => 'environment/nightly/.env.production',
|
||||
$upgrade_script_location => 'scripts/nightly/upgrade.sh',
|
||||
$install_script_location => 'scripts/nightly/install.sh',
|
||||
];
|
||||
} else {
|
||||
$files = [
|
||||
$compose_file_location => 'docker/docker-compose.yml',
|
||||
$compose_file_prod_location => 'docker/docker-compose.prod.yml',
|
||||
$production_env_location => 'environment/.env.production',
|
||||
$upgrade_script_location => 'scripts/upgrade.sh',
|
||||
$install_script_location => 'scripts/install.sh',
|
||||
];
|
||||
}
|
||||
|
||||
$githubSuccess = $this->syncFilesToGitHubRepo($files, $nightly);
|
||||
$this->newLine();
|
||||
$this->info('=== Summary ===');
|
||||
$this->info('BunnyCDN sync: Complete');
|
||||
$this->info('GitHub PR: '.($githubSuccess ? 'Created' : 'Failed'));
|
||||
} catch (\Throwable $e) {
|
||||
$this->error('Error: '.$e->getMessage());
|
||||
}
|
||||
|
||||
@@ -2,67 +2,47 @@
|
||||
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
function createFakeSyncBunnyBinary(string $binDir, string $name, string $contents): void
|
||||
function createSyncBunnyFailingBinary(string $binDir, string $name): void
|
||||
{
|
||||
file_put_contents("{$binDir}/{$name}", $contents);
|
||||
file_put_contents("{$binDir}/{$name}", <<<'SH'
|
||||
#!/bin/sh
|
||||
printf '%s %s\n' "$(basename "$0")" "$*" >> "$SYNC_BUNNY_TEST_LOG"
|
||||
exit 1
|
||||
SH);
|
||||
chmod("{$binDir}/{$name}", 0755);
|
||||
}
|
||||
|
||||
it('syncs nightly files to the nested nightly json path in the cdn repository', function (string $option, string $confirmation, bool $syncsReleases) {
|
||||
it('syncs nightly versions to BunnyCDN without creating a GitHub PR', function () {
|
||||
Http::fake([
|
||||
'api.github.com/repos/coollabsio/coolify/releases*' => Http::response([], 200),
|
||||
'storage.bunnycdn.com/*' => Http::response([], 201),
|
||||
'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/json/nightly"
|
||||
printf '{}' > "$4/json/releases.json"
|
||||
printf '{}' > "$4/json/nightly/versions.json"
|
||||
fi
|
||||
exit 0
|
||||
SH);
|
||||
|
||||
createFakeSyncBunnyBinary($binDir, 'git', <<<'SH'
|
||||
#!/bin/sh
|
||||
printf 'git %s\n' "$*" >> "$SYNC_BUNNY_TEST_LOG"
|
||||
if [ "$1" = "status" ]; then
|
||||
printf 'M %s\n' "$3"
|
||||
fi
|
||||
exit 0
|
||||
SH);
|
||||
createSyncBunnyFailingBinary($binDir, 'gh');
|
||||
createSyncBunnyFailingBinary($binDir, 'git');
|
||||
|
||||
$originalPath = getenv('PATH') ?: '';
|
||||
putenv("PATH={$binDir}:{$originalPath}");
|
||||
putenv("SYNC_BUNNY_TEST_LOG={$logFile}");
|
||||
|
||||
try {
|
||||
$this->artisan("sync:bunny {$option} --nightly")
|
||||
->expectsConfirmation($confirmation, 'yes')
|
||||
$this->artisan('sync:bunny --release --nightly')
|
||||
->expectsConfirmation('Are you sure you want to proceed?', 'yes')
|
||||
->expectsOutputToContain('BunnyCDN sync: ✓ Complete')
|
||||
->doesntExpectOutputToContain('GitHub PR')
|
||||
->assertExitCode(0);
|
||||
} finally {
|
||||
putenv("PATH={$originalPath}");
|
||||
putenv('SYNC_BUNNY_TEST_LOG');
|
||||
}
|
||||
|
||||
$log = file_get_contents($logFile);
|
||||
expect(file_exists($logFile))->toBeFalse();
|
||||
|
||||
expect($log)
|
||||
->toContain('json/nightly/versions.json')
|
||||
->not->toContain('json/versions-nightly.json');
|
||||
|
||||
if ($syncsReleases) {
|
||||
expect($log)
|
||||
->toContain('json/nightly/releases.json')
|
||||
->not->toContain('git add json/releases.json');
|
||||
}
|
||||
})->with([
|
||||
'release sync with releases' => ['--release', 'Are you sure you want to proceed?', true],
|
||||
'versions-only github sync' => ['--github-versions', 'Are you sure you want to sync versions.json via GitHub PR?', false],
|
||||
]);
|
||||
Http::assertSent(fn ($request) => $request->url() === 'https://storage.bunnycdn.com/coolcdn/coolify-nightly/versions.json');
|
||||
Http::assertSent(fn ($request) => str_starts_with($request->url(), 'https://api.bunny.net/purge')
|
||||
&& $request['url'] === 'https://cdn.coollabs.io/coolify-nightly/versions.json');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user