diff --git a/app/Http/Livewire/Project/Application/General.php b/app/Http/Livewire/Project/Application/General.php
index 0284b40a9..da642ba77 100644
--- a/app/Http/Livewire/Project/Application/General.php
+++ b/app/Http/Livewire/Project/Application/General.php
@@ -27,6 +27,7 @@ class General extends Component
public bool $isConfigurationChanged = false;
public ?string $initialDockerComposeLocation = null;
+ public ?string $initialDockerComposePrLocation = null;
public bool $is_static;
@@ -57,6 +58,7 @@ class General extends Component
'application.docker_registry_image_tag' => 'nullable',
'application.dockerfile_location' => 'nullable',
'application.docker_compose_location' => 'nullable',
+ 'application.docker_compose_pr_location' => 'nullable',
'application.docker_compose' => 'nullable',
'application.docker_compose_raw' => 'nullable',
'application.custom_labels' => 'nullable',
@@ -84,6 +86,7 @@ class General extends Component
'application.docker_registry_image_tag' => 'Docker registry image tag',
'application.dockerfile_location' => 'Dockerfile location',
'application.docker_compose_location' => 'Docker compose location',
+ 'application.docker_compose_pr_location' => 'Docker compose location',
'application.docker_compose' => 'Docker compose',
'application.docker_compose_raw' => 'Docker compose raw',
'application.custom_labels' => 'Custom labels',
@@ -125,10 +128,11 @@ public function loadComposeFile($isInit = false)
if ($isInit && $this->application->docker_compose_raw) {
return;
}
- ['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation] = $this->application->loadComposeFile($isInit);
+ ['parsedServices' => $this->parsedServices, 'initialDockerComposeLocation' => $this->initialDockerComposeLocation, 'initialDockerComposePrLocation' => $this->initialDockerComposePrLocation] = $this->application->loadComposeFile($isInit);
$this->emit('success', 'Docker compose file loaded.');
} catch (\Throwable $e) {
$this->application->docker_compose_location = $this->initialDockerComposeLocation;
+ $this->application->docker_compose_pr_location = $this->initialDockerComposePrLocation;
$this->application->save();
return handleError($e, $this);
}
diff --git a/app/Jobs/ApplicationDeployDockerImageJob.php b/app/Jobs/ApplicationDeployDockerImageJob.php
deleted file mode 100644
index 9dfdad1f1..000000000
--- a/app/Jobs/ApplicationDeployDockerImageJob.php
+++ /dev/null
@@ -1,151 +0,0 @@
-clearAll();
- ray('Deploying Docker Image');
- static::$batch_counter = 0;
- try {
- $deploymentUuid = data_get($this->deploymentQueueEntry, 'deployment_uuid');
- $pullRequestId = data_get($this->deploymentQueueEntry, 'pull_request_id');
-
- $this->server = data_get($this->application->destination, 'server');
- $network = data_get($this->application->destination, 'network');
-
- $dockerImage = data_get($this->application, 'docker_registry_image_name');
- $dockerImageTag = data_get($this->application, 'docker_registry_image_tag');
-
- $productionImageName = str("{$dockerImage}:{$dockerImageTag}");
- $this->containerName = generateApplicationContainerName($this->application, $pullRequestId);
- savePrivateKeyToFs($this->server);
-
- ray("echo 'Starting deployment of {$productionImageName}.'");
-
- $this->deploymentQueueEntry->update([
- 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
- ]);
-
- $this->deploymentQueueEntry->addLogEntry('Starting deployment of ' . $productionImageName);
-
- $this->server->executeRemoteCommand(
- commands: collect(
- [
- [
- "name" => "ls",
- "command" => 'ls -la',
- "hidden" => true,
- ],
- [
- "name" => "pwd",
- "command" => 'pwd',
- "hidden" => true,
- ]
- ],
- ),
- loggingModel: $this->deploymentQueueEntry
- );
- $this->server->executeRemoteCommand(
- commands: prepareHelperContainer($this->server, $network, $deploymentUuid),
- loggingModel: $this->deploymentQueueEntry
- );
- $this->server->executeRemoteCommand(
- commands: generateComposeFile(
- deploymentUuid: $deploymentUuid,
- server: $this->server,
- network: $network,
- application: $this->application,
- containerName: $this->containerName,
- imageName: $productionImageName,
- pullRequestId: $pullRequestId
- ),
- loggingModel: $this->deploymentQueueEntry
- );
- $this->deploymentQueueEntry->addLogEntry('----------------------------------------');
-
- // Rolling update not possible
- if (count($this->application->ports_mappings_array) > 0) {
- $this->deploymentQueueEntry->addLogEntry('Application has ports mapped to the host system, rolling update is not supported.');
- $this->deploymentQueueEntry->addLogEntry('Stopping running container.');
- $this->server->stopApplicationRelatedRunningContainers($this->application->id, $this->containerName);
- } else {
- $this->deploymentQueueEntry->addLogEntry('Rolling update started.');
- // TODO
- $this->server->executeRemoteCommand(
- commands: startNewApplication(application: $this->application, deploymentUuid: $deploymentUuid, loggingModel: $this->deploymentQueueEntry),
- loggingModel: $this->deploymentQueueEntry
- );
- // $this->server->executeRemoteCommand(
- // commands: healthCheckContainer(application: $this->application, containerName: $this->containerName , loggingModel: $this->deploymentQueueEntry),
- // loggingModel: $this->deploymentQueueEntry
- // );
-
- }
-
- ray($this->remoteCommandOutputs);
- $this->deploymentQueueEntry->update([
- 'status' => ApplicationDeploymentStatus::FINISHED->value,
- ]);
- } catch (Throwable $e) {
- $this->fail($e);
- throw $e;
- }
- }
- public function failed(Throwable $exception): void
- {
- $this->deploymentQueueEntry->addLogEntry('Oops something is not okay, are you okay? 😢', 'error');
- $this->deploymentQueueEntry->addLogEntry($exception->getMessage(), 'error');
- $this->deploymentQueueEntry->addLogEntry('Deployment failed. Removing the new version of your application.');
-
- $this->server->executeRemoteCommand(
- commands: removeOldDeployment($this->containerName),
- loggingModel: $this->deploymentQueueEntry
- );
- $this->deploymentQueueEntry->update([
- 'status' => ApplicationDeploymentStatus::FAILED->value,
- ]);
- }
- // private function next(string $status)
- // {
- // // If the deployment is cancelled by the user, don't update the status
- // if ($this->application_deployment_queue->status !== ApplicationDeploymentStatus::CANCELLED_BY_USER->value) {
- // $this->application_deployment_queue->update([
- // 'status' => $status,
- // ]);
- // }
- // queue_next_deployment($this->application);
- // if ($status === ApplicationDeploymentStatus::FINISHED->value) {
- // $this->application->environment->project->team->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
- // }
- // if ($status === ApplicationDeploymentStatus::FAILED->value) {
- // $this->application->environment->project->team->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->preview));
- // }
- // }
-}
diff --git a/app/Jobs/ApplicationDeploySimpleDockerfileJob.php b/app/Jobs/ApplicationDeploySimpleDockerfileJob.php
deleted file mode 100644
index 0cf9f61c4..000000000
--- a/app/Jobs/ApplicationDeploySimpleDockerfileJob.php
+++ /dev/null
@@ -1,46 +0,0 @@
-applicationDeploymentQueueId = $applicationDeploymentQueueId;
- }
- public function handle()
- {
- ray('Deploying Simple Dockerfile');
- $applicationDeploymentQueue = ApplicationDeploymentQueue::find($this->applicationDeploymentQueueId);
- $application = Application::find($applicationDeploymentQueue->application_id);
- $destination = $application->destination->getMorphClass()::where('id', $application->destination->id)->first();
- $server = data_get($destination, 'server');
- $commands = collect([]);
- $commands->push(
- [
- 'command' => 'echo "Starting deployment of simple dockerfile."',
- ],
- [
- 'command' => 'ls -la',
- ]
- );
- $server->executeRemoteCommand(commands: $commands, logModel: $applicationDeploymentQueue);
- }
-}
diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php
index 36907a917..eea334c8e 100644
--- a/app/Jobs/ApplicationDeploymentJob.php
+++ b/app/Jobs/ApplicationDeploymentJob.php
@@ -456,7 +456,6 @@ private function deploy_docker_compose_buildpack()
if ($this->pull_request_id === 0) {
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->application->name}.");
} else {
- ray('asd');
$this->application_deployment_queue->addLogEntry("Starting pull request (#{$this->pull_request_id}) deployment of {$this->customRepository}:{$this->application->git_branch}.");
}
$this->server->executeRemoteCommand(
diff --git a/app/Jobs/MultipleApplicationDeploymentJob.php b/app/Jobs/MultipleApplicationDeploymentJob.php
deleted file mode 100644
index 4c3cc29c9..000000000
--- a/app/Jobs/MultipleApplicationDeploymentJob.php
+++ /dev/null
@@ -1,1164 +0,0 @@
-application_deployment_queue = ApplicationDeploymentQueue::find($application_deployment_queue_id);
- $this->log_model = $this->application_deployment_queue;
- $this->application = Application::find($this->application_deployment_queue->application_id);
- $this->build_pack = data_get($this->application, 'build_pack');
-
- $this->application_deployment_queue_id = $application_deployment_queue_id;
- $this->deployment_uuid = $this->application_deployment_queue->deployment_uuid;
- $this->commit = $this->application_deployment_queue->commit;
- $this->force_rebuild = $this->application_deployment_queue->force_rebuild;
- $this->restart_only = $this->application_deployment_queue->restart_only;
-
- $this->git_type = data_get($this->application_deployment_queue, 'git_type');
-
- $source = data_get($this->application, 'source');
- if ($source) {
- $this->source = $source->getMorphClass()::where('id', $this->application->source->id)->first();
- }
- $this->destination = $this->application->destination->getMorphClass()::where('id', $this->application->destination->id)->first();
- $this->server = $this->mainServer = $this->destination->server;
- $this->serverUser = $this->server->user;
- $this->basedir = generateBaseDir($this->deployment_uuid);
- $this->workdir = "{$this->basedir}" . rtrim($this->application->base_directory, '/');
- $this->configuration_dir = application_configuration_dir() . "/{$this->application->uuid}";
- $this->is_debug_enabled = $this->application->settings->is_debug_enabled;
- $this->saved_outputs = collect();
- $this->container_name = generateApplicationContainerName($this->application, 0);
- }
-
- public function handle(): void
- {
- savePrivateKeyToFs($this->server);
- $this->application_deployment_queue->update([
- 'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
- ]);
-
- $this->addHosts = generateHostIpMapping($this->server, $this->destination->network);
-
- if ($this->application->dockerfile_target_build) {
- $this->buildTarget = " --target {$this->application->dockerfile_target_build} ";
- }
-
- // Check custom port
- preg_match('/(?<=:)\d+(?=\/)/', $this->application->git_repository, $matches);
- if (count($matches) === 1) {
- $this->customPort = $matches[0];
- $gitHost = str($this->application->git_repository)->before(':');
- $gitRepo = str($this->application->git_repository)->after('/');
- $this->customRepository = "$gitHost:$gitRepo";
- } else {
- $this->customRepository = $this->application->git_repository;
- }
- try {
- if ($this->application->isMultipleServerDeployment()) {
- if ($this->application->build_pack === 'dockerimage') {
- $this->dockerImage = $this->application->docker_registry_image_name;
- $this->dockerImageTag = $this->application->docker_registry_image_tag;
- $this->execute_remote_command(
- [
- "echo 'Starting deployment of {$this->dockerImage}:{$this->dockerImageTag}.'"
- ],
- );
- $this->production_image_name = Str::lower("{$this->dockerImage}:{$this->dockerImageTag}");
- ray(prepareHelperContainer($this->server, $this->deployment_uuid));
- $this->execute_remote_command(
- [prepareHelperContainer($this->server, $this->deployment_uuid)]
- );
- }
- } else {
- throw new RuntimeException('Missing configuration for multiple server deployment.');
- }
- // if ($this->restart_only && $this->application->build_pack !== 'dockerimage') {
- // $this->just_restart();
- // if ($this->server->isProxyShouldRun()) {
- // dispatch(new ContainerStatusJob($this->server));
- // }
- // $this->next(ApplicationDeploymentStatus::FINISHED->value);
- // $this->application->isConfigurationChanged(true);
- // return;
- // } else if ($this->application->dockerfile) {
- // $this->deploy_simple_dockerfile();
- // } else if ($this->application->build_pack === 'dockerimage') {
- // $this->deploy_dockerimage_buildpack();
- // } else if ($this->application->build_pack === 'dockerfile') {
- // $this->deploy_dockerfile_buildpack();
- // } else if ($this->application->build_pack === 'static') {
- // $this->deploy_static_buildpack();
- // } else {
- // $this->deploy_nixpacks_buildpack();
- // }
- // if ($this->server->isProxyShouldRun()) {
- // dispatch(new ContainerStatusJob($this->server));
- // }
- // if ($this->application->docker_registry_image_name) {
- // $this->push_to_docker_registry();
- // }
- // $this->next(ApplicationDeploymentStatus::FINISHED->value);
- // $this->application->isConfigurationChanged(true);
- } catch (Exception $e) {
- $this->fail($e);
- throw $e;
- } finally {
- // if (isset($this->docker_compose_base64)) {
- // $readme = generate_readme_file($this->application->name, $this->application_deployment_queue->updated_at);
- // $composeFileName = "$this->configuration_dir/docker-compose.yml";
- // $this->execute_remote_command(
- // [
- // "mkdir -p $this->configuration_dir"
- // ],
- // [
- // "echo '{$this->docker_compose_base64}' | base64 -d > $composeFileName",
- // ],
- // [
- // "echo '{$readme}' > $this->configuration_dir/README.md",
- // ]
- // );
- // }
- // $this->execute_remote_command(
- // [
- // "docker rm -f {$this->deployment_uuid} >/dev/null 2>&1",
- // "hidden" => true,
- // "ignore_errors" => true,
- // ]
- // );
- // $this->execute_remote_command(
- // [
- // "docker image prune -f >/dev/null 2>&1",
- // "hidden" => true,
- // "ignore_errors" => true,
- // ]
- // );
- }
- }
- private function push_to_docker_registry()
- {
- try {
- instant_remote_process(["docker images --format '{{json .}}' {$this->production_image_name}"], $this->server);
- $this->execute_remote_command(
- [
- "echo '\n----------------------------------------'",
- ],
- ["echo -n 'Pushing image to docker registry ({$this->production_image_name}).'"],
- [
- executeInDocker($this->deployment_uuid, "docker push {$this->production_image_name}"), 'hidden' => true
- ],
- );
- if ($this->application->docker_registry_image_tag) {
- // Tag image with latest
- $this->execute_remote_command(
- ['echo -n "Tagging and pushing image with latest tag."'],
- [
- executeInDocker($this->deployment_uuid, "docker tag {$this->production_image_name} {$this->application->docker_registry_image_name}:{$this->application->docker_registry_image_tag}"), 'ignore_errors' => true, 'hidden' => true
- ],
- [
- executeInDocker($this->deployment_uuid, "docker push {$this->application->docker_registry_image_name}:{$this->application->docker_registry_image_tag}"), 'ignore_errors' => true, 'hidden' => true
- ],
- );
- }
- $this->execute_remote_command([
- "echo -n 'Image pushed to docker registry.'"
- ]);
- } catch (Exception $e) {
- $this->execute_remote_command(
- ["echo -n 'Failed to push image to docker registry. Please check debug logs for more information.'"],
- );
- ray($e);
- }
- }
- // private function deploy_docker_compose()
- // {
- // $dockercompose_base64 = base64_encode($this->application->dockercompose);
- // $this->execute_remote_command(
- // [
- // "echo 'Starting deployment of {$this->application->name}.'"
- // ],
- // );
- // $this->prepare_builder_image();
- // $this->execute_remote_command(
- // [
- // executeInDocker($this->deployment_uuid, "echo '$dockercompose_base64' | base64 -d > $this->workdir/docker-compose.yaml")
- // ],
- // );
- // $this->build_image_name = Str::lower("{$this->customRepository}:build");
- // $this->production_image_name = Str::lower("{$this->application->uuid}:latest");
- // $this->save_environment_variables();
- // $containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id);
- // ray($containers);
- // if ($containers->count() > 0) {
- // foreach ($containers as $container) {
- // $containerName = data_get($container, 'Names');
- // if ($containerName) {
- // instant_remote_process(
- // ["docker rm -f {$containerName}"],
- // $this->application->destination->server
- // );
- // }
- // }
- // }
-
- // $this->execute_remote_command(
- // ["echo -n 'Starting services (could take a while)...'"],
- // [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up -d"), "hidden" => true],
- // );
- // }
- private function generate_image_names()
- {
- if ($this->application->dockerfile) {
- if ($this->application->docker_registry_image_name) {
- $this->build_image_name = Str::lower("{$this->application->docker_registry_image_name}:build");
- $this->production_image_name = Str::lower("{$this->application->docker_registry_image_name}:latest");
- } else {
- $this->build_image_name = Str::lower("{$this->application->uuid}:build");
- $this->production_image_name = Str::lower("{$this->application->uuid}:latest");
- }
- } else if ($this->application->build_pack === 'dockerimage') {
- $this->production_image_name = Str::lower("{$this->dockerImage}:{$this->dockerImageTag}");
- } else {
- $this->dockerImageTag = str($this->commit)->substr(0, 128);
- if ($this->application->docker_registry_image_name) {
- $this->build_image_name = Str::lower("{$this->application->docker_registry_image_name}:{$this->dockerImageTag}-build");
- $this->production_image_name = Str::lower("{$this->application->docker_registry_image_name}:{$this->dockerImageTag}");
- } else {
- $this->build_image_name = Str::lower("{$this->application->uuid}:{$this->dockerImageTag}-build");
- $this->production_image_name = Str::lower("{$this->application->uuid}:{$this->dockerImageTag}");
- }
- }
- }
- private function just_restart()
- {
- $this->execute_remote_command(
- [
- "echo 'Starting deployment of {$this->customRepository}:{$this->application->git_branch}.'"
- ],
- );
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->set_base_dir();
- $this->generate_image_names();
- $this->check_image_locally_or_remotely();
- if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
- $this->generate_compose_file();
- $this->rolling_update();
- return;
- }
- throw new RuntimeException('Cannot find image anywhere. Please redeploy the application.');
- }
- private function check_image_locally_or_remotely()
- {
- $this->execute_remote_command([
- "docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
- ]);
- if (str($this->saved_outputs->get('local_image_found'))->isEmpty() && $this->application->docker_registry_image_name) {
- $this->execute_remote_command([
- "docker pull {$this->production_image_name} 2>/dev/null", "ignore_errors" => true, "hidden" => true
- ]);
- $this->execute_remote_command([
- "docker images -q {$this->production_image_name} 2>/dev/null", "hidden" => true, "save" => "local_image_found"
- ]);
- }
- }
- // private function save_environment_variables()
- // {
- // $envs = collect([]);
- // foreach ($this->application->environment_variables as $env) {
- // $envs->push($env->key . '=' . $env->value);
- // }
- // $envs_base64 = base64_encode($envs->implode("\n"));
- // $this->execute_remote_command(
- // [
- // executeInDocker($this->deployment_uuid, "echo '$envs_base64' | base64 -d > $this->workdir/.env")
- // ],
- // );
- // }
- private function deploy_simple_dockerfile()
- {
- $dockerfile_base64 = base64_encode($this->application->dockerfile);
- $this->execute_remote_command(
- [
- "echo 'Starting deployment of {$this->application->name}.'"
- ],
- );
- $this->prepare_builder_image();
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '$dockerfile_base64' | base64 -d > $this->workdir$this->dockerfile_location")
- ],
- );
- $this->generate_image_names();
- $this->generate_compose_file();
- $this->generate_build_env_variables();
- $this->add_build_env_variables_to_dockerfile();
- $this->build_image();
- $this->rolling_update();
- }
-
- private function deploy_dockerimage_buildpack()
- {
- // $this->dockerImage = $this->application->docker_registry_image_name;
- // $this->dockerImageTag = $this->application->docker_registry_image_tag;
- // ray("echo 'Starting deployment of {$this->dockerImage}:{$this->dockerImageTag}.'");
- // $this->execute_remote_command(
- // [
- // "echo 'Starting deployment of {$this->dockerImage}:{$this->dockerImageTag}.'"
- // ],
- // );
- // $this->generate_image_names();
- // $this->prepare_builder_image();
- $this->generate_compose_file();
- $this->rolling_update();
- }
-
- private function deploy_dockerfile_buildpack()
- {
- if (data_get($this->application, 'dockerfile_location')) {
- $this->dockerfile_location = $this->application->dockerfile_location;
- }
- $this->execute_remote_command(
- [
- "echo 'Starting deployment of {$this->customRepository}:{$this->application->git_branch}.'"
- ],
- );
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->clone_repository();
- $this->set_base_dir();
- $this->generate_image_names();
- $this->cleanup_git();
- $this->generate_compose_file();
- $this->generate_build_env_variables();
- $this->add_build_env_variables_to_dockerfile();
- $this->build_image();
- // if ($this->application->additional_destinations) {
- // $this->push_to_docker_registry();
- // $this->deploy_to_additional_destinations();
- // } else {
- $this->rolling_update();
- // }
- }
- private function deploy_nixpacks_buildpack()
- {
- $this->execute_remote_command(
- [
- "echo 'Starting deployment of {$this->customRepository}:{$this->application->git_branch}.'"
- ],
- );
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->set_base_dir();
- $this->generate_image_names();
- if (!$this->force_rebuild) {
- $this->check_image_locally_or_remotely();
- if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
- $this->execute_remote_command([
- "echo 'No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.'",
- ]);
- $this->generate_compose_file();
- $this->rolling_update();
- return;
- }
- if ($this->application->isConfigurationChanged()) {
- $this->execute_remote_command([
- "echo 'Configuration changed. Rebuilding image.'",
- ]);
- }
- }
- $this->clone_repository();
- $this->cleanup_git();
- $this->generate_nixpacks_confs();
- $this->generate_compose_file();
- $this->generate_build_env_variables();
- $this->add_build_env_variables_to_dockerfile();
- $this->build_image();
- $this->rolling_update();
- }
- private function deploy_static_buildpack()
- {
- $this->execute_remote_command(
- [
- "echo 'Starting deployment of {$this->customRepository}:{$this->application->git_branch}.'"
- ],
- );
- $this->prepare_builder_image();
- $this->check_git_if_build_needed();
- $this->set_base_dir();
- $this->generate_image_names();
- $this->clone_repository();
- $this->cleanup_git();
- $this->build_image();
- $this->generate_compose_file();
- $this->rolling_update();
- }
-
- private function rolling_update()
- {
- if (count($this->application->ports_mappings_array) > 0) {
- $this->execute_remote_command(
- [
- "echo '\n----------------------------------------'",
- ],
- ["echo -n 'Application has ports mapped to the host system, rolling update is not supported.'"],
- );
- $this->stop_running_container(force: true);
- $this->start_by_compose_file();
- } else {
- $this->execute_remote_command(
- [
- "echo '\n----------------------------------------'",
- ],
- ["echo -n 'Rolling update started.'"],
- );
- $this->start_by_compose_file();
- $this->health_check();
- $this->stop_running_container();
- }
- }
- private function health_check()
- {
- if ($this->application->isHealthcheckDisabled()) {
- $this->newVersionIsHealthy = true;
- return;
- }
- // ray('New container name: ', $this->container_name);
- if ($this->container_name) {
- $counter = 1;
- $this->execute_remote_command(
- [
- "echo 'Waiting for healthcheck to pass on the new container.'"
- ]
- );
- if ($this->full_healthcheck_url) {
- $this->execute_remote_command(
- [
- "echo 'Healthcheck URL (inside the container): {$this->full_healthcheck_url}'"
- ]
- );
- }
- while ($counter < $this->application->health_check_retries) {
- $this->execute_remote_command(
- [
- "docker inspect --format='{{json .State.Health.Status}}' {$this->container_name}",
- "hidden" => true,
- "save" => "health_check"
- ],
-
- );
- $this->execute_remote_command(
- [
- "echo 'Attempt {$counter} of {$this->application->health_check_retries} | Healthcheck status: {$this->saved_outputs->get('health_check')}'"
- ],
- );
- if (Str::of($this->saved_outputs->get('health_check'))->contains('healthy')) {
- $this->newVersionIsHealthy = true;
- $this->application->update(['status' => 'running']);
- $this->execute_remote_command(
- [
- "echo 'New container is healthy.'"
- ],
- );
- break;
- }
- $counter++;
- sleep($this->application->health_check_interval);
- }
- }
- }
-
- private function prepare_builder_image()
- {
- $helperImage = config('coolify.helper_image');
- // Get user home directory
- $this->serverUserHomeDir = instant_remote_process(["echo \$HOME"], $this->server);
- $this->dockerConfigFileExists = instant_remote_process(["test -f {$this->serverUserHomeDir}/.docker/config.json && echo 'OK' || echo 'NOK'"], $this->server);
-
- if ($this->dockerConfigFileExists === 'OK') {
- $runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v {$this->serverUserHomeDir}/.docker/config.json:/root/.docker/config.json:ro -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
- } else {
- $runCommand = "docker run -d --network {$this->destination->network} -v /:/host --name {$this->deployment_uuid} --rm -v /var/run/docker.sock:/var/run/docker.sock {$helperImage}";
- }
- $this->execute_remote_command(
- [
- "echo -n 'Preparing container with helper image: $helperImage.'",
- ],
- [
- $runCommand,
- "hidden" => true,
- ],
- [
- "command" => executeInDocker($this->deployment_uuid, "mkdir -p {$this->basedir}")
- ],
- );
- }
- private function deploy_to_additional_destinations()
- {
- $destination_ids = collect(str($this->application->additional_destinations)->explode(','));
- foreach ($destination_ids as $destination_id) {
- $destination = StandaloneDocker::find($destination_id);
- $server = $destination->server;
- if ($server->team_id !== $this->mainServer->team_id) {
- $this->execute_remote_command(
- [
- "echo -n 'Skipping deployment to {$server->name}. Not in the same team?!'",
- ],
- );
- continue;
- }
- $this->server = $server;
- $this->execute_remote_command(
- [
- "echo -n 'Deploying to {$this->server->name}.'",
- ],
- );
- $this->prepare_builder_image();
- $this->generate_image_names();
- $this->rolling_update();
- }
- }
- private function set_base_dir()
- {
- $this->execute_remote_command(
- [
- "echo -n 'Setting base directory to {$this->workdir}.'"
- ],
- );
- }
- private function check_git_if_build_needed()
- {
- $this->generate_git_import_commands();
- $private_key = data_get($this->application, 'private_key.private_key');
- if ($private_key) {
- $private_key = base64_encode($private_key);
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "mkdir -p /root/.ssh")
- ],
- [
- executeInDocker($this->deployment_uuid, "echo '{$private_key}' | base64 -d > /root/.ssh/id_rsa")
- ],
- [
- executeInDocker($this->deployment_uuid, "chmod 600 /root/.ssh/id_rsa")
- ],
- [
- executeInDocker($this->deployment_uuid, "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" git ls-remote {$this->fullRepoUrl} {$this->branch}"),
- "hidden" => true,
- "save" => "git_commit_sha"
- ],
- );
- } else {
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null\" git ls-remote {$this->fullRepoUrl} {$this->branch}"),
- "hidden" => true,
- "save" => "git_commit_sha"
- ],
- );
- }
-
- if ($this->saved_outputs->get('git_commit_sha')) {
- $this->commit = $this->saved_outputs->get('git_commit_sha')->before("\t");
- }
- }
- private function clone_repository()
- {
- $importCommands = $this->generate_git_import_commands();
- $this->execute_remote_command(
- [
- "echo '\n----------------------------------------'",
- ],
- [
- "echo -n 'Importing {$this->customRepository}:{$this->application->git_branch} (commit sha {$this->application->git_commit_sha}) to {$this->basedir}. '"
- ],
- [
- $importCommands, "hidden" => true
- ]
- );
- }
-
- private function generate_git_import_commands()
- {
- $this->branch = $this->application->git_branch;
- $commands = collect([]);
- $git_clone_command = "git clone -q -b {$this->application->git_branch}";
-
- if ($this->application->deploymentType() === 'source') {
- $source_html_url = data_get($this->application, 'source.html_url');
- $url = parse_url(filter_var($source_html_url, FILTER_SANITIZE_URL));
- $source_html_url_host = $url['host'];
- $source_html_url_scheme = $url['scheme'];
-
- if ($this->source->getMorphClass() == 'App\Models\GithubApp') {
- if ($this->source->is_public) {
- $this->fullRepoUrl = "{$this->source->html_url}/{$this->customRepository}";
- $git_clone_command = "{$git_clone_command} {$this->source->html_url}/{$this->customRepository} {$this->basedir}";
- $git_clone_command = $this->set_git_import_settings($git_clone_command);
-
- $commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
- } else {
- $github_access_token = generate_github_installation_token($this->source);
- $commands->push(executeInDocker($this->deployment_uuid, "git clone -q -b {$this->application->git_branch} $source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->customRepository}.git {$this->basedir}"));
- $this->fullRepoUrl = "$source_html_url_scheme://x-access-token:$github_access_token@$source_html_url_host/{$this->customRepository}.git";
- }
- return $commands->implode(' && ');
- }
- }
- if ($this->application->deploymentType() === 'deploy_key') {
- $this->fullRepoUrl = $this->customRepository;
- $private_key = data_get($this->application, 'private_key.private_key');
- if (is_null($private_key)) {
- throw new RuntimeException('Private key not found. Please add a private key to the application and try again.');
- }
- $private_key = base64_encode($private_key);
- $git_clone_command_base = "GIT_SSH_COMMAND=\"ssh -o ConnectTimeout=30 -p {$this->customPort} -o Port={$this->customPort} -o LogLevel=ERROR -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /root/.ssh/id_rsa\" {$git_clone_command} {$this->customRepository} {$this->basedir}";
- $git_clone_command = $this->set_git_import_settings($git_clone_command_base);
- $commands = collect([
- executeInDocker($this->deployment_uuid, "mkdir -p /root/.ssh"),
- executeInDocker($this->deployment_uuid, "echo '{$private_key}' | base64 -d > /root/.ssh/id_rsa"),
- executeInDocker($this->deployment_uuid, "chmod 600 /root/.ssh/id_rsa"),
- ]);
-
- $commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
- return $commands->implode(' && ');
- }
- if ($this->application->deploymentType() === 'other') {
- $this->fullRepoUrl = $this->customRepository;
- $git_clone_command = "{$git_clone_command} {$this->customRepository} {$this->basedir}";
- $git_clone_command = $this->set_git_import_settings($git_clone_command);
- $commands->push(executeInDocker($this->deployment_uuid, $git_clone_command));
- return $commands->implode(' && ');
- }
- }
-
- private function set_git_import_settings($git_clone_command)
- {
- if ($this->application->git_commit_sha !== 'HEAD') {
- $git_clone_command = "{$git_clone_command} && cd {$this->basedir} && git -c advice.detachedHead=false checkout {$this->application->git_commit_sha} >/dev/null 2>&1";
- }
- if ($this->application->settings->is_git_submodules_enabled) {
- $git_clone_command = "{$git_clone_command} && cd {$this->basedir} && git submodule update --init --recursive";
- }
- if ($this->application->settings->is_git_lfs_enabled) {
- $git_clone_command = "{$git_clone_command} && cd {$this->basedir} && git lfs pull";
- }
- return $git_clone_command;
- }
-
- private function cleanup_git()
- {
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "rm -fr {$this->basedir}/.git")],
- );
- }
-
- private function generate_nixpacks_confs()
- {
- $nixpacks_command = $this->nixpacks_build_cmd();
- $this->execute_remote_command(
- [
- "echo -n 'Generating nixpacks configuration with: $nixpacks_command'",
- ],
- [executeInDocker($this->deployment_uuid, $nixpacks_command)],
- [executeInDocker($this->deployment_uuid, "cp {$this->workdir}/.nixpacks/Dockerfile {$this->workdir}/Dockerfile")],
- [executeInDocker($this->deployment_uuid, "rm -f {$this->workdir}/.nixpacks/Dockerfile")]
- );
- }
-
- private function nixpacks_build_cmd()
- {
- $this->generate_env_variables();
- $nixpacks_command = "nixpacks build --cache-key '{$this->application->uuid}' -o {$this->workdir} {$this->env_args} --no-error-without-start";
- if ($this->application->build_command) {
- $nixpacks_command .= " --build-cmd \"{$this->application->build_command}\"";
- }
- if ($this->application->start_command) {
- $nixpacks_command .= " --start-cmd \"{$this->application->start_command}\"";
- }
- if ($this->application->install_command) {
- $nixpacks_command .= " --install-cmd \"{$this->application->install_command}\"";
- }
- $nixpacks_command .= " {$this->workdir}";
- return $nixpacks_command;
- }
-
- private function generate_env_variables()
- {
- $this->env_args = collect([]);
- foreach ($this->application->nixpacks_environment_variables_preview as $env) {
- $this->env_args->push("--env {$env->key}={$env->value}");
- }
- $this->env_args = $this->env_args->implode(' ');
- }
-
- private function generate_compose_file()
- {
- $ports = $this->application->settings->is_static ? [80] : $this->application->ports_exposes_array;
-
- $persistent_storages = $this->generate_local_persistent_volumes();
- $volume_names = $this->generate_local_persistent_volumes_only_volume_names();
- $environment_variables = $this->generate_environment_variables($ports);
-
- if (data_get($this->application, 'custom_labels')) {
- $labels = collect(str($this->application->custom_labels)->explode(','));
- $labels = $labels->filter(function ($value, $key) {
- return !Str::startsWith($value, 'coolify.');
- });
- $this->application->custom_labels = $labels->implode(',');
- $this->application->save();
- } else {
- $labels = collect(generateLabelsApplication($this->application, $this->preview));
- }
-
- $labels = $labels->merge(defaultLabels($this->application->id, $this->application->uuid, 0))->toArray();
- $docker_compose = [
- 'version' => '3.8',
- 'services' => [
- $this->container_name => [
- 'image' => $this->production_image_name,
- 'container_name' => $this->container_name,
- 'restart' => RESTART_MODE,
- 'environment' => $environment_variables,
- 'labels' => $labels,
- 'expose' => $ports,
- 'networks' => [
- $this->destination->network,
- ],
- 'healthcheck' => [
- 'test' => [
- 'CMD-SHELL',
- $this->generate_healthcheck_commands()
- ],
- 'interval' => $this->application->health_check_interval . 's',
- 'timeout' => $this->application->health_check_timeout . 's',
- 'retries' => $this->application->health_check_retries,
- 'start_period' => $this->application->health_check_start_period . 's'
- ],
- 'mem_limit' => $this->application->limits_memory,
- 'memswap_limit' => $this->application->limits_memory_swap,
- 'mem_swappiness' => $this->application->limits_memory_swappiness,
- 'mem_reservation' => $this->application->limits_memory_reservation,
- 'cpus' => (int) $this->application->limits_cpus,
- 'cpuset' => $this->application->limits_cpuset,
- 'cpu_shares' => $this->application->limits_cpu_shares,
- ]
- ],
- 'networks' => [
- $this->destination->network => [
- 'external' => true,
- 'name' => $this->destination->network,
- 'attachable' => true
- ]
- ]
- ];
- if ($this->server->isLogDrainEnabled() && $this->application->isLogDrainEnabled()) {
- $docker_compose['services'][$this->container_name]['logging'] = [
- 'driver' => 'fluentd',
- 'options' => [
- 'fluentd-address' => "tcp://127.0.0.1:24224",
- 'fluentd-async' => "true",
- 'fluentd-sub-second-precision' => "true",
- ]
- ];
- }
- if ($this->application->settings->is_gpu_enabled) {
- ray('asd');
- $docker_compose['services'][$this->container_name]['deploy']['resources']['reservations']['devices'] = [
- [
- 'driver' => data_get($this->application, 'settings.gpu_driver', 'nvidia'),
- 'capabilities' => ['gpu'],
- 'options' => data_get($this->application, 'settings.gpu_options', [])
- ]
- ];
- if (data_get($this->application, 'settings.gpu_count')) {
- $count = data_get($this->application, 'settings.gpu_count');
- if ($count === 'all') {
- $docker_compose['services'][$this->container_name]['deploy']['resources']['reservations']['devices'][0]['count'] = $count;
- } else {
- $docker_compose['services'][$this->container_name]['deploy']['resources']['reservations']['devices'][0]['count'] = (int) $count;
- }
- } else if (data_get($this->application, 'settings.gpu_device_ids')) {
- $docker_compose['services'][$this->container_name]['deploy']['resources']['reservations']['devices'][0]['ids'] = data_get($this->application, 'settings.gpu_device_ids');
- }
- }
- if ($this->application->isHealthcheckDisabled()) {
- data_forget($docker_compose, 'services.' . $this->container_name . '.healthcheck');
- }
- if (count($persistent_storages) > 0) {
- $docker_compose['services'][$this->container_name]['volumes'] = $persistent_storages;
- }
- if (count($volume_names) > 0) {
- $docker_compose['volumes'] = $volume_names;
- }
- // if ($this->build_pack === 'dockerfile') {
- // $docker_compose['services'][$this->container_name]['build'] = [
- // 'context' => $this->workdir,
- // 'dockerfile' => $this->workdir . $this->dockerfile_location,
- // ];
- // }
- $this->docker_compose = Yaml::dump($docker_compose, 10);
- $this->docker_compose_base64 = base64_encode($this->docker_compose);
- $this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d > {$this->workdir}/docker-compose.yml"), "hidden" => true]);
- }
-
- private function generate_local_persistent_volumes()
- {
- $local_persistent_volumes = [];
- foreach ($this->application->persistentStorages as $persistentStorage) {
- $volume_name = $persistentStorage->host_path ?? $persistentStorage->name;
- $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path;
- }
- return $local_persistent_volumes;
- }
-
- private function generate_local_persistent_volumes_only_volume_names()
- {
- $local_persistent_volumes_names = [];
- foreach ($this->application->persistentStorages as $persistentStorage) {
- if ($persistentStorage->host_path) {
- continue;
- }
- $name = $persistentStorage->name;
- $local_persistent_volumes_names[$name] = [
- 'name' => $name,
- 'external' => false,
- ];
- }
- return $local_persistent_volumes_names;
- }
-
- private function generate_environment_variables($ports)
- {
- $environment_variables = collect();
- foreach ($this->application->runtime_environment_variables_preview as $env) {
- $environment_variables->push("$env->key=$env->value");
- }
- foreach ($this->application->nixpacks_environment_variables_preview as $env) {
- $environment_variables->push("$env->key=$env->value");
- }
- // Add PORT if not exists, use the first port as default
- if ($environment_variables->filter(fn ($env) => Str::of($env)->contains('PORT'))->isEmpty()) {
- $environment_variables->push("PORT={$ports[0]}");
- }
- return $environment_variables->all();
- }
-
- private function generate_healthcheck_commands()
- {
- if ($this->application->dockerfile || $this->application->build_pack === 'dockerfile' || $this->application->build_pack === 'dockerimage') {
- // TODO: disabled HC because there are several ways to hc a simple docker image, hard to figure out a good way. Like some docker images (pocketbase) does not have curl.
- return 'exit 0';
- }
- if (!$this->application->health_check_port) {
- $health_check_port = $this->application->ports_exposes_array[0];
- } else {
- $health_check_port = $this->application->health_check_port;
- }
- if ($this->application->health_check_path) {
- $this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path}";
- $generated_healthchecks_commands = [
- "curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}{$this->application->health_check_path} > /dev/null"
- ];
- } else {
- $this->full_healthcheck_url = "{$this->application->health_check_method}: {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/";
- $generated_healthchecks_commands = [
- "curl -s -X {$this->application->health_check_method} -f {$this->application->health_check_scheme}://{$this->application->health_check_host}:{$health_check_port}/"
- ];
- }
- return implode(' ', $generated_healthchecks_commands);
- }
- private function pull_latest_image($image)
- {
- $this->execute_remote_command(
- ["echo -n 'Pulling latest image ($image) from the registry.'"],
-
- [
- executeInDocker($this->deployment_uuid, "docker pull {$image}"), "hidden" => true
- ]
- );
- }
- private function build_image()
- {
- if ($this->application->build_pack === 'static') {
- $this->execute_remote_command([
- "echo -n 'Static deployment. Copying static assets to the image.'",
- ]);
- } else {
- $this->execute_remote_command(
- [
- "echo -n 'Building docker image started.'",
- ],
- ["echo -n 'To check the current progress, click on Show Debug Logs.'"]
- );
- }
-
- if ($this->application->settings->is_static || $this->application->build_pack === 'static') {
- if ($this->application->static_image) {
- $this->pull_latest_image($this->application->static_image);
- }
- if ($this->application->build_pack === 'static') {
- $dockerfile = base64_encode("FROM {$this->application->static_image}
-WORKDIR /usr/share/nginx/html/
-LABEL coolify.deploymentId={$this->deployment_uuid}
-COPY . .
-RUN rm -f /usr/share/nginx/html/nginx.conf
-RUN rm -f /usr/share/nginx/html/Dockerfile
-COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
- $nginx_config = base64_encode("server {
- listen 80;
- listen [::]:80;
- server_name localhost;
-
- location / {
- root /usr/share/nginx/html;
- index index.html;
- try_files \$uri \$uri.html \$uri/index.html \$uri/ /index.html =404;
- }
-
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root /usr/share/nginx/html;
- }
- }");
- } else {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "docker build $this->buildTarget $this->addHosts --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->build_image_name {$this->workdir}"), "hidden" => true
- ]);
-
- $dockerfile = base64_encode("FROM {$this->application->static_image}
-WORKDIR /usr/share/nginx/html/
-LABEL coolify.deploymentId={$this->deployment_uuid}
-COPY --from=$this->build_image_name /app/{$this->application->publish_directory} .
-COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
-
- $nginx_config = base64_encode("server {
- listen 80;
- listen [::]:80;
- server_name localhost;
-
- location / {
- root /usr/share/nginx/html;
- index index.html;
- try_files \$uri \$uri.html \$uri/index.html \$uri/ /index.html =404;
- }
-
- error_page 500 502 503 504 /50x.html;
- location = /50x.html {
- root /usr/share/nginx/html;
- }
- }");
- }
- $this->execute_remote_command(
- [
- executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d > {$this->workdir}/Dockerfile")
- ],
- [
- executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d > {$this->workdir}/nginx.conf")
- ],
- [
- executeInDocker($this->deployment_uuid, "docker build $this->addHosts --network host -f {$this->workdir}/Dockerfile {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
- ]
- );
- } else {
- // Pure Dockerfile based deployment
- if ($this->application->dockerfile) {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "docker build --pull $this->buildTarget $this->addHosts --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
- ]);
- } else {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "docker build $this->buildTarget $this->addHosts --network host -f {$this->workdir}{$this->dockerfile_location} {$this->build_args} --progress plain -t $this->production_image_name {$this->workdir}"), "hidden" => true
- ]);
- }
- }
- $this->execute_remote_command([
- "echo -n 'Building docker image completed.'",
- ]);
- }
-
- private function stop_running_container(bool $force = false)
- {
- $this->execute_remote_command(["echo -n 'Removing old container.'"]);
- if ($this->newVersionIsHealthy || $force) {
- $containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, 0);
- $containers = $containers->filter(function ($container) {
- return data_get($container, 'Names') !== $this->container_name;
- });
- $containers->each(function ($container) {
- $containerName = data_get($container, 'Names');
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "docker rm -f $containerName >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true],
- );
- });
- $this->execute_remote_command(
- [
- "echo 'Rolling update completed.'"
- ],
- );
- } else {
- $this->execute_remote_command(
- ["echo -n 'New container is not healthy, rolling back to the old container.'"],
- [executeInDocker($this->deployment_uuid, "docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true],
- );
- }
- }
-
- private function start_by_compose_file()
- {
- if ($this->application->build_pack === 'dockerimage') {
- $this->execute_remote_command(
- ["echo -n 'Pulling latest images from the registry.'"],
- [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} pull"), "hidden" => true],
- [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
- );
- } else {
- $this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "docker compose --project-directory {$this->workdir} up --build -d"), "hidden" => true],
- );
- }
- }
-
- private function generate_build_env_variables()
- {
- $this->build_args = collect(["--build-arg SOURCE_COMMIT=\"{$this->commit}\""]);
- foreach ($this->application->build_environment_variables_preview as $env) {
- $this->build_args->push("--build-arg {$env->key}=\"{$env->value}\"");
- }
- $this->build_args = $this->build_args->implode(' ');
- }
-
- private function add_build_env_variables_to_dockerfile()
- {
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), "hidden" => true, "save" => 'dockerfile'
- ]);
- $dockerfile = collect(Str::of($this->saved_outputs->get('dockerfile'))->trim()->explode("\n"));
-
- foreach ($this->application->build_environment_variables as $env) {
- $dockerfile->splice(1, 0, "ARG {$env->key}={$env->value}");
- }
- $dockerfile_base64 = base64_encode($dockerfile->implode("\n"));
- $this->execute_remote_command([
- executeInDocker($this->deployment_uuid, "echo '{$dockerfile_base64}' | base64 -d > {$this->workdir}{$this->dockerfile_location}"),
- "hidden" => true
- ]);
- }
-
- private function next(string $status)
- {
- // If the deployment is cancelled by the user, don't update the status
- if ($this->application_deployment_queue->status !== ApplicationDeploymentStatus::CANCELLED_BY_USER->value) {
- $this->application_deployment_queue->update([
- 'status' => $status,
- ]);
- }
- queue_next_deployment($this->application);
- if ($status === ApplicationDeploymentStatus::FINISHED->value) {
- $this->application->environment->project->team->notify(new DeploymentSuccess($this->application, $this->deployment_uuid, $this->preview));
- }
- if ($status === ApplicationDeploymentStatus::FAILED->value) {
- $this->application->environment->project->team->notify(new DeploymentFailed($this->application, $this->deployment_uuid, $this->preview));
- }
- }
-
- public function failed(Throwable $exception): void
- {
- $this->execute_remote_command(
- ["echo 'Oops something is not okay, are you okay? 😢'", 'type' => 'err'],
- ["echo '{$exception->getMessage()}'", 'type' => 'err'],
- ["echo -n 'Deployment failed. Removing the new version of your application.'", 'type' => 'err'],
- [executeInDocker($this->deployment_uuid, "docker rm -f $this->container_name >/dev/null 2>&1"), "hidden" => true, "ignore_errors" => true]
- );
-
- $this->next(ApplicationDeploymentStatus::FAILED->value);
- }
-}
diff --git a/app/Models/Application.php b/app/Models/Application.php
index 2e58d1891..a7c721800 100644
--- a/app/Models/Application.php
+++ b/app/Models/Application.php
@@ -138,7 +138,22 @@ public function dockerComposeLocation(): Attribute
return Attribute::make(
set: function ($value) {
if (is_null($value) || $value === '') {
- return '/docker-compose.yml';
+ return '/docker-compose.yaml';
+ } else {
+ if ($value !== '/') {
+ return Str::start(Str::replaceEnd('/', '', $value), '/');
+ }
+ return Str::start($value, '/');
+ }
+ }
+ );
+ }
+ public function dockerComposePrLocation(): Attribute
+ {
+ return Attribute::make(
+ set: function ($value) {
+ if (is_null($value) || $value === '') {
+ return '/docker-compose-pr.yaml';
} else {
if ($value !== '/') {
return Str::start(Str::replaceEnd('/', '', $value), '/');
@@ -595,6 +610,7 @@ function parseCompose(int $pull_request_id = 0)
function loadComposeFile($isInit = false)
{
$initialDockerComposeLocation = $this->docker_compose_location;
+ $initialDockerComposePrLocation = $this->docker_compose_pr_location;
if ($this->build_pack === 'dockercompose') {
if ($isInit && $this->docker_compose_raw) {
return;
@@ -603,11 +619,12 @@ function loadComposeFile($isInit = false)
['commands' => $cloneCommand] = $this->generateGitImportCommands(deployment_uuid: $uuid, only_checkout: true, exec_in_docker: false, custom_base_dir: '.');
$workdir = rtrim($this->base_directory, '/');
$composeFile = $this->docker_compose_location;
+ $prComposeFile = $this->docker_compose_pr_location;
$commands = collect([
"mkdir -p /tmp/{$uuid} && cd /tmp/{$uuid}",
$cloneCommand,
"git sparse-checkout init --cone",
- "git sparse-checkout set .$workdir$composeFile",
+ "git sparse-checkout set .$workdir$composeFile .$workdir$prComposeFile",
"git read-tree -mu HEAD",
"cat .$workdir$composeFile",
]);
@@ -620,13 +637,26 @@ function loadComposeFile($isInit = false)
$this->docker_compose_raw = $composeFileContent;
$this->save();
}
+ $commands = collect([
+ "cat .$workdir$prComposeFile",
+ ]);
+ $composePrFileContent = instant_remote_process($commands, $this->destination->server, false);
+ if (!$composePrFileContent) {
+ $this->docker_compose_pr_location = $initialDockerComposePrLocation;
+ $this->save();
+ throw new \Exception("Could not load compose file from $workdir$prComposeFile");
+ } else {
+ $this->docker_compose_pr_raw = $composePrFileContent;
+ $this->save();
+ }
$commands = collect([
"rm -rf /tmp/{$uuid}",
]);
instant_remote_process($commands, $this->destination->server, false);
return [
'parsedServices' => $this->parseCompose(),
- 'initialDockerComposeLocation' => $this->docker_compose_location
+ 'initialDockerComposeLocation' => $this->docker_compose_location,
+ 'initialDockerComposePrLocation' => $this->docker_compose_pr_location,
];
}
}
diff --git a/bootstrap/helpers/applications.php b/bootstrap/helpers/applications.php
index 17c3aa486..bc0de5c47 100644
--- a/bootstrap/helpers/applications.php
+++ b/bootstrap/helpers/applications.php
@@ -36,10 +36,6 @@ function queue_application_deployment(int $application_id, string $deployment_uu
if ($running_deployments->count() > 0) {
return;
}
- // New deployment
- // dispatchDeploymentJob($deployment);
-
- // Old deployment
dispatch(new ApplicationDeploymentJob(
application_deployment_queue_id: $deployment->id,
))->onConnection('long-running')->onQueue('long-running');
@@ -50,39 +46,11 @@ function queue_next_deployment(Application $application)
{
$next_found = ApplicationDeploymentQueue::where('application_id', $application->id)->where('status', 'queued')->first();
if ($next_found) {
- // New deployment
- // dispatchDeploymentJob($next_found->id);
-
- // Old deployment
dispatch(new ApplicationDeploymentJob(
application_deployment_queue_id: $next_found->id,
))->onConnection('long-running')->onQueue('long-running');
}
}
-function dispatchDeploymentJob(ApplicationDeploymentQueue $deploymentQueueEntry)
-{
- $application = Application::find($deploymentQueueEntry->application_id);
-
- $isRestartOnly = data_get($deploymentQueueEntry, 'restart_only');
- $isSimpleDockerFile = data_get($application, 'dockerfile');
- $isDockerImage = data_get($application, 'build_pack') === 'dockerimage';
-
- // if ($isRestartOnly) {
- // ApplicationRestartJob::dispatch(queue: $deploymentQueueEntry, application: $application)->onConnection('long-running')->onQueue('long-running');
- // } else if ($isSimpleDockerFile) {
- // ApplicationDeploySimpleDockerfileJob::dispatch(applicationDeploymentQueueId: $id)->onConnection('long-running')->onQueue('long-running');
- // } else
-
- if ($isDockerImage) {
- ApplicationDeployDockerImageJob::dispatch(
- deploymentQueueEntry: $deploymentQueueEntry,
- application: $application
- )->onConnection('long-running')->onQueue('long-running');
- } else {
- throw new Exception('Unknown build pack');
- }
-}
-
// Deployment things
function generateHostIpMapping(Server $server, string $network)
{
diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php
index ecb67cd0c..fcf32d215 100644
--- a/bootstrap/helpers/shared.php
+++ b/bootstrap/helpers/shared.php
@@ -1089,11 +1089,16 @@ function parseDockerComposeFile(Service|Application $resource, bool $isNew = fal
return collect([]);
}
} else if ($resource->getMorphClass() === 'App\Models\Application') {
- try {
- $yaml = Yaml::parse($resource->docker_compose_raw);
- } catch (\Exception $e) {
- throw new \Exception($e->getMessage());
+ if ($pull_request_id !== 0 && $resource->dockerComposePrLocation() !== $resource->dockerComposeLocation()) {
+
+ } else {
+ try {
+ $yaml = Yaml::parse($resource->docker_compose_raw);
+ } catch (\Exception $e) {
+ throw new \Exception($e->getMessage());
+ }
}
+
$server = $resource->destination->server;
$topLevelVolumes = collect(data_get($yaml, 'volumes', []));
if ($pull_request_id !== 0) {
diff --git a/database/migrations/2023_11_24_080341_add_docker_compose_location.php b/database/migrations/2023_11_24_080341_add_docker_compose_location.php
index b811aa4d1..eab705ff0 100644
--- a/database/migrations/2023_11_24_080341_add_docker_compose_location.php
+++ b/database/migrations/2023_11_24_080341_add_docker_compose_location.php
@@ -12,11 +12,15 @@
public function up(): void
{
Schema::table('applications', function (Blueprint $table) {
- $table->string('docker_compose_location')->nullable()->default('/docker-compose.yml')->after('dockerfile_location');
- $table->longText('docker_compose')->nullable()->after('docker_compose_location');
- $table->longText('docker_compose_raw')->nullable()->after('docker_compose');
- $table->text('docker_compose_domains')->nullable()->after('docker_compose_raw');
+ $table->string('docker_compose_location')->nullable()->default('/docker-compose.yaml')->after('dockerfile_location');
+ $table->string('docker_compose_pr_location')->nullable()->default('/docker-compose-pr.yaml')->after('docker_compose_location');
+ $table->longText('docker_compose')->nullable()->after('docker_compose_location');
+ $table->longText('docker_compose_pr')->nullable()->after('docker_compose_location');
+ $table->longText('docker_compose_raw')->nullable()->after('docker_compose');
+ $table->longText('docker_compose_pr_raw')->nullable()->after('docker_compose');
+
+ $table->text('docker_compose_domains')->nullable()->after('docker_compose_raw');
});
}
@@ -27,8 +31,11 @@ public function down(): void
{
Schema::table('applications', function (Blueprint $table) {
$table->dropColumn('docker_compose_location');
+ $table->dropColumn('docker_compose_pr_location');
$table->dropColumn('docker_compose');
+ $table->dropColumn('docker_compose_pr');
$table->dropColumn('docker_compose_raw');
+ $table->dropColumn('docker_compose_pr_raw');
$table->dropColumn('docker_compose_domains');
});
}
diff --git a/resources/views/livewire/project/application/general.blade.php b/resources/views/livewire/project/application/general.blade.php
index 0975dbf4d..b08a9fb60 100644
--- a/resources/views/livewire/project/application/general.blade.php
+++ b/resources/views/livewire/project/application/general.blade.php
@@ -116,9 +116,12 @@
@endif
@if ($application->build_pack === 'dockercompose')
-
+
@endif
@if ($application->build_pack === 'dockerfile')