From e74c464857a278f463cab6bafa806b4be60735af Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Tue, 21 Mar 2023 09:08:36 +0000 Subject: [PATCH 1/8] Refactoring: extract process handling from async job. --- app/Jobs/ExecuteCoolifyProcess.php | 105 +-------------- app/Services/CoolifyProcess.php | 8 +- app/Services/RemoteProcess/RemoteProcess.php | 121 ++++++++++++++++++ bootstrap/helpers.php | 3 +- .../views/livewire/run-command.blade.php | 3 +- tests/Feature/DockerCommandsTest.php | 17 +-- 6 files changed, 139 insertions(+), 118 deletions(-) create mode 100644 app/Services/RemoteProcess/RemoteProcess.php diff --git a/app/Jobs/ExecuteCoolifyProcess.php b/app/Jobs/ExecuteCoolifyProcess.php index 8dca3bc00..e6e6898e6 100755 --- a/app/Jobs/ExecuteCoolifyProcess.php +++ b/app/Jobs/ExecuteCoolifyProcess.php @@ -2,35 +2,20 @@ namespace App\Jobs; -use App\Services\ProcessStatus; -use Illuminate\Support\Facades\DB; +use App\Services\RemoteProcess\RemoteProcess; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Process\InvokedProcess; use Illuminate\Process\ProcessResult; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Illuminate\Support\Facades\Process; use Spatie\Activitylog\Contracts\Activity; class ExecuteCoolifyProcess implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - protected $throttleIntervalMS = 500; - - protected $timeStart; - - protected $currentTime; - - protected $lastWriteAt = 0; - - protected string $stdOutIncremental = ''; - - protected string $stdErrIncremental = ''; - /** * Create a new job instance. */ @@ -41,92 +26,12 @@ class ExecuteCoolifyProcess implements ShouldQueue /** * Execute the job. */ - public function handle(): ProcessResult + public function handle(): void { - $this->timeStart = hrtime(true); - - $user = $this->activity->getExtraProperty('user'); - $destination = $this->activity->getExtraProperty('destination'); - $port = $this->activity->getExtraProperty('port'); - $command = $this->activity->getExtraProperty('command'); - - $delimiter = 'EOF-COOLIFY-SSH'; - - $sshCommand = 'ssh ' - . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' - . '-o PasswordAuthentication=no ' - . '-o RequestTTY=no ' - // Quiet mode. Causes most warning and diagnostic messages to be suppressed. - // Errors are still out put. This is to silence for example, that warning - // Permanently added to the list of known hosts. - . '-q ' - . "-p {$port} " - . "{$user}@{$destination} " - . " 'bash -se' << \\$delimiter" . PHP_EOL - . $command . PHP_EOL - . $delimiter; - - $process = Process::start($sshCommand, $this->handleOutput(...)); - - $processResult = $process->wait(); - - $status = match ($processResult->exitCode()) { - 0 => ProcessStatus::FINISHED, - default => ProcessStatus::ERROR, - }; - - $this->activity->properties = $this->activity->properties->merge([ - 'exitCode' => $processResult->exitCode(), - 'stdout' => $processResult->output(), - 'stderr' => $processResult->errorOutput(), - 'status' => $status, + $remoteProcess = resolve(RemoteProcess::class, [ + 'activity' => $this->activity, ]); - $this->activity->save(); - - return $processResult; - } - - protected function handleOutput(string $type, string $output) - { - $this->currentTime = $this->elapsedTime(); - - if ($type === 'out') { - $this->stdOutIncremental .= $output; - } else { - $this->stdErrIncremental .= $output; - } - - $this->activity->description .= $output; - - if ($this->isAfterLastThrottle()) { - // Let's write to database. - DB::transaction(function () { - $this->activity->save(); - $this->lastWriteAt = $this->currentTime; - }); - } - } - - /** - * Decides if it's time to write again to database. - * - * @return bool - */ - protected function isAfterLastThrottle() - { - // If DB was never written, then we immediately decide we have to write. - if ($this->lastWriteAt === 0) { - return true; - } - - return ($this->currentTime - $this->throttleIntervalMS) > $this->lastWriteAt; - } - - protected function elapsedTime(): int - { - $timeMs = (hrtime(true) - $this->timeStart) / 1_000_000; - - return intval($timeMs); + $remoteProcess(); } } diff --git a/app/Services/CoolifyProcess.php b/app/Services/CoolifyProcess.php index 16071ebd7..cba46ebac 100644 --- a/app/Services/CoolifyProcess.php +++ b/app/Services/CoolifyProcess.php @@ -27,17 +27,13 @@ class CoolifyProcess 'command' => $this->command, 'status' => ProcessStatus::HOLDING, ]) - ->log("Awaiting to start command...\n\n"); + ->log("Awaiting command to start...\n\n"); } - public function __invoke(): Activity|ProcessResult + public function __invoke(): Activity { $job = new ExecuteCoolifyProcess($this->activity); - if (app()->environment('testing')) { - return $job->handle(); - } - dispatch($job); return $this->activity; diff --git a/app/Services/RemoteProcess/RemoteProcess.php b/app/Services/RemoteProcess/RemoteProcess.php new file mode 100644 index 000000000..ce83a9769 --- /dev/null +++ b/app/Services/RemoteProcess/RemoteProcess.php @@ -0,0 +1,121 @@ +timeStart = hrtime(true); + + $processResult = Process::run($this->getCommand(), $this->handleOutput(...)); + + $status = match ($processResult->exitCode()) { + 0 => ProcessStatus::FINISHED, + default => ProcessStatus::ERROR, + }; + + $this->activity->properties = $this->activity->properties->merge([ + 'exitCode' => $processResult->exitCode(), + 'stdout' => $processResult->output(), + 'stderr' => $processResult->errorOutput(), + 'status' => $status, + ]); + + $this->activity->save(); + + return $processResult; + } + + protected function getCommand(): string + { + $user = $this->activity->getExtraProperty('user'); + $destination = $this->activity->getExtraProperty('destination'); + $port = $this->activity->getExtraProperty('port'); + $command = $this->activity->getExtraProperty('command'); + + $delimiter = 'EOF-COOLIFY-SSH'; + + return 'ssh ' + . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' + . '-o PasswordAuthentication=no ' + . '-o RequestTTY=no ' + // Quiet mode. Causes most warning and diagnostic messages to be suppressed. + // Errors are still out put. This is to silence for example, that warning + // Permanently added to the list of known hosts. + . '-q ' + . "-p {$port} " + . "{$user}@{$destination} " + . " 'bash -se' << \\$delimiter" . PHP_EOL + . $command . PHP_EOL + . $delimiter; + } + + protected function handleOutput(string $type, string $output) + { + $this->currentTime = $this->elapsedTime(); + + if ($type === 'out') { + $this->stdOutIncremental .= $output; + } else { + $this->stdErrIncremental .= $output; + } + + $this->activity->description .= $output; + + if ($this->isAfterLastThrottle()) { + // Let's write to database. + DB::transaction(function () { + $this->activity->save(); + $this->lastWriteAt = $this->currentTime; + }); + } + } + + /** + * Determines if it's time to write again to database. + * + * @return bool + */ + protected function isAfterLastThrottle() + { + // If DB was never written, then we immediately decide we have to write. + if ($this->lastWriteAt === 0) { + return true; + } + + return ($this->currentTime - $this->throttleIntervalMS) > $this->lastWriteAt; + } + + protected function elapsedTime(): int + { + $timeMs = (hrtime(true) - $this->timeStart) / 1_000_000; + + return intval($timeMs); + } +} diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index 0d48f5401..4d26314f2 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -1,7 +1,6 @@ $destination, diff --git a/resources/views/livewire/run-command.blade.php b/resources/views/livewire/run-command.blade.php index 370264e6c..027eb14f0 100755 --- a/resources/views/livewire/run-command.blade.php +++ b/resources/views/livewire/run-command.blade.php @@ -56,8 +56,7 @@ flex-direction: column-reverse; " placeholder="Build output" - > - {{ data_get($activity, 'description') }} + >{{ data_get($activity, 'description') }}
diff --git a/tests/Feature/DockerCommandsTest.php b/tests/Feature/DockerCommandsTest.php index 32340a70d..45a2f1f64 100644 --- a/tests/Feature/DockerCommandsTest.php +++ b/tests/Feature/DockerCommandsTest.php @@ -13,20 +13,21 @@ it('starts a docker container correctly', function () { $host = 'testing-host'; // Assert there's no containers start with coolify_test_* - $processResult = coolifyProcess($areThereCoolifyTestContainers, $host); - $containers = Output::containerList($processResult->output()); + $activity = coolifyProcess($areThereCoolifyTestContainers, $host); + ray($activity); + $containers = Output::containerList($activity->getExtraProperty('stdout')); expect($containers)->toBeEmpty(); // start a container nginx -d --name = $containerName - $processResult = coolifyProcess("docker run -d --name {$containerName} nginx", $host); - expect($processResult->successful())->toBeTrue(); + $activity = coolifyProcess("docker run -d --name {$containerName} nginx", $host); + expect($activity->getExtraProperty('exitCode'))->toBe(0); // docker ps name = $container - $processResult = coolifyProcess($areThereCoolifyTestContainers, $host); - $containers = Output::containerList($processResult->output()); + $activity = coolifyProcess($areThereCoolifyTestContainers, $host); + $containers = Output::containerList($activity->getExtraProperty('stdout')); expect($containers->where('Names', $containerName)->count())->toBe(1); // Stop testing containers - $processResult = coolifyProcess("docker stop $(docker ps --filter='name={$coolifyNamePrefix}*' -q)", $host); - expect($processResult->successful())->toBeTrue(); + $activity = coolifyProcess("docker stop $(docker ps --filter='name={$coolifyNamePrefix}*' -q)", $host); + expect($activity->getExtraProperty('exitCode'))->toBe(0); }); From d0d33da493ac12a72cc16568b0d266a8ed032e7c Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Tue, 21 Mar 2023 09:31:16 +0000 Subject: [PATCH 2/8] Refactoring: extract process handling from async job. --- app/Http/Livewire/RunCommand.php | 6 +++--- app/Jobs/ExecuteCoolifyProcess.php | 1 - app/Services/CoolifyProcess.php | 6 ++++-- bootstrap/helpers.php | 12 ++++-------- tests/Feature/DockerCommandsTest.php | 8 ++++---- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/app/Http/Livewire/RunCommand.php b/app/Http/Livewire/RunCommand.php index 76425e012..ae189422e 100755 --- a/app/Http/Livewire/RunCommand.php +++ b/app/Http/Livewire/RunCommand.php @@ -23,21 +23,21 @@ class RunCommand extends Component { $this->isKeepAliveOn = true; - $this->activity = coolifyProcess($this->command, 'testing-host'); + $this->activity = remoteProcess($this->command, 'testing-host'); } public function runSleepingBeauty() { $this->isKeepAliveOn = true; - $this->activity = coolifyProcess('x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done', 'testing-host'); + $this->activity = remoteProcess('x=1; while [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done', 'testing-host'); } public function runDummyProjectBuild() { $this->isKeepAliveOn = true; - $this->activity = coolifyProcess(<<activity = remoteProcess(<<activity->refresh(); + + ray($this->activity->id); + return $this->activity; } - } diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index 4d26314f2..e4d1f51a7 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -3,21 +3,17 @@ use App\Services\CoolifyProcess; use Spatie\Activitylog\Contracts\Activity; -if (! function_exists('coolifyProcess')) { +if (! function_exists('remoteProcess')) { /** * Run a Coolify Process, which SSH's into a machine to run the command(s). * */ - function coolifyProcess($command, $destination): Activity + function remoteProcess($command, $destination): Activity { - $process = resolve(CoolifyProcess::class, [ + return resolve(CoolifyProcess::class, [ 'destination' => $destination, 'command' => $command, - ]); - - $activityLog = $process(); - - return $activityLog; + ])(); } } diff --git a/tests/Feature/DockerCommandsTest.php b/tests/Feature/DockerCommandsTest.php index 45a2f1f64..918025525 100644 --- a/tests/Feature/DockerCommandsTest.php +++ b/tests/Feature/DockerCommandsTest.php @@ -13,21 +13,21 @@ it('starts a docker container correctly', function () { $host = 'testing-host'; // Assert there's no containers start with coolify_test_* - $activity = coolifyProcess($areThereCoolifyTestContainers, $host); + $activity = remoteProcess($areThereCoolifyTestContainers, $host); ray($activity); $containers = Output::containerList($activity->getExtraProperty('stdout')); expect($containers)->toBeEmpty(); // start a container nginx -d --name = $containerName - $activity = coolifyProcess("docker run -d --name {$containerName} nginx", $host); + $activity = remoteProcess("docker run -d --name {$containerName} nginx", $host); expect($activity->getExtraProperty('exitCode'))->toBe(0); // docker ps name = $container - $activity = coolifyProcess($areThereCoolifyTestContainers, $host); + $activity = remoteProcess($areThereCoolifyTestContainers, $host); $containers = Output::containerList($activity->getExtraProperty('stdout')); expect($containers->where('Names', $containerName)->count())->toBe(1); // Stop testing containers - $activity = coolifyProcess("docker stop $(docker ps --filter='name={$coolifyNamePrefix}*' -q)", $host); + $activity = remoteProcess("docker stop $(docker ps --filter='name={$coolifyNamePrefix}*' -q)", $host); expect($activity->getExtraProperty('exitCode'))->toBe(0); }); From 83a7ef21f388906ffbdb8c6b22ce0e13624d4e3c Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Tue, 21 Mar 2023 09:32:16 +0000 Subject: [PATCH 3/8] Refactoring: extract process handling from async job. --- app/{Services => Actions}/RemoteProcess/RemoteProcess.php | 4 ++-- app/{Services => Enums}/ProcessStatus.php | 2 +- app/Jobs/ExecuteCoolifyProcess.php | 3 +-- app/Services/CoolifyProcess.php | 1 + 4 files changed, 5 insertions(+), 5 deletions(-) rename app/{Services => Actions}/RemoteProcess/RemoteProcess.php (97%) rename app/{Services => Enums}/ProcessStatus.php (87%) diff --git a/app/Services/RemoteProcess/RemoteProcess.php b/app/Actions/RemoteProcess/RemoteProcess.php similarity index 97% rename from app/Services/RemoteProcess/RemoteProcess.php rename to app/Actions/RemoteProcess/RemoteProcess.php index ce83a9769..24c17dd8d 100644 --- a/app/Services/RemoteProcess/RemoteProcess.php +++ b/app/Actions/RemoteProcess/RemoteProcess.php @@ -1,8 +1,8 @@ Date: Tue, 21 Mar 2023 09:56:49 +0000 Subject: [PATCH 4/8] Refactoring: extract process handling from async job. --- .../RemoteProcess/DispatchRemoteProcess.php} | 11 +++++------ .../{RemoteProcess.php => RunRemoteProcess.php} | 16 ++++++++++++---- app/Enums/ActivityTypes.php | 8 ++++++++ app/Jobs/ExecuteCoolifyProcess.php | 4 ++-- bootstrap/helpers.php | 4 ++-- tests/Unit/RulesTest.php | 5 +++++ 6 files changed, 34 insertions(+), 14 deletions(-) rename app/{Services/CoolifyProcess.php => Actions/RemoteProcess/DispatchRemoteProcess.php} (87%) rename app/Actions/RemoteProcess/{RemoteProcess.php => RunRemoteProcess.php} (89%) create mode 100644 app/Enums/ActivityTypes.php create mode 100644 tests/Unit/RulesTest.php diff --git a/app/Services/CoolifyProcess.php b/app/Actions/RemoteProcess/DispatchRemoteProcess.php similarity index 87% rename from app/Services/CoolifyProcess.php rename to app/Actions/RemoteProcess/DispatchRemoteProcess.php index 102a94a74..c8a81699a 100644 --- a/app/Services/CoolifyProcess.php +++ b/app/Actions/RemoteProcess/DispatchRemoteProcess.php @@ -1,12 +1,13 @@ activity = activity() ->withProperties([ - 'type' => 'COOLIFY_PROCESS', + 'type' => ActivityTypes::COOLIFY_PROCESS, + 'status' => ProcessStatus::HOLDING, 'user' => $this->user, 'destination' => $this->destination, 'port' => $this->port, 'command' => $this->command, - 'status' => ProcessStatus::HOLDING, ]) ->log("Awaiting command to start...\n\n"); } @@ -38,8 +39,6 @@ class CoolifyProcess $this->activity->refresh(); - ray($this->activity->id); - return $this->activity; } diff --git a/app/Actions/RemoteProcess/RemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php similarity index 89% rename from app/Actions/RemoteProcess/RemoteProcess.php rename to app/Actions/RemoteProcess/RunRemoteProcess.php index 24c17dd8d..b0694f53d 100644 --- a/app/Actions/RemoteProcess/RemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -2,14 +2,17 @@ namespace App\Actions\RemoteProcess; +use App\Enums\ActivityTypes; use App\Enums\ProcessStatus; use Illuminate\Process\ProcessResult; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Process; use Spatie\Activitylog\Contracts\Activity; -class RemoteProcess +class RunRemoteProcess { + public Activity $activity; + protected $timeStart; protected $currentTime; @@ -25,9 +28,14 @@ class RemoteProcess /** * Create a new job instance. */ - public function __construct( - public Activity $activity, - ){} + public function __construct(Activity $activity) + { + if ($activity->getExtraProperty('type') !== ActivityTypes::COOLIFY_PROCESS->value) { + throw new \RuntimeException('Incompatible Activity to run a remote command.'); + } + + $this->activity = $activity; + } public function __invoke(): ProcessResult { diff --git a/app/Enums/ActivityTypes.php b/app/Enums/ActivityTypes.php new file mode 100644 index 000000000..52a35e2f8 --- /dev/null +++ b/app/Enums/ActivityTypes.php @@ -0,0 +1,8 @@ + $this->activity, ]); diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index e4d1f51a7..966206c43 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -1,6 +1,6 @@ $destination, 'command' => $command, ])(); diff --git a/tests/Unit/RulesTest.php b/tests/Unit/RulesTest.php new file mode 100644 index 000000000..02e14ba48 --- /dev/null +++ b/tests/Unit/RulesTest.php @@ -0,0 +1,5 @@ +expect(['dd', 'dump', 'ray']) + ->not->toBeUsed(); From 34c9265aa9f6f55b76c1c8b2c13b9d65c71539d2 Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Tue, 21 Mar 2023 10:02:16 +0000 Subject: [PATCH 5/8] Refactoring: extract process handling from async job. --- .../RemoteProcess/DispatchRemoteProcess.php | 17 +++++++++-------- app/Data/RemoteProcessArgs.php | 19 +++++++++++++++++++ composer.json | 2 +- 3 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 app/Data/RemoteProcessArgs.php diff --git a/app/Actions/RemoteProcess/DispatchRemoteProcess.php b/app/Actions/RemoteProcess/DispatchRemoteProcess.php index c8a81699a..09dc2348e 100644 --- a/app/Actions/RemoteProcess/DispatchRemoteProcess.php +++ b/app/Actions/RemoteProcess/DispatchRemoteProcess.php @@ -2,6 +2,7 @@ namespace App\Actions\RemoteProcess; +use App\Data\RemoteProcessArgs; use App\Enums\ActivityTypes; use App\Enums\ProcessStatus; use App\Jobs\ExecuteCoolifyProcess; @@ -19,15 +20,15 @@ class DispatchRemoteProcess protected ?int $port = 22, protected ?string $user = 'root', ){ + $arguments = new RemoteProcessArgs( + destination: $this->destination, + command: $this->command, + port: $this->port, + user: $this->user, + ); + $this->activity = activity() - ->withProperties([ - 'type' => ActivityTypes::COOLIFY_PROCESS, - 'status' => ProcessStatus::HOLDING, - 'user' => $this->user, - 'destination' => $this->destination, - 'port' => $this->port, - 'command' => $this->command, - ]) + ->withProperties($arguments->toArray()) ->log("Awaiting command to start...\n\n"); } diff --git a/app/Data/RemoteProcessArgs.php b/app/Data/RemoteProcessArgs.php new file mode 100644 index 000000000..a94e461fb --- /dev/null +++ b/app/Data/RemoteProcessArgs.php @@ -0,0 +1,19 @@ +value, + protected string $status = ProcessStatus::HOLDING->value, + ){} +} diff --git a/composer.json b/composer.json index 2b626323e..b023863bc 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "keywords": ["framework", "laravel"], "license": "MIT", "require": { - "php": "^8.1", + "php": "^8.2", "guzzlehttp/guzzle": "^7.2", "laravel/framework": "^10.0", "laravel/sanctum": "^3.2", From 29fb40bd160f3c4280a19381efdd5930412dd202 Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Tue, 21 Mar 2023 10:32:38 +0000 Subject: [PATCH 6/8] Refactoring: extract process handling from async job. --- .../RemoteProcess/DispatchRemoteProcess.php | 23 +++---------------- .../RemoteProcess/RunRemoteProcess.php | 6 +---- app/Data/RemoteProcessArgs.php | 12 +++++----- app/Jobs/ExecuteCoolifyProcess.php | 2 +- bootstrap/helpers.php | 20 ++++++++++++---- tests/Feature/DockerCommandsTest.php | 3 +-- 6 files changed, 27 insertions(+), 39 deletions(-) diff --git a/app/Actions/RemoteProcess/DispatchRemoteProcess.php b/app/Actions/RemoteProcess/DispatchRemoteProcess.php index 09dc2348e..c907c7a7d 100644 --- a/app/Actions/RemoteProcess/DispatchRemoteProcess.php +++ b/app/Actions/RemoteProcess/DispatchRemoteProcess.php @@ -3,32 +3,16 @@ namespace App\Actions\RemoteProcess; use App\Data\RemoteProcessArgs; -use App\Enums\ActivityTypes; -use App\Enums\ProcessStatus; use App\Jobs\ExecuteCoolifyProcess; -use Spatie\Activitylog\Contracts\Activity; +use Spatie\Activitylog\Models\Activity; class DispatchRemoteProcess { protected Activity $activity; - // TODO Left 'root' as default user instead of 'coolify' because - // there's a task at TODO.md to run docker without sudo - public function __construct( - protected string $destination, - protected string $command, - protected ?int $port = 22, - protected ?string $user = 'root', - ){ - $arguments = new RemoteProcessArgs( - destination: $this->destination, - command: $this->command, - port: $this->port, - user: $this->user, - ); - + public function __construct(RemoteProcessArgs $remoteProcessArgs){ $this->activity = activity() - ->withProperties($arguments->toArray()) + ->withProperties($remoteProcessArgs->toArray()) ->log("Awaiting command to start...\n\n"); } @@ -42,5 +26,4 @@ class DispatchRemoteProcess return $this->activity; } - } diff --git a/app/Actions/RemoteProcess/RunRemoteProcess.php b/app/Actions/RemoteProcess/RunRemoteProcess.php index b0694f53d..69dc35465 100644 --- a/app/Actions/RemoteProcess/RunRemoteProcess.php +++ b/app/Actions/RemoteProcess/RunRemoteProcess.php @@ -7,7 +7,7 @@ use App\Enums\ProcessStatus; use Illuminate\Process\ProcessResult; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Process; -use Spatie\Activitylog\Contracts\Activity; +use Spatie\Activitylog\Models\Activity; class RunRemoteProcess { @@ -73,10 +73,6 @@ class RunRemoteProcess . '-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' . '-o PasswordAuthentication=no ' . '-o RequestTTY=no ' - // Quiet mode. Causes most warning and diagnostic messages to be suppressed. - // Errors are still out put. This is to silence for example, that warning - // Permanently added to the list of known hosts. - . '-q ' . "-p {$port} " . "{$user}@{$destination} " . " 'bash -se' << \\$delimiter" . PHP_EOL diff --git a/app/Data/RemoteProcessArgs.php b/app/Data/RemoteProcessArgs.php index a94e461fb..65ed0e645 100644 --- a/app/Data/RemoteProcessArgs.php +++ b/app/Data/RemoteProcessArgs.php @@ -9,11 +9,11 @@ use Spatie\LaravelData\Data; class RemoteProcessArgs extends Data { public function __construct( - protected string $destination, - protected string $command, - protected int $port = 22, - protected string $user = 'root', - protected string $type = ActivityTypes::COOLIFY_PROCESS->value, - protected string $status = ProcessStatus::HOLDING->value, + public string $destination, + public string $command, + public int $port, + public string $user, + public string $type = ActivityTypes::COOLIFY_PROCESS->value, + public string $status = ProcessStatus::HOLDING->value, ){} } diff --git a/app/Jobs/ExecuteCoolifyProcess.php b/app/Jobs/ExecuteCoolifyProcess.php index fdb460361..9cdcaa809 100755 --- a/app/Jobs/ExecuteCoolifyProcess.php +++ b/app/Jobs/ExecuteCoolifyProcess.php @@ -8,7 +8,7 @@ use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use Spatie\Activitylog\Contracts\Activity; +use Spatie\Activitylog\Models\Activity; class ExecuteCoolifyProcess implements ShouldQueue { diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php index 966206c43..c7517b0db 100644 --- a/bootstrap/helpers.php +++ b/bootstrap/helpers.php @@ -1,19 +1,29 @@ $destination, - 'command' => $command, + 'remoteProcessArgs' => new RemoteProcessArgs( + destination: $destination, + command: $command, + port: $port, + user: $user, + ), ])(); } } diff --git a/tests/Feature/DockerCommandsTest.php b/tests/Feature/DockerCommandsTest.php index 918025525..8fc551a04 100644 --- a/tests/Feature/DockerCommandsTest.php +++ b/tests/Feature/DockerCommandsTest.php @@ -14,12 +14,11 @@ it('starts a docker container correctly', function () { // Assert there's no containers start with coolify_test_* $activity = remoteProcess($areThereCoolifyTestContainers, $host); - ray($activity); $containers = Output::containerList($activity->getExtraProperty('stdout')); expect($containers)->toBeEmpty(); // start a container nginx -d --name = $containerName - $activity = remoteProcess("docker run -d --name {$containerName} nginx", $host); + $activity = remoteProcess("docker run -d --rm --name {$containerName} nginx", $host); expect($activity->getExtraProperty('exitCode'))->toBe(0); // docker ps name = $container From 0d3b493a76179234d19c1cb99f36eb2862dcc07a Mon Sep 17 00:00:00 2001 From: Joao Patricio Date: Tue, 21 Mar 2023 10:39:44 +0000 Subject: [PATCH 7/8] Refactoring: extract process handling from async job. --- app/Actions/RemoteProcess/DispatchRemoteProcess.php | 4 ++-- .../{ExecuteCoolifyProcess.php => ExecuteRemoteProcess.php} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename app/Jobs/{ExecuteCoolifyProcess.php => ExecuteRemoteProcess.php} (93%) diff --git a/app/Actions/RemoteProcess/DispatchRemoteProcess.php b/app/Actions/RemoteProcess/DispatchRemoteProcess.php index c907c7a7d..9c7cb20b2 100644 --- a/app/Actions/RemoteProcess/DispatchRemoteProcess.php +++ b/app/Actions/RemoteProcess/DispatchRemoteProcess.php @@ -3,7 +3,7 @@ namespace App\Actions\RemoteProcess; use App\Data\RemoteProcessArgs; -use App\Jobs\ExecuteCoolifyProcess; +use App\Jobs\ExecuteRemoteProcess; use Spatie\Activitylog\Models\Activity; class DispatchRemoteProcess @@ -18,7 +18,7 @@ class DispatchRemoteProcess public function __invoke(): Activity { - $job = new ExecuteCoolifyProcess($this->activity); + $job = new ExecuteRemoteProcess($this->activity); dispatch($job); diff --git a/app/Jobs/ExecuteCoolifyProcess.php b/app/Jobs/ExecuteRemoteProcess.php similarity index 93% rename from app/Jobs/ExecuteCoolifyProcess.php rename to app/Jobs/ExecuteRemoteProcess.php index 9cdcaa809..567c88d9a 100755 --- a/app/Jobs/ExecuteCoolifyProcess.php +++ b/app/Jobs/ExecuteRemoteProcess.php @@ -10,7 +10,7 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; use Spatie\Activitylog\Models\Activity; -class ExecuteCoolifyProcess implements ShouldQueue +class ExecuteRemoteProcess implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; From c1866f84e41420a448d8db797a060d8f7299b3c5 Mon Sep 17 00:00:00 2001 From: Andras Bacsai Date: Wed, 22 Mar 2023 17:34:55 +0100 Subject: [PATCH 8/8] Add missing laravel-data --- composer.json | 1 + composer.lock | 485 +++++++++++++++++++++++++++++--------------------- 2 files changed, 285 insertions(+), 201 deletions(-) diff --git a/composer.json b/composer.json index b023863bc..207edd878 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "laravel/tinker": "^2.8", "livewire/livewire": "^2.12", "spatie/laravel-activitylog": "^4.7", + "spatie/laravel-data": "^3.2", "spatie/laravel-ray": "^1.32" }, "require-dev": { diff --git a/composer.lock b/composer.lock index bad962709..ad3d8bd5e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "5b876c04da75e4ae5fab21efa402fd45", + "content-hash": "c6bfcd94dc256f9124e84a380eaaf556", "packages": [ { "name": "brick/math", @@ -137,6 +137,49 @@ }, "time": "2022-10-27T11:44:00+00:00" }, + { + "name": "doctrine/deprecations", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/deprecations.git", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", + "shasum": "" + }, + "require": { + "php": "^7.1|^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9", + "phpunit/phpunit": "^7.5|^8.5|^9.5", + "psr/log": "^1|^2|^3" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" + }, + "time": "2022-05-02T15:47:09+00:00" + }, { "name": "doctrine/inflector", "version": "2.0.6", @@ -2276,6 +2319,117 @@ ], "time": "2023-02-08T01:06:31+00:00" }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.7.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", + "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^1.0", + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.0" + }, + "time": "2023-03-12T10:13:29+00:00" + }, { "name": "phpoption/phpoption", "version": "1.9.1", @@ -2351,6 +2505,51 @@ ], "time": "2023-02-25T19:38:58+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.16.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e27e92d939e2e3636f0a1f0afaba59692c0bf571", + "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.16.1" + }, + "time": "2023-02-07T18:11:17+00:00" + }, { "name": "pimple/pimple", "version": "v3.5.0", @@ -3222,6 +3421,89 @@ ], "time": "2023-01-25T17:04:51+00:00" }, + { + "name": "spatie/laravel-data", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-data.git", + "reference": "c4f632924870e52beefe982aa50a88ff59250bfd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-data/zipball/c4f632924870e52beefe982aa50a88ff59250bfd", + "reference": "c4f632924870e52beefe982aa50a88ff59250bfd", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^9.30|^10.0", + "php": "^8.1", + "phpdocumentor/type-resolver": "^1.5", + "spatie/laravel-package-tools": "^1.9.0" + }, + "require-dev": { + "fakerphp/faker": "^1.14", + "friendsofphp/php-cs-fixer": "^3.0", + "inertiajs/inertia-laravel": "^0.6.3", + "nesbot/carbon": "^2.63", + "nette/php-generator": "^3.5", + "nunomaduro/larastan": "^2.0", + "orchestra/testbench": "^7.6|^8.0", + "pestphp/pest": "^1.22", + "pestphp/pest-plugin-laravel": "^1.3", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpunit/phpunit": "^9.3", + "spatie/invade": "^1.0", + "spatie/laravel-typescript-transformer": "^2.1.6", + "spatie/pest-plugin-snapshots": "^1.1", + "spatie/phpunit-snapshot-assertions": "^4.2", + "spatie/test-time": "^1.2" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\LaravelData\\LaravelDataServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\LaravelData\\": "src", + "Spatie\\LaravelData\\Database\\Factories\\": "database/factories" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ruben Van Assche", + "email": "ruben@spatie.be", + "role": "Developer" + } + ], + "description": "Create unified resources and data transfer objects", + "homepage": "https://github.com/spatie/laravel-data", + "keywords": [ + "laravel", + "laravel-data", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-data/issues", + "source": "https://github.com/spatie/laravel-data/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2023-03-17T09:48:15+00:00" + }, { "name": "spatie/laravel-package-tools", "version": "1.14.2", @@ -6406,49 +6688,6 @@ ], "time": "2023-03-20T15:15:41+00:00" }, - { - "name": "doctrine/deprecations", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", - "reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de", - "shasum": "" - }, - "require": { - "php": "^7.1|^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.0.0" - }, - "time": "2022-05-02T15:47:09+00:00" - }, { "name": "fakerphp/faker", "version": "v1.21.0", @@ -7521,59 +7760,6 @@ }, "time": "2022-02-21T01:04:05+00:00" }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, { "name": "phpdocumentor/reflection-docblock", "version": "5.3.0", @@ -7631,109 +7817,6 @@ }, "time": "2021-10-19T17:43:47+00:00" }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.7.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", - "reference": "1534aea9bde19a5c85c5d1e1f834ab63f4c5dcf5", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.13" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.0" - }, - "time": "2023-03-12T10:13:29+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "1.16.1", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/e27e92d939e2e3636f0a1f0afaba59692c0bf571", - "reference": "e27e92d939e2e3636f0a1f0afaba59692c0bf571", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.16.1" - }, - "time": "2023-02-07T18:11:17+00:00" - }, { "name": "phpunit/php-code-coverage", "version": "10.0.2", @@ -9484,7 +9567,7 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^8.1" + "php": "^8.2" }, "platform-dev": [], "plugin-api-version": "2.3.0"