feat: add deployments as activity
fix: tests refactor: remoteProcess
This commit is contained in:
		| @@ -10,10 +10,23 @@ class DispatchRemoteProcess | |||||||
| { | { | ||||||
|     protected Activity $activity; |     protected Activity $activity; | ||||||
| 
 | 
 | ||||||
|     public function __construct(RemoteProcessArgs $remoteProcessArgs){ |     public function __construct(RemoteProcessArgs $remoteProcessArgs) | ||||||
|         $this->activity = activity() |     { | ||||||
|             ->withProperties($remoteProcessArgs->toArray()) |         if ($remoteProcessArgs->model) { | ||||||
|             ->log(""); |             $properties = $remoteProcessArgs->toArray(); | ||||||
|  |             unset($properties['model']); | ||||||
|  | 
 | ||||||
|  |             $this->activity = activity() | ||||||
|  |                 ->withProperties($properties) | ||||||
|  |                 ->performedOn($remoteProcessArgs->model) | ||||||
|  |                 ->event('deployment') | ||||||
|  |                 ->log(""); | ||||||
|  |         } else { | ||||||
|  |             $this->activity = activity() | ||||||
|  |                 ->withProperties($remoteProcessArgs->toArray()) | ||||||
|  |                 ->event('remote_process') | ||||||
|  |                 ->log(""); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function __invoke(): Activity |     public function __invoke(): Activity | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ class RunRemoteProcess | |||||||
|      */ |      */ | ||||||
|     public function __construct(Activity $activity) |     public function __construct(Activity $activity) | ||||||
|     { |     { | ||||||
|         if ($activity->getExtraProperty('type') !== ActivityTypes::COOLIFY_PROCESS->value) { |         if ($activity->getExtraProperty('type') !== ActivityTypes::REMOTE_PROCESS->value) { | ||||||
|             throw new \RuntimeException('Incompatible Activity to run a remote command.'); |             throw new \RuntimeException('Incompatible Activity to run a remote command.'); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @@ -64,7 +64,7 @@ class RunRemoteProcess | |||||||
|     protected function getCommand(): string |     protected function getCommand(): string | ||||||
|     { |     { | ||||||
|         $user = $this->activity->getExtraProperty('user'); |         $user = $this->activity->getExtraProperty('user'); | ||||||
|         $destination = $this->activity->getExtraProperty('destination'); |         $server_ip = $this->activity->getExtraProperty('server_ip'); | ||||||
|         $private_key_location = $this->activity->getExtraProperty('private_key_location'); |         $private_key_location = $this->activity->getExtraProperty('private_key_location'); | ||||||
|         $port = $this->activity->getExtraProperty('port'); |         $port = $this->activity->getExtraProperty('port'); | ||||||
|         $command = $this->activity->getExtraProperty('command'); |         $command = $this->activity->getExtraProperty('command'); | ||||||
| @@ -80,7 +80,7 @@ class RunRemoteProcess | |||||||
|             . '-o LogLevel=ERROR ' |             . '-o LogLevel=ERROR ' | ||||||
|             . '-o ControlMaster=auto -o ControlPersist=yes -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r ' |             . '-o ControlMaster=auto -o ControlPersist=yes -o ControlPersist=1m -o ControlPath=/var/www/html/storage/app/.ssh/ssh_mux_%h_%p_%r ' | ||||||
|             . "-p {$port} " |             . "-p {$port} " | ||||||
|             . "{$user}@{$destination} " |             . "{$user}@{$server_ip} " | ||||||
|             . " 'bash -se' << \\$delimiter" . PHP_EOL |             . " 'bash -se' << \\$delimiter" . PHP_EOL | ||||||
|             . $command . PHP_EOL |             . $command . PHP_EOL | ||||||
|             . $delimiter; |             . $delimiter; | ||||||
|   | |||||||
| @@ -4,17 +4,21 @@ namespace App\Data; | |||||||
| 
 | 
 | ||||||
| use App\Enums\ActivityTypes; | use App\Enums\ActivityTypes; | ||||||
| use App\Enums\ProcessStatus; | use App\Enums\ProcessStatus; | ||||||
|  | use Illuminate\Database\Eloquent\Model; | ||||||
| use Spatie\LaravelData\Data; | use Spatie\LaravelData\Data; | ||||||
| 
 | 
 | ||||||
| class RemoteProcessArgs extends Data | class RemoteProcessArgs extends Data | ||||||
| { | { | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         public string    $destination, |         public Model|null       $model, | ||||||
|         public string    $private_key_location, |         public string           $server_ip, | ||||||
|         public string    $command, |         public string           $private_key_location, | ||||||
|         public int       $port, |         public string|null      $deployment_uuid, | ||||||
|         public string    $user, |         public string           $command, | ||||||
|         public string    $type = ActivityTypes::COOLIFY_PROCESS->value, |         public int              $port, | ||||||
|         public string    $status = ProcessStatus::HOLDING->value, |         public string           $user, | ||||||
|     ){} |         public string           $type = ActivityTypes::REMOTE_PROCESS->value, | ||||||
|  |         public string           $status = ProcessStatus::HOLDING->value, | ||||||
|  |     ) { | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,5 +4,5 @@ namespace App\Enums; | |||||||
| 
 | 
 | ||||||
| enum ActivityTypes: string | enum ActivityTypes: string | ||||||
| { | { | ||||||
|     case COOLIFY_PROCESS = 'coolify_process'; |     case REMOTE_PROCESS = 'remote_process'; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||||||
| 
 | 
 | ||||||
| use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
| 
 | 
 | ||||||
| class ProjectController extends Controller | class ProjectController extends Controller | ||||||
| { | { | ||||||
| @@ -103,7 +104,7 @@ class ProjectController extends Controller | |||||||
|         if (!$application) { |         if (!$application) { | ||||||
|             return redirect()->route('home'); |             return redirect()->route('home'); | ||||||
|         } |         } | ||||||
|         $deployment = $application->deployments->where('uuid', $deployment_uuid)->first(); |         $activity = $application->get_deployment($deployment_uuid); | ||||||
|         return view('project.deployment', ['project' => $project, 'deployment' => $deployment]); |         return view('project.deployment', ['project' => $project, 'activity' => $activity]); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ class DeployApplication extends Component | |||||||
|     } |     } | ||||||
|     private function start_builder_container() |     private function start_builder_container() | ||||||
|     { |     { | ||||||
|         $this->command[] = "docker run --pull=always -d --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/coollabsio/coolify-builder >/dev/null"; |         $this->command[] = "docker run --pull=always -d --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock ghcr.io/coollabsio/coolify-builder >/dev/null 2>&1"; | ||||||
|     } |     } | ||||||
|     public function deploy() |     public function deploy() | ||||||
|     { |     { | ||||||
| @@ -36,18 +36,17 @@ class DeployApplication extends Component | |||||||
|         $wildcard_domain = $project_wildcard_domain ?? $global_wildcard_domain ?? null; |         $wildcard_domain = $project_wildcard_domain ?? $global_wildcard_domain ?? null; | ||||||
| 
 | 
 | ||||||
|         // Create Deployment ID
 |         // Create Deployment ID
 | ||||||
|         $this->deployment_uuid = new Cuid2(10); |         $this->deployment_uuid = new Cuid2(12); | ||||||
|         $workdir = "/artifacts/{$this->deployment_uuid}"; |         $workdir = "/artifacts/{$this->deployment_uuid}"; | ||||||
| 
 | 
 | ||||||
|         // Start build process
 |         // Start build process
 | ||||||
|         $this->command[] = "echo 'Starting deployment of {$application->name} ({$application->uuid})'"; |         $this->command[] = "echo 'Starting deployment of {$application->name} ({$application->uuid})'"; | ||||||
|         $this->start_builder_container(); |         $this->start_builder_container(); | ||||||
|         $this->execute_in_builder('hostname'); |         // $this->execute_in_builder('hostname');
 | ||||||
|         $this->execute_in_builder("git clone -b {$application->git_branch} {$source->html_url}/{$application->git_repository}.git {$workdir}"); |         $this->execute_in_builder("git clone -b {$application->git_branch} {$source->html_url}/{$application->git_repository}.git {$workdir}"); | ||||||
|         $this->execute_in_builder("ls -l {$workdir}"); |         $this->execute_in_builder("ls -l {$workdir}"); | ||||||
|         $this->command[] = "docker stop -t 0 {$this->deployment_uuid} >/dev/null"; |         $this->command[] = "docker stop -t 0 {$this->deployment_uuid} >/dev/null"; | ||||||
| 
 |         $this->activity = remoteProcess($this->command, $destination->server, $this->deployment_uuid, $application); | ||||||
|         $this->activity = remoteProcess(implode("\n", $this->command), $destination->server->name); |  | ||||||
| 
 | 
 | ||||||
|         // Create Deployment
 |         // Create Deployment
 | ||||||
|         Deployment::create([ |         Deployment::create([ | ||||||
|   | |||||||
| @@ -3,16 +3,12 @@ | |||||||
| namespace App\Http\Livewire; | namespace App\Http\Livewire; | ||||||
| 
 | 
 | ||||||
| use Livewire\Component; | use Livewire\Component; | ||||||
| use Spatie\Activitylog\Models\Activity; |  | ||||||
| 
 | 
 | ||||||
| class PollActivity extends Component | class PollActivity extends Component | ||||||
| { | { | ||||||
|     public $activity; |     public $activity; | ||||||
|     public $activity_log_id; |  | ||||||
|     public $isKeepAliveOn = true; |     public $isKeepAliveOn = true; | ||||||
|     public function mount() { | 
 | ||||||
|         $this->activity = Activity::find($this->activity_log_id); |  | ||||||
|     } |  | ||||||
|     public function polling() |     public function polling() | ||||||
|     { |     { | ||||||
|         $this->activity?->refresh(); |         $this->activity?->refresh(); | ||||||
|   | |||||||
| @@ -19,11 +19,13 @@ class RunCommand extends Component | |||||||
| 
 | 
 | ||||||
|     public $servers = []; |     public $servers = []; | ||||||
| 
 | 
 | ||||||
|  |     protected $rules = [ | ||||||
|  |         'server' => 'required', | ||||||
|  |     ]; | ||||||
|     public function mount() |     public function mount() | ||||||
|     { |     { | ||||||
|         $this->servers = Server::all()->pluck('name')->toArray(); |         $this->servers = Server::all(); | ||||||
|         $this->server = $this->servers[0]; |         $this->server = $this->servers[0]->uuid; | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
|     public function render() |     public function render() | ||||||
|     { |     { | ||||||
| @@ -33,25 +35,19 @@ class RunCommand extends Component | |||||||
|     public function runCommand() |     public function runCommand() | ||||||
|     { |     { | ||||||
|         $this->isKeepAliveOn = true; |         $this->isKeepAliveOn = true; | ||||||
| 
 |         $this->activity = remoteProcess([$this->command], Server::where('uuid', $this->server)->first()); | ||||||
|         $this->activity = remoteProcess($this->command, $this->server); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function runSleepingBeauty() |     public function runSleepingBeauty() | ||||||
|     { |     { | ||||||
|         $this->isKeepAliveOn = true; |         $this->isKeepAliveOn = true; | ||||||
| 
 |         $this->activity = remoteProcess(['x=1; while  [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done'], Server::where('uuid', $this->server)->first()); | ||||||
|         $this->activity = remoteProcess('x=1; while  [ $x -le 40 ]; do sleep 0.1 && echo "Welcome $x times" $(( x++ )); done', $this->server); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function runDummyProjectBuild() |     public function runDummyProjectBuild() | ||||||
|     { |     { | ||||||
|         $this->isKeepAliveOn = true; |         $this->isKeepAliveOn = true; | ||||||
| 
 |         $this->activity = remoteProcess([' cd projects/dummy-project', 'docker-compose build --no-cache'], Server::where('uuid', $this->server)->first()); | ||||||
|         $this->activity = remoteProcess(<<<EOT |  | ||||||
|         cd projects/dummy-project |  | ||||||
|         ~/.docker/cli-plugins/docker-compose build --no-cache |  | ||||||
|         EOT, $this->server); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public function polling() |     public function polling() | ||||||
|   | |||||||
| @@ -2,6 +2,8 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Models; | namespace App\Models; | ||||||
| 
 | 
 | ||||||
|  | use Spatie\Activitylog\Models\Activity; | ||||||
|  | 
 | ||||||
| class Application extends BaseModel | class Application extends BaseModel | ||||||
| { | { | ||||||
|     public function environment() |     public function environment() | ||||||
| @@ -20,8 +22,9 @@ class Application extends BaseModel | |||||||
|     { |     { | ||||||
|         return $this->morphTo(); |         return $this->morphTo(); | ||||||
|     } |     } | ||||||
|     public function deployments() | 
 | ||||||
|  |     public function get_deployment(string $deployment_uuid) | ||||||
|     { |     { | ||||||
|         return $this->morphMany(Deployment::class, 'type'); |         return Activity::where('subject_id', $this->id)->where('properties->deployment_uuid', '=', $deployment_uuid)->first(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| use App\Actions\RemoteProcess\DispatchRemoteProcess; | use App\Actions\RemoteProcess\DispatchRemoteProcess; | ||||||
| use App\Data\RemoteProcessArgs; | use App\Data\RemoteProcessArgs; | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
|  | use Illuminate\Database\Eloquent\Model; | ||||||
| use Illuminate\Support\Facades\Storage; | use Illuminate\Support\Facades\Storage; | ||||||
| use Spatie\Activitylog\Contracts\Activity; | use Spatie\Activitylog\Contracts\Activity; | ||||||
| 
 | 
 | ||||||
| @@ -13,36 +14,33 @@ if (!function_exists('remoteProcess')) { | |||||||
|      * |      * | ||||||
|      */ |      */ | ||||||
|     function remoteProcess( |     function remoteProcess( | ||||||
|         string    $command, |         array           $command, | ||||||
|         string    $destination |         Server          $server, | ||||||
|  |         string|null     $deployment_uuid = null, | ||||||
|  |         Model|null      $model = null, | ||||||
|     ): Activity { |     ): Activity { | ||||||
|         $found_server = checkServer($destination); |         $command_string = implode("\n", $command); | ||||||
|         checkTeam($found_server->team_id); |         // @TODO: Check if the user has access to this server
 | ||||||
|  |         // checkTeam($server->team_id);
 | ||||||
| 
 | 
 | ||||||
|         $temp_file = 'id.rsa_' . 'root' . '@' . $found_server->ip; |         $temp_file = 'id.rsa_' . 'root' . '@' . $server->ip; | ||||||
|         Storage::disk('local')->put($temp_file, $found_server->privateKey->private_key, 'private'); |         Storage::disk('local')->put($temp_file, $server->privateKey->private_key, 'private'); | ||||||
|         $private_key_location = '/var/www/html/storage/app/' . $temp_file; |         $private_key_location = '/var/www/html/storage/app/' . $temp_file; | ||||||
|  | 
 | ||||||
|         return resolve(DispatchRemoteProcess::class, [ |         return resolve(DispatchRemoteProcess::class, [ | ||||||
|             'remoteProcessArgs' => new RemoteProcessArgs( |             'remoteProcessArgs' => new RemoteProcessArgs( | ||||||
|                 destination: $found_server->ip, |                 model: $model, | ||||||
|  |                 server_ip: $server->ip, | ||||||
|  |                 deployment_uuid: $deployment_uuid, | ||||||
|                 private_key_location: $private_key_location, |                 private_key_location: $private_key_location, | ||||||
|                 command: <<<EOT |                 command: <<<EOT | ||||||
|                 {$command} |                 {$command_string} | ||||||
|                 EOT, |                 EOT, | ||||||
|                 port: $found_server->port, |                 port: $server->port, | ||||||
|                 user: $found_server->user, |                 user: $server->user, | ||||||
|             ), |             ), | ||||||
|         ])(); |         ])(); | ||||||
|     } |     } | ||||||
|     function checkServer(string $destination) |  | ||||||
|     { |  | ||||||
|         // @TODO: Use UUID instead of name
 |  | ||||||
|         $found_server = Server::where('name', $destination)->first(); |  | ||||||
|         if (!$found_server) { |  | ||||||
|             throw new \RuntimeException('Server not found.'); |  | ||||||
|         }; |  | ||||||
|         return $found_server; |  | ||||||
|     } |  | ||||||
|     function checkTeam(string $team_id) |     function checkTeam(string $team_id) | ||||||
|     { |     { | ||||||
|         $found_team = auth()->user()->teams->pluck('id')->contains($team_id); |         $found_team = auth()->user()->teams->pluck('id')->contains($team_id); | ||||||
|   | |||||||
| @@ -37,7 +37,7 @@ class ServerSeeder extends Seeder | |||||||
|             'id' => 3, |             'id' => 3, | ||||||
|             'name' => "localhost", |             'name' => "localhost", | ||||||
|             'description' => "This is the local machine", |             'description' => "This is the local machine", | ||||||
|             'user' => 'andrasbacsai', |             'user' => 'root', | ||||||
|             'ip' => "172.17.0.1", |             'ip' => "172.17.0.1", | ||||||
|             'team_id' => $root_team->id, |             'team_id' => $root_team->id, | ||||||
|             'private_key_id' => $private_key_1->id, |             'private_key_id' => $private_key_1->id, | ||||||
|   | |||||||
| @@ -1,8 +1,5 @@ | |||||||
| <div> | <div> | ||||||
|     @isset($activity?->id) |     @isset($activity?->id) | ||||||
|         <div> |  | ||||||
|             Activity: <span>{{ $activity?->id ?? 'waiting' }}</span> |  | ||||||
|         </div> |  | ||||||
|         <pre style="width: 100%;overflow-y: scroll;" @if ($isKeepAliveOn) wire:poll.750ms="polling" @endif>{{ data_get($activity, 'description') }}</pre> |         <pre style="width: 100%;overflow-y: scroll;" @if ($isKeepAliveOn) wire:poll.750ms="polling" @endif>{{ data_get($activity, 'description') }}</pre> | ||||||
|     @endisset |     @endisset | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
|             <input autofocus id="command" wire:model.defer="command" type="text" wire:keydown.enter="runCommand" /> |             <input autofocus id="command" wire:model.defer="command" type="text" wire:keydown.enter="runCommand" /> | ||||||
|             <select wire:model.defer="server"> |             <select wire:model.defer="server"> | ||||||
|                 @foreach ($servers as $server) |                 @foreach ($servers as $server) | ||||||
|                     <option value="{{ $server }}">{{ $server }}</option> |                     <option value="{{ $server->uuid }}">{{ $server->name }}</option> | ||||||
|                 @endforeach |                 @endforeach | ||||||
|             </select> |             </select> | ||||||
|         </label> |         </label> | ||||||
| @@ -21,13 +21,6 @@ | |||||||
|         @endif |         @endif | ||||||
|     </div> |     </div> | ||||||
|     @isset($activity?->id) |     @isset($activity?->id) | ||||||
|         <div> |  | ||||||
|             Activity: <span>{{ $activity?->id ?? 'waiting' }}</span> |  | ||||||
|         </div> |  | ||||||
|         <pre style="width: 100%;overflow-y: scroll;" @if ($isKeepAliveOn || $manualKeepAlive) wire:poll.750ms="polling" @endif>{{ data_get($activity, 'description') }}</pre> |         <pre style="width: 100%;overflow-y: scroll;" @if ($isKeepAliveOn || $manualKeepAlive) wire:poll.750ms="polling" @endif>{{ data_get($activity, 'description') }}</pre> | ||||||
|         {{-- <div> |  | ||||||
|             <div>Details:</div> |  | ||||||
|             <pre style="width: 100%;overflow-y: scroll;">{{ json_encode(data_get($activity, 'properties'), JSON_PRETTY_PRINT) }}</pre> |  | ||||||
|         </div> --}} |  | ||||||
|     @endisset |     @endisset | ||||||
| </div> | </div> | ||||||
|   | |||||||
| @@ -3,6 +3,5 @@ | |||||||
|     <p>Name: {{ $project->name }}</p> |     <p>Name: {{ $project->name }}</p> | ||||||
|     <p>UUID: {{ $project->uuid }}</p> |     <p>UUID: {{ $project->uuid }}</p> | ||||||
| 
 | 
 | ||||||
|     <p>Deployment UUID: {{ $deployment->uuid }}</p> |     <livewire:poll-activity :activity="$activity" /> | ||||||
|     <livewire:poll-activity :activity_log_id="$deployment->activity_log_id" /> |  | ||||||
| </x-layout> | </x-layout> | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| <?php | <?php | ||||||
| 
 | 
 | ||||||
|  | use App\Models\Server; | ||||||
| use Tests\Support\Output; | use Tests\Support\Output; | ||||||
| 
 | 
 | ||||||
| it('starts a docker container correctly', function () { | it('starts a docker container correctly', function () { | ||||||
| @@ -10,23 +11,23 @@ it('starts a docker container correctly', function () { | |||||||
| 
 | 
 | ||||||
|     // Generate a known name
 |     // Generate a known name
 | ||||||
|     $containerName = 'coolify_test_' . now()->format('Ymd_his'); |     $containerName = 'coolify_test_' . now()->format('Ymd_his'); | ||||||
|     $host = 'testing-host'; |     $host = Server::where('name', 'testing-local-docker-container')->first(); | ||||||
| 
 | 
 | ||||||
|     // Assert there's no containers start with coolify_test_*
 |     // Assert there's no containers start with coolify_test_*
 | ||||||
|     $activity = remoteProcess($areThereCoolifyTestContainers, $host); |     $activity = remoteProcess([$areThereCoolifyTestContainers], $host); | ||||||
|     $containers = Output::containerList($activity->getExtraProperty('stdout')); |     $containers = Output::containerList($activity->getExtraProperty('stdout')); | ||||||
|     expect($containers)->toBeEmpty(); |     expect($containers)->toBeEmpty(); | ||||||
| 
 | 
 | ||||||
|     // start a container nginx -d --name = $containerName
 |     // start a container nginx -d --name = $containerName
 | ||||||
|     $activity = remoteProcess("docker run -d --rm --name {$containerName} nginx", $host); |     $activity = remoteProcess(["docker run -d --rm --name {$containerName} nginx"], $host); | ||||||
|     expect($activity->getExtraProperty('exitCode'))->toBe(0); |     expect($activity->getExtraProperty('exitCode'))->toBe(0); | ||||||
| 
 | 
 | ||||||
|     // docker ps name = $container
 |     // docker ps name = $container
 | ||||||
|     $activity = remoteProcess($areThereCoolifyTestContainers, $host); |     $activity = remoteProcess([$areThereCoolifyTestContainers], $host); | ||||||
|     $containers = Output::containerList($activity->getExtraProperty('stdout')); |     $containers = Output::containerList($activity->getExtraProperty('stdout')); | ||||||
|     expect($containers->where('Names', $containerName)->count())->toBe(1); |     expect($containers->where('Names', $containerName)->count())->toBe(1); | ||||||
| 
 | 
 | ||||||
|     // Stop testing containers
 |     // Stop testing containers
 | ||||||
|     $activity = remoteProcess("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); |     expect($activity->getExtraProperty('exitCode'))->toBe(0); | ||||||
| }); | }); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Andras Bacsai
					Andras Bacsai