diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index a16164ffc..b0c513a33 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -192,8 +192,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $this->preserveRepository = $this->application->settings->is_preserve_repository_enabled; $this->basedir = $this->application->generateBaseDir($this->deployment_uuid); - $this->workdir = "{$this->basedir}".rtrim($this->application->base_directory, '/'); - $this->configuration_dir = application_configuration_dir()."/{$this->application->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->container_name = generateApplicationContainerName($this->application, $this->pull_request_id); @@ -402,13 +402,13 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue if (data_get($this->application, 'docker_compose_custom_start_command')) { $this->docker_compose_custom_start_command = $this->application->docker_compose_custom_start_command; if (! str($this->docker_compose_custom_start_command)->contains('--project-directory')) { - $this->docker_compose_custom_start_command = str($this->docker_compose_custom_start_command)->replaceFirst('compose', 'compose --project-directory '.$this->workdir)->value(); + $this->docker_compose_custom_start_command = str($this->docker_compose_custom_start_command)->replaceFirst('compose', 'compose --project-directory ' . $this->workdir)->value(); } } if (data_get($this->application, 'docker_compose_custom_build_command')) { $this->docker_compose_custom_build_command = $this->application->docker_compose_custom_build_command; if (! str($this->docker_compose_custom_build_command)->contains('--project-directory')) { - $this->docker_compose_custom_build_command = str($this->docker_compose_custom_build_command)->replaceFirst('compose', 'compose --project-directory '.$this->workdir)->value(); + $this->docker_compose_custom_build_command = str($this->docker_compose_custom_build_command)->replaceFirst('compose', 'compose --project-directory ' . $this->workdir)->value(); } } if ($this->pull_request_id === 0) { @@ -422,7 +422,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue if ($this->preserveRepository) { foreach ($this->application->fileStorages as $fileStorage) { $path = $fileStorage->fs_path; - $saveName = 'file_stat_'.$fileStorage->id; + $saveName = 'file_stat_' . $fileStorage->id; $realPathInGit = str($path)->replace($this->application->workdir(), $this->workdir)->value(); // check if the file is a directory or a file inside the repository $this->execute_remote_command( @@ -443,7 +443,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $fileStorage->deleteStorageOnServer(); $fileStorage->saveStorageOnServer(); } - } } } @@ -476,7 +475,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } $this->docker_compose_base64 = base64_encode($yaml); $this->execute_remote_command([ - executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d | tee {$this->workdir}{$this->docker_compose_location} > /dev/null"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "echo '{$this->docker_compose_base64}' | base64 -d | tee {$this->workdir}{$this->docker_compose_location} > /dev/null"), + 'hidden' => true, ]); // Build new container to limit downtime. $this->application_deployment_queue->addLogEntry('Pulling & building required images.'); @@ -506,9 +506,13 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue // TODO } else { $this->execute_remote_command([ - "docker network inspect '{$networkId}' >/dev/null 2>&1 || docker network create --attachable '{$networkId}' >/dev/null || true", 'hidden' => true, 'ignore_errors' => true, + "docker network inspect '{$networkId}' >/dev/null 2>&1 || docker network create --attachable '{$networkId}' >/dev/null || true", + 'hidden' => true, + 'ignore_errors' => true, ], [ - "docker network connect {$networkId} coolify-proxy || true", 'hidden' => true, 'ignore_errors' => true, + "docker network connect {$networkId} coolify-proxy || true", + 'hidden' => true, + 'ignore_errors' => true, ]); } @@ -561,7 +565,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue ); $this->write_deployment_configurations(); } - } } @@ -737,14 +740,15 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue return; } - ray('push_to_docker_registry noww: '.$this->production_image_name); + ray('push_to_docker_registry noww: ' . $this->production_image_name); try { instant_remote_process(["docker images --format '{{json .}}' {$this->production_image_name}"], $this->server); $this->application_deployment_queue->addLogEntry('----------------------------------------'); $this->application_deployment_queue->addLogEntry("Pushing image to docker registry ({$this->production_image_name})."); $this->execute_remote_command( [ - executeInDocker($this->deployment_uuid, "docker push {$this->production_image_name}"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "docker push {$this->production_image_name}"), + 'hidden' => true, ], ); if ($this->application->docker_registry_image_tag) { @@ -752,10 +756,14 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $this->application_deployment_queue->addLogEntry("Tagging and pushing image with {$this->application->docker_registry_image_tag} tag."); $this->execute_remote_command( [ - 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 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, + executeInDocker($this->deployment_uuid, "docker push {$this->application->docker_registry_image_name}:{$this->application->docker_registry_image_tag}"), + 'ignore_errors' => true, + 'hidden' => true, ], ); } @@ -852,14 +860,20 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue 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', + "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, + "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', + "docker images -q {$this->production_image_name} 2>/dev/null", + 'hidden' => true, + 'save' => 'local_image_found', ]); } } @@ -892,12 +906,14 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } if ($this->application->environment_variables_preview->where('key', 'COOLIFY_FQDN')->isEmpty()) { $envs->push("COOLIFY_FQDN={$this->preview->fqdn}"); + $envs->push("COOLIFY_DOMAIN_URL={$this->preview->fqdn}"); } if ($this->application->environment_variables_preview->where('key', 'COOLIFY_URL')->isEmpty()) { $url = str($this->preview->fqdn)->replace('http://', '')->replace('https://', ''); $envs->push("COOLIFY_URL={$url}"); + $envs->push("COOLIFY_DOMAIN_FQDN={$url}"); } - if ($this->application->compose_parsing_version === '1' || $this->application->compose_parsing_version === '2') { + if ($this->application->build_pack !== 'dockercompose' || $this->application->compose_parsing_version === '1' || $this->application->compose_parsing_version === '2') { if ($this->application->environment_variables_preview->where('key', 'COOLIFY_BRANCH')->isEmpty()) { $envs->push("COOLIFY_BRANCH={$local_branch}"); } @@ -911,12 +927,12 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $real_value = $env->real_value; } else { if ($env->is_literal || $env->is_multiline) { - $real_value = '\''.$real_value.'\''; + $real_value = '\'' . $real_value . '\''; } else { $real_value = escapeEnvVariables($env->real_value); } } - $envs->push($env->key.'='.$real_value); + $envs->push($env->key . '=' . $real_value); } // Add PORT if not exists, use the first port as default if ($this->build_pack !== 'dockercompose') { @@ -940,12 +956,14 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } if ($this->application->environment_variables->where('key', 'COOLIFY_FQDN')->isEmpty()) { $envs->push("COOLIFY_FQDN={$this->application->fqdn}"); + $envs->push("COOLIFY_DOMAIN_URL={$this->application->fqdn}"); } if ($this->application->environment_variables->where('key', 'COOLIFY_URL')->isEmpty()) { $url = str($this->application->fqdn)->replace('http://', '')->replace('https://', ''); $envs->push("COOLIFY_URL={$url}"); + $envs->push("COOLIFY_DOMAIN_FQDN={$url}"); } - if ($this->application->compose_parsing_version === '1' || $this->application->compose_parsing_version === '2') { + if ($this->application->build_pack !== 'dockercompose' || $this->application->compose_parsing_version === '1' || $this->application->compose_parsing_version === '2') { if ($this->application->environment_variables->where('key', 'COOLIFY_BRANCH')->isEmpty()) { $envs->push("COOLIFY_BRANCH={$local_branch}"); } @@ -959,12 +977,12 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $real_value = $env->real_value; } else { if ($env->is_literal || $env->is_multiline) { - $real_value = '\''.$real_value.'\''; + $real_value = '\'' . $real_value . '\''; } else { $real_value = escapeEnvVariables($env->real_value); } } - $envs->push($env->key.'='.$real_value); + $envs->push($env->key . '=' . $real_value); } // Add PORT if not exists, use the first port as default if ($this->build_pack !== 'dockercompose') { @@ -1331,7 +1349,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue destination: $destination, no_questions_asked: true, ); - $this->application_deployment_queue->addLogEntry("Deployment to {$server->name}. Logs: ".route('project.application.deployment.show', [ + $this->application_deployment_queue->addLogEntry("Deployment to {$server->name}. Logs: " . route('project.application.deployment.show', [ 'project_uuid' => data_get($this->application, 'environment.project.uuid'), 'application_uuid' => data_get($this->application, 'uuid'), 'deployment_uuid' => $deployment_uuid, @@ -1411,7 +1429,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } $this->execute_remote_command( [ - $importCommands, 'hidden' => true, + $importCommands, + 'hidden' => true, ] ); $this->create_workdir(); @@ -1621,7 +1640,10 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue // Check for custom HEALTHCHECK if ($this->application->build_pack === 'dockerfile' || $this->application->dockerfile) { $this->execute_remote_command([ - executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), 'hidden' => true, 'save' => 'dockerfile_from_repo', 'ignore_errors' => true, + executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), + 'hidden' => true, + 'save' => 'dockerfile_from_repo', + 'ignore_errors' => true, ]); $dockerfile = collect(str($this->saved_outputs->get('dockerfile_from_repo'))->trim()->explode("\n")); $this->application->parseHealthcheckFromDockerfile($dockerfile); @@ -1664,27 +1686,27 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue 'CMD-SHELL', $this->generate_healthcheck_commands(), ], - 'interval' => $this->application->health_check_interval.'s', - 'timeout' => $this->application->health_check_timeout.'s', + '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', + 'start_period' => $this->application->health_check_start_period . 's', ]; if (! is_null($this->application->limits_cpuset)) { - data_set($docker_compose, 'services.'.$this->container_name.'.cpuset', $this->application->limits_cpuset); + data_set($docker_compose, 'services.' . $this->container_name . '.cpuset', $this->application->limits_cpuset); } if ($this->server->isSwarm()) { - data_forget($docker_compose, 'services.'.$this->container_name.'.container_name'); - data_forget($docker_compose, 'services.'.$this->container_name.'.expose'); - data_forget($docker_compose, 'services.'.$this->container_name.'.restart'); + data_forget($docker_compose, 'services.' . $this->container_name . '.container_name'); + data_forget($docker_compose, 'services.' . $this->container_name . '.expose'); + data_forget($docker_compose, 'services.' . $this->container_name . '.restart'); - data_forget($docker_compose, 'services.'.$this->container_name.'.mem_limit'); - data_forget($docker_compose, 'services.'.$this->container_name.'.memswap_limit'); - data_forget($docker_compose, 'services.'.$this->container_name.'.mem_swappiness'); - data_forget($docker_compose, 'services.'.$this->container_name.'.mem_reservation'); - data_forget($docker_compose, 'services.'.$this->container_name.'.cpus'); - data_forget($docker_compose, 'services.'.$this->container_name.'.cpuset'); - data_forget($docker_compose, 'services.'.$this->container_name.'.cpu_shares'); + data_forget($docker_compose, 'services.' . $this->container_name . '.mem_limit'); + data_forget($docker_compose, 'services.' . $this->container_name . '.memswap_limit'); + data_forget($docker_compose, 'services.' . $this->container_name . '.mem_swappiness'); + data_forget($docker_compose, 'services.' . $this->container_name . '.mem_reservation'); + data_forget($docker_compose, 'services.' . $this->container_name . '.cpus'); + data_forget($docker_compose, 'services.' . $this->container_name . '.cpuset'); + data_forget($docker_compose, 'services.' . $this->container_name . '.cpu_shares'); $docker_compose['services'][$this->container_name]['deploy'] = [ 'mode' => 'replicated', @@ -1753,20 +1775,20 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue } } if ($this->application->isHealthcheckDisabled()) { - data_forget($docker_compose, 'services.'.$this->container_name.'.healthcheck'); + data_forget($docker_compose, 'services.' . $this->container_name . '.healthcheck'); } if (count($this->application->ports_mappings_array) > 0 && $this->pull_request_id === 0) { $docker_compose['services'][$this->container_name]['ports'] = $this->application->ports_mappings_array; } if (count($persistent_storages) > 0) { - if (! data_get($docker_compose, 'services.'.$this->container_name.'.volumes')) { + if (! data_get($docker_compose, 'services.' . $this->container_name . '.volumes')) { $docker_compose['services'][$this->container_name]['volumes'] = []; } $docker_compose['services'][$this->container_name]['volumes'] = array_merge($docker_compose['services'][$this->container_name]['volumes'], $persistent_storages); } if (count($persistent_file_volumes) > 0) { - if (! data_get($docker_compose, 'services.'.$this->container_name.'.volumes')) { + if (! data_get($docker_compose, 'services.' . $this->container_name . '.volumes')) { $docker_compose['services'][$this->container_name]['volumes'] = []; } $docker_compose['services'][$this->container_name]['volumes'] = array_merge($docker_compose['services'][$this->container_name]['volumes'], $persistent_file_volumes->map(function ($item) { @@ -1834,9 +1856,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $volume_name = $persistentStorage->name; } if ($this->pull_request_id !== 0) { - $volume_name = $volume_name.'-pr-'.$this->pull_request_id; + $volume_name = $volume_name . '-pr-' . $this->pull_request_id; } - $local_persistent_volumes[] = $volume_name.':'.$persistentStorage->mount_path; + $local_persistent_volumes[] = $volume_name . ':' . $persistentStorage->mount_path; } return $local_persistent_volumes; @@ -1852,7 +1874,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $name = $persistentStorage->name; if ($this->pull_request_id !== 0) { - $name = $name.'-pr-'.$this->pull_request_id; + $name = $name . '-pr-' . $this->pull_request_id; } $local_persistent_volumes_names[$name] = [ @@ -1894,7 +1916,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $this->application_deployment_queue->addLogEntry("Pulling latest image ($image) from the registry."); $this->execute_remote_command( [ - executeInDocker($this->deployment_uuid, "docker pull {$image}"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "docker pull {$image}"), + 'hidden' => true, ] ); } @@ -1944,12 +1967,14 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); $this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d | tee /artifacts/thegameplan.json > /dev/null"), 'hidden' => true]); if ($this->force_rebuild) { $this->execute_remote_command([ - executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --no-cache --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --no-cache --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"), + 'hidden' => true, ]); $build_command = "docker build --no-cache {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->build_image_name} {$this->workdir}"; } else { $this->execute_remote_command([ - executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"), + 'hidden' => true, ]); $build_command = "docker build {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->build_image_name} {$this->workdir}"; } @@ -1957,10 +1982,12 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); $base64_build_command = base64_encode($build_command); $this->execute_remote_command( [ - executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), + 'hidden' => true, ], [ - executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), 'hidden' => true, + executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), + 'hidden' => true, ] ); $this->execute_remote_command([executeInDocker($this->deployment_uuid, 'rm /artifacts/thegameplan.json'), 'hidden' => true]); @@ -1974,10 +2001,12 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); } $this->execute_remote_command( [ - executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), + 'hidden' => true, ], [ - executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), 'hidden' => true, + executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), + 'hidden' => true, ] ); } @@ -2014,10 +2043,12 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d | tee {$this->workdir}/nginx.conf > /dev/null"), ], [ - executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), + 'hidden' => true, ], [ - executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), 'hidden' => true, + executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), + 'hidden' => true, ] ); } else { @@ -2031,10 +2062,12 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); $base64_build_command = base64_encode($build_command); $this->execute_remote_command( [ - executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), + 'hidden' => true, ], [ - executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), 'hidden' => true, + executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), + 'hidden' => true, ] ); } else { @@ -2043,22 +2076,26 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); $this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d | tee /artifacts/thegameplan.json > /dev/null"), 'hidden' => true]); if ($this->force_rebuild) { $this->execute_remote_command([ - executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --no-cache --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --no-cache --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"), + 'hidden' => true, ]); $build_command = "docker build --no-cache {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}"; } else { $this->execute_remote_command([ - executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"), + 'hidden' => true, ]); $build_command = "docker build {$this->addHosts} --network host -f {$this->workdir}/.nixpacks/Dockerfile {$this->build_args} --progress plain -t {$this->production_image_name} {$this->workdir}"; } $base64_build_command = base64_encode($build_command); $this->execute_remote_command( [ - executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), + 'hidden' => true, ], [ - executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), 'hidden' => true, + executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), + 'hidden' => true, ] ); $this->execute_remote_command([executeInDocker($this->deployment_uuid, 'rm /artifacts/thegameplan.json'), 'hidden' => true]); @@ -2072,10 +2109,12 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); } $this->execute_remote_command( [ - executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), 'hidden' => true, + executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"), + 'hidden' => true, ], [ - executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), 'hidden' => true, + executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'), + 'hidden' => true, ] ); } @@ -2101,7 +2140,6 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); $this->execute_remote_command( ["docker rm -f $containerName", 'hidden' => true, 'ignore_errors' => true] ); - } private function stop_running_container(bool $force = false) @@ -2114,7 +2152,7 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); $containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id); if ($this->pull_request_id === 0) { $containers = $containers->filter(function ($container) { - return data_get($container, 'Names') !== $this->container_name && data_get($container, 'Names') !== $this->container_name.'-pr-'.$this->pull_request_id; + return data_get($container, 'Names') !== $this->container_name && data_get($container, 'Names') !== $this->container_name . '-pr-' . $this->pull_request_id; }); } $containers->each(function ($container) { @@ -2179,7 +2217,9 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); 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', + executeInDocker($this->deployment_uuid, "cat {$this->workdir}{$this->dockerfile_location}"), + 'hidden' => true, + 'save' => 'dockerfile', ]); $dockerfile = collect(str($this->saved_outputs->get('dockerfile'))->trim()->explode("\n")); if ($this->pull_request_id === 0) { @@ -2219,12 +2259,13 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); foreach ($containers as $container) { $containerName = data_get($container, 'Names'); - if ($containers->count() == 1 || str_starts_with($containerName, $this->application->pre_deployment_command_container.'-'.$this->application->uuid)) { - $cmd = "sh -c '".str_replace("'", "'\''", $this->application->pre_deployment_command)."'"; + if ($containers->count() == 1 || str_starts_with($containerName, $this->application->pre_deployment_command_container . '-' . $this->application->uuid)) { + $cmd = "sh -c '" . str_replace("'", "'\''", $this->application->pre_deployment_command) . "'"; $exec = "docker exec {$containerName} {$cmd}"; $this->execute_remote_command( [ - 'command' => $exec, 'hidden' => true, + 'command' => $exec, + 'hidden' => true, ], ); @@ -2245,13 +2286,15 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); $containers = getCurrentApplicationContainerStatus($this->server, $this->application->id, $this->pull_request_id); foreach ($containers as $container) { $containerName = data_get($container, 'Names'); - if ($containers->count() == 1 || str_starts_with($containerName, $this->application->post_deployment_command_container.'-'.$this->application->uuid)) { - $cmd = "sh -c '".str_replace("'", "'\''", $this->application->post_deployment_command)."'"; + if ($containers->count() == 1 || str_starts_with($containerName, $this->application->post_deployment_command_container . '-' . $this->application->uuid)) { + $cmd = "sh -c '" . str_replace("'", "'\''", $this->application->post_deployment_command) . "'"; $exec = "docker exec {$containerName} {$cmd}"; try { $this->execute_remote_command( [ - 'command' => $exec, 'hidden' => true, 'save' => 'post-deployment-command-output', + 'command' => $exec, + 'hidden' => true, + 'save' => 'post-deployment-command-output', ], ); } catch (Exception $e) { diff --git a/app/Models/Application.php b/app/Models/Application.php index bf01353f3..db2708274 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -1089,7 +1089,7 @@ class Application extends BaseModel public function newParser(int $pull_request_id = 0, ?int $preview_id = null) { - return newParser($this, $pull_request_id, $preview_id); + // return newParser($this, $pull_request_id, $preview_id); // $pullRequestId = $pull_request_id; // $isPullRequest = $pullRequestId == 0 ? false : true; @@ -1630,7 +1630,7 @@ class Application extends BaseModel public function oldParser(int $pull_request_id = 0, ?int $preview_id = null) { if ($this->compose_parsing_version === '3') { - return $this->newParser($pull_request_id, $preview_id); + return newParser($this, $pull_request_id, $preview_id); } elseif ($this->docker_compose_raw) { return parseDockerComposeFile(resource: $this, isNew: false, pull_request_id: $pull_request_id, preview_id: $preview_id); } else { diff --git a/app/Models/Service.php b/app/Models/Service.php index d0dc6aa7c..c809daeba 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -995,10 +995,8 @@ class Service extends BaseModel instant_remote_process($commands, $this->server); } - public function newParser(): Collection + public function newParser() { - return newParser($this); - // $uuid = data_get($this, 'uuid'); // $server = data_get($this, 'destination.server'); // $compose = data_get($this, 'docker_compose_raw'); @@ -1526,7 +1524,7 @@ class Service extends BaseModel public function parse(bool $isNew = false): Collection { if ($this->compose_parsing_version === '3') { - return $this->newParser(); + return newParser($this); } elseif ($this->docker_compose_raw) { return parseDockerComposeFile($this, $isNew); } else { diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index a5d151f88..df64bc41f 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -3185,6 +3185,18 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int } // convert environment variables to one format $environment = convertComposeEnvironmentToArray($environment); + + // Add Coolify defined environments + $allEnvironments = $resource->environment_variables()->get(['key', 'value']); + + $allEnvironments = $allEnvironments->mapWithKeys(function ($item) { + return [$item['key'] => $item['value']]; + }); + + // remove $environment from $allEnvironments + $coolifyDefinedEnvironments = $allEnvironments->diffKeys($environment); + + // filter magic environments $magicEnvironments = $environment->filter(function ($value, $key) { $value = str(replaceVariables(str($value))); @@ -3258,7 +3270,7 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int } else { $value = $fqdn; } - $value = str($fqdn)->replace('http://', '')->replace('https://', '')->replace('www.', ''); + $value = str($fqdn)->replace('http://', '')->replace('https://', ''); } else { $generatedValue = generateEnvValue($valueCommand, $resource); if ($generatedValue) { @@ -3327,6 +3339,17 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int ]); } } + if ($isApplication) { + $branch = $originalResource->git_branch; + if ($pullRequestId !== 0) { + $branch = "pull/{$pullRequestId}/head"; + } + if ($originalResource->environment_variables->where('key', 'COOLIFY_BRANCH')->isEmpty()) { + ray($branch); + $environment->put('COOLIFY_BRANCH', $branch); + } + } + // Add COOLIFY_CONTAINER_NAME to environment if ($resource->environment_variables->where('key', 'COOLIFY_CONTAINER_NAME')->isEmpty()) { $environment->put('COOLIFY_CONTAINER_NAME', $containerName); @@ -3381,9 +3404,19 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int } $defaultLabels = defaultLabels($resource->id, $containerName, type: 'service', subType: $isDatabase ? 'database' : 'application', subId: $savedService->id); } + // Add COOLIFY_FQDN & COOLIFY_URL to environment + if (! $isDatabase && $fqdns?->count() > 0) { + $environment->put('COOLIFY_FQDN', $fqdns->implode(',')); + $environment->put('COOLIFY_DOMAIN_URL', $fqdns->implode(',')); + + $urls = $fqdns->map(function ($fqdn) { + return str($fqdn)->replace('http://', '')->replace('https://', ''); + }); + $environment->put('COOLIFY_URL', $urls->implode(',')); + $environment->put('COOLIFY_DOMAIN_FQDN', $urls->implode(',')); + } $serviceLabels = $labels->merge($defaultLabels); - if (! $isDatabase && $fqdns?->count() > 0) { if ($isApplication) { $shouldGenerateLabelsExactly = $resource->destination->server->settings->generate_exact_labels; @@ -3464,8 +3497,8 @@ function newParser(Application|Service $resource, int $pull_request_id = 0, ?int if ($volumesParsed->count() > 0) { $payload['volumes'] = $volumesParsed; } - if ($environment->count() > 0) { - $payload['environment'] = $environment; + if ($environment->count() > 0 || $coolifyDefinedEnvironments->count() > 0) { + $payload['environment'] = $environment->merge($coolifyDefinedEnvironments); } if ($logging) { $payload['logging'] = $logging;