mirror of
https://github.com/coollabsio/coolify.git
synced 2026-10-29 01:54:37 +08:00
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Furox <177975472+Furox-Art@users.noreply.github.com> Co-authored-by: johandenhollander <johan.den.hollander@finalist.nl> Co-authored-by: João Cruz <161638790+SrJooJ@users.noreply.github.com> Co-authored-by: Saim Hashmi <hashmisaim037@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
90 lines
3.0 KiB
PHP
90 lines
3.0 KiB
PHP
<?php
|
|
|
|
use App\Exceptions\DeploymentException;
|
|
use App\Jobs\ApplicationDeploymentJob;
|
|
use App\Models\Application;
|
|
use App\Models\ApplicationDeploymentQueue;
|
|
use Illuminate\Support\Sleep;
|
|
|
|
/**
|
|
* Records remote commands and fails the repository import with the queued exit codes.
|
|
*/
|
|
class ImportRetryDeploymentJob extends ApplicationDeploymentJob
|
|
{
|
|
public array $commands = [];
|
|
|
|
public array $importExitCodes = [];
|
|
|
|
public function __construct() {}
|
|
|
|
public function execute_remote_command(...$commands): void
|
|
{
|
|
foreach ($commands as $command) {
|
|
$this->commands[] = $command[0];
|
|
if (str_contains($command[0], 'git clone') && $exitCode = array_shift($this->importExitCodes)) {
|
|
throw new DeploymentException('Command execution failed', $exitCode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
beforeEach(function () {
|
|
Sleep::fake();
|
|
config()->set('constants.ssh.max_retries', 3);
|
|
|
|
$application = Mockery::mock(Application::class)->makePartial();
|
|
$application->shouldReceive('generateGitImportCommands')->andReturn([
|
|
'commands' => "docker exec deploy-uuid bash -c 'git clone repo /artifacts/deploy-uuid'",
|
|
'branch' => 'main',
|
|
'fullRepoUrl' => 'repo',
|
|
]);
|
|
|
|
$queue = Mockery::mock(ApplicationDeploymentQueue::class)->makePartial();
|
|
$queue->shouldReceive('addLogEntry');
|
|
|
|
$this->job = new ImportRetryDeploymentJob;
|
|
foreach ([
|
|
'application' => $application,
|
|
'application_deployment_queue' => $queue,
|
|
'deployment_uuid' => 'deploy-uuid',
|
|
'basedir' => '/artifacts/deploy-uuid',
|
|
'pull_request_id' => 0,
|
|
'commit' => 'HEAD',
|
|
] as $property => $value) {
|
|
(new ReflectionProperty(ApplicationDeploymentJob::class, $property))->setValue($this->job, $value);
|
|
}
|
|
});
|
|
|
|
function importRepository(ImportRetryDeploymentJob $job): void
|
|
{
|
|
(new ReflectionMethod(ApplicationDeploymentJob::class, 'import_repository'))->invoke($job);
|
|
}
|
|
|
|
function cloneCommandCount(ImportRetryDeploymentJob $job): int
|
|
{
|
|
return collect($job->commands)->filter(fn (string $command) => str_contains($command, 'git clone'))->count();
|
|
}
|
|
|
|
it('cleans up and clones again when the SSH connection drops during the import', function () {
|
|
$this->job->importExitCodes = [255];
|
|
|
|
importRepository($this->job);
|
|
|
|
expect(cloneCommandCount($this->job))->toBe(2)
|
|
->and($this->job->commands[1])->toBe(executeInDocker('deploy-uuid', "pkill git; rm -rf '/artifacts/deploy-uuid'"));
|
|
});
|
|
|
|
it('does not retry the import when git itself fails', function () {
|
|
$this->job->importExitCodes = [128];
|
|
|
|
expect(fn () => importRepository($this->job))->toThrow(DeploymentException::class);
|
|
expect(cloneCommandCount($this->job))->toBe(1);
|
|
});
|
|
|
|
it('stops retrying the import after the configured SSH attempts', function () {
|
|
$this->job->importExitCodes = [255, 255, 255];
|
|
|
|
expect(fn () => importRepository($this->job))->toThrow(DeploymentException::class);
|
|
expect(cloneCommandCount($this->job))->toBe(3);
|
|
});
|