Files
coolify/app/Actions/Application/CleanupOldDeployments.php
Andras BacsaiandClaude Opus 4.5 885fb20445 Implement versioned deployment snapshots for improved rollback
- Add SaveDeploymentSnapshot action to save docker-compose.yaml, .env,
  and metadata.json to versioned deployment directories
- Add CleanupOldDeployments action to enforce retention policy (last 5)
- Add helper functions for deployment directory paths
- Modify ApplicationDeploymentJob to save snapshots after deployment
- Rewrite Rollback component to show deployment history
- Support instant rollback (when image exists) and rebuild rollback

New directory structure on server:
/data/coolify/applications/{uuid}/deployments/{deployment_uuid}/
  - docker-compose.yaml
  - .env
  - metadata.json

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 15:25:55 +01:00

71 lines
2.7 KiB
PHP

<?php
namespace App\Actions\Application;
use App\Models\Application;
use App\Models\Server;
use Lorisleiva\Actions\Concerns\AsAction;
class CleanupOldDeployments
{
use AsAction;
public const DEFAULT_RETENTION = 5;
public function handle(Application $application, Server $server, int $retention = self::DEFAULT_RETENTION): array
{
$deploymentsBaseDir = deployments_base_dir($application->uuid);
$cleanupLog = [];
// List all deployment directories sorted by modification time (newest first)
$listCommand = "ls -1t {$deploymentsBaseDir} 2>/dev/null || true";
$output = instant_remote_process([$listCommand], $server, throwError: false);
if (empty(trim($output))) {
return $cleanupLog;
}
$deployments = collect(explode("\n", trim($output)))->filter();
// Skip if we have fewer deployments than retention limit
if ($deployments->count() <= $retention) {
return $cleanupLog;
}
// Get deployments to delete (skip first N based on retention)
$deploymentsToDelete = $deployments->skip($retention);
foreach ($deploymentsToDelete as $deploymentUuid) {
$deploymentDir = "{$deploymentsBaseDir}/{$deploymentUuid}";
// Read metadata to get image name for potential cleanup
$metadataCommand = "cat {$deploymentDir}/metadata.json 2>/dev/null || echo '{}'";
$metadataJson = instant_remote_process([$metadataCommand], $server, throwError: false);
$metadata = json_decode($metadataJson, true) ?? [];
// Delete deployment directory
$deleteCommand = "rm -rf {$deploymentDir}";
instant_remote_process([$deleteCommand], $server, throwError: false);
$cleanupLog[] = "Deleted deployment directory: {$deploymentDir}";
// Optionally clean up the Docker image if it exists and is not used by remaining deployments
if (isset($metadata['image_name'])) {
$imageName = $metadata['image_name'];
// Check if this image is still referenced by other deployments
$checkImageUsage = "grep -r '\"image_name\": \"{$imageName}\"' {$deploymentsBaseDir}/*/metadata.json 2>/dev/null | wc -l";
$usageCount = (int) trim(instant_remote_process([$checkImageUsage], $server, throwError: false));
if ($usageCount === 0) {
instant_remote_process([
"docker rmi {$imageName} 2>/dev/null || true",
], $server, throwError: false);
$cleanupLog[] = "Removed unused image: {$imageName}";
}
}
}
return $cleanupLog;
}
}