diff --git a/app/Actions/CoolifyTask/RunRemoteProcess.php b/app/Actions/CoolifyTask/RunRemoteProcess.php
index d46497450..16924476b 100644
--- a/app/Actions/CoolifyTask/RunRemoteProcess.php
+++ b/app/Actions/CoolifyTask/RunRemoteProcess.php
@@ -5,7 +5,6 @@ namespace App\Actions\CoolifyTask;
use App\Enums\ActivityTypes;
use App\Enums\ProcessStatus;
use App\Jobs\ApplicationDeploymentJob;
-use App\Jobs\ApplicationDeploymentJobNew;
use App\Models\Server;
use Illuminate\Process\ProcessResult;
use Illuminate\Support\Facades\DB;
@@ -166,23 +165,13 @@ class RunRemoteProcess
public function encodeOutput($type, $output)
{
$outputStack = json_decode($this->activity->description, associative: true, flags: JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
- if (isDev()) {
- $outputStack[] = [
- 'type' => $type,
- 'output' => $output,
- 'timestamp' => hrtime(true),
- 'batch' => ApplicationDeploymentJobNew::$batch_counter,
- 'order' => $this->getLatestCounter(),
- ];
- } else {
- $outputStack[] = [
- 'type' => $type,
- 'output' => $output,
- 'timestamp' => hrtime(true),
- 'batch' => ApplicationDeploymentJob::$batch_counter,
- 'order' => $this->getLatestCounter(),
- ];
- }
+ $outputStack[] = [
+ 'type' => $type,
+ 'output' => $output,
+ 'timestamp' => hrtime(true),
+ 'batch' => ApplicationDeploymentJob::$batch_counter,
+ 'order' => $this->getLatestCounter(),
+ ];
return json_encode($outputStack, flags: JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE);
}
diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php
index 2c49a3096..ab8794877 100644
--- a/app/Console/Kernel.php
+++ b/app/Console/Kernel.php
@@ -11,6 +11,8 @@ use App\Jobs\ContainerStatusJob;
use App\Jobs\PullHelperImageJob;
use App\Jobs\PullSentinelImageJob;
use App\Jobs\PullTemplatesAndVersions;
+use App\Jobs\PullTemplatesFromCDN;
+use App\Jobs\PullVersionsFromCDN;
use App\Jobs\ServerStatusJob;
use App\Models\InstanceSettings;
use App\Models\ScheduledDatabaseBackup;
@@ -30,7 +32,8 @@ class Kernel extends ConsoleKernel
// Instance Jobs
$schedule->command('horizon:snapshot')->everyMinute();
$schedule->job(new CleanupInstanceStuffsJob)->everyMinute()->onOneServer();
- $schedule->job(new PullTemplatesAndVersions)->everyTenMinutes()->onOneServer();
+ $schedule->job(new PullVersionsFromCDN)->everyTenMinutes()->onOneServer();
+ $schedule->job(new PullTemplatesFromCDN)->everyTwoHours()->onOneServer();
// $schedule->job(new CheckResaleLicenseJob)->hourly()->onOneServer();
// Server Jobs
$this->check_scheduled_backups($schedule);
@@ -43,7 +46,8 @@ class Kernel extends ConsoleKernel
// Instance Jobs
$schedule->command('horizon:snapshot')->everyFiveMinutes();
$schedule->command('cleanup:unreachable-servers')->daily();
- $schedule->job(new PullTemplatesAndVersions)->everyTenMinutes()->onOneServer();
+ $schedule->job(new PullVersionsFromCDN)->everyTenMinutes()->onOneServer();
+ $schedule->job(new PullTemplatesFromCDN)->everyTwoHours()->onOneServer();
$schedule->job(new CleanupInstanceStuffsJob)->everyTwoMinutes()->onOneServer();
// $schedule->job(new CheckResaleLicenseJob)->hourly()->onOneServer();
diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php
index 2009c6c7a..15259a082 100644
--- a/app/Jobs/ApplicationDeploymentJob.php
+++ b/app/Jobs/ApplicationDeploymentJob.php
@@ -67,6 +67,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
// Save original server between phases
private Server $original_server;
private Server $mainServer;
+ private bool $is_this_additional_server = false;
private ?ApplicationPreview $preview = null;
private ?string $git_type = null;
private bool $only_this_server = false;
@@ -112,6 +113,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
public $tries = 1;
public function __construct(int $application_deployment_queue_id)
{
+ ray()->clearAll();
$this->application_deployment_queue = ApplicationDeploymentQueue::find($application_deployment_queue_id);
$this->application = Application::find($this->application_deployment_queue->application_id);
$this->build_pack = data_get($this->application, 'build_pack');
@@ -123,6 +125,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->rollback = $this->application_deployment_queue->rollback;
$this->force_rebuild = $this->application_deployment_queue->force_rebuild;
$this->restart_only = $this->application_deployment_queue->restart_only;
+ $this->restart_only = $this->restart_only && $this->application->build_pack !== 'dockerimage' && $this->application->build_pack !== 'dockerfile';
$this->only_this_server = $this->application_deployment_queue->only_this_server;
$this->git_type = data_get($this->application_deployment_queue, 'git_type');
@@ -136,6 +139,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->destination = $this->server->destinations()->where('id', $this->application_deployment_queue->destination_id)->first();
$this->server = $this->mainServer = $this->destination->server;
$this->serverUser = $this->server->user;
+ $this->is_this_additional_server = $this->application->additional_servers()->wherePivot('server_id', $this->server->id)->count() > 0;
+
$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}";
@@ -149,28 +154,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
// Set preview fqdn
if ($this->pull_request_id !== 0) {
- $this->preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->application->id, $this->pull_request_id);
- if ($this->application->fqdn) {
- if (str($this->application->fqdn)->contains(',')) {
- $url = Url::fromString(str($this->application->fqdn)->explode(',')[0]);
- $preview_fqdn = getFqdnWithoutPort(str($this->application->fqdn)->explode(',')[0]);
- } else {
- $url = Url::fromString($this->application->fqdn);
- if (data_get($this->preview, 'fqdn')) {
- $preview_fqdn = getFqdnWithoutPort(data_get($this->preview, 'fqdn'));
- }
- }
- $template = $this->application->preview_url_template;
- $host = $url->getHost();
- $schema = $url->getScheme();
- $random = new Cuid2(7);
- $preview_fqdn = str_replace('{{random}}', $random, $template);
- $preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
- $preview_fqdn = str_replace('{{pr_id}}', $this->pull_request_id, $preview_fqdn);
- $preview_fqdn = "$schema://$preview_fqdn";
- $this->preview->fqdn = $preview_fqdn;
- $this->preview->save();
- }
+ $this->preview = $this->application->generate_preview_fqdn($this->pull_request_id);
if ($this->application->is_github_based()) {
ApplicationPullRequestUpdateJob::dispatch(application: $this->application, preview: $this->preview, deployment_uuid: $this->deployment_uuid, status: ProcessStatus::IN_PROGRESS);
}
@@ -284,7 +268,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
}
private function decide_what_to_do()
{
- if ($this->restart_only && $this->application->build_pack !== 'dockerimage' && $this->application->build_pack !== 'dockerfile') {
+ if ($this->restart_only) {
$this->just_restart();
return;
} else if ($this->pull_request_id !== 0) {
@@ -334,18 +318,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
],
);
$this->generate_image_names();
-
- // Always rebuild dockerfile based container.
- // if (!$this->force_rebuild) {
- // $this->check_image_locally_or_remotely();
- // if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
- // $this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
- // $this->generate_compose_file();
- // $this->push_to_docker_registry();
- // $this->rolling_update();
- // return;
- // }
- // }
$this->generate_compose_file();
$this->generate_build_env_variables();
$this->add_build_env_variables_to_dockerfile();
@@ -393,15 +365,29 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
if ($this->application->settings->is_raw_compose_deployment_enabled) {
$this->application->parseRawCompose();
$yaml = $composeFile = $this->application->docker_compose_raw;
+ $this->save_environment_variables();
} else {
$composeFile = $this->application->parseCompose(pull_request_id: $this->pull_request_id);
+ $this->save_environment_variables();
+ if (!is_null($this->env_filename)) {
+ $services = collect($composeFile['services']);
+ $services = $services->map(function ($service, $name) {
+ $service['env_file'] = [$this->env_filename];
+ return $service;
+ });
+ $composeFile['services'] = $services->toArray();
+ }
+ if (is_null($composeFile)) {
+ $this->application_deployment_queue->addLogEntry("Failed to parse docker-compose file.");
+ $this->fail("Failed to parse docker-compose file.");
+ return;
+ }
$yaml = Yaml::dump($composeFile->toArray(), 10);
}
$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
]);
- $this->save_environment_variables();
// Build new container to limit downtime.
$this->application_deployment_queue->addLogEntry("Pulling & building required images.");
@@ -410,8 +396,13 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_build_command}"), "hidden" => true],
);
} else {
+ $command = "{$this->coolify_variables} docker compose";
+ if ($this->env_filename) {
+ $command .= " --env-file {$this->workdir}/{$this->env_filename}";
+ }
+ $command .= " --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build";
$this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "{$this->coolify_variables} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build"), "hidden" => true],
+ [executeInDocker($this->deployment_uuid, $command), "hidden" => true],
);
}
@@ -441,9 +432,15 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
} else {
$this->write_deployment_configurations();
$server_workdir = $this->application->workdir();
- ray("{$this->coolify_variables} docker compose --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d");
+
+ $command = "{$this->coolify_variables} docker compose";
+ if ($this->env_filename) {
+ $command .= " --env-file {$this->workdir}/{$this->env_filename}";
+ }
+ $command .= " --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d";
+
$this->execute_remote_command(
- ["{$this->coolify_variables} docker compose --project-directory {$server_workdir} -f {$server_workdir}{$this->docker_compose_location} up -d", "hidden" => true],
+ ["command" => $command, "hidden" => true],
);
}
} else {
@@ -453,8 +450,13 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
);
$this->write_deployment_configurations();
} else {
+ $command = "{$this->coolify_variables} docker compose";
+ if ($this->env_filename) {
+ $command .= " --env-file {$this->workdir}/{$this->env_filename}";
+ }
+ $command .= " --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d";
$this->execute_remote_command(
- [executeInDocker($this->deployment_uuid, "{$this->coolify_variables} docker compose --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} up -d"), "hidden" => true],
+ [executeInDocker($this->deployment_uuid, $command), "hidden" => true],
);
$this->write_deployment_configurations();
}
@@ -473,16 +475,11 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
}
$this->prepare_builder_image();
$this->check_git_if_build_needed();
- $this->set_base_dir();
$this->generate_image_names();
$this->clone_repository();
if (!$this->force_rebuild) {
$this->check_image_locally_or_remotely();
- if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty() && !$this->application->isConfigurationChanged()) {
- $this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
- $this->generate_compose_file();
- $this->push_to_docker_registry();
- $this->rolling_update();
+ if ($this->should_skip_build()) {
return;
}
}
@@ -502,21 +499,12 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
$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->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
- $this->generate_compose_file();
- ray('pushing to docker registry');
- $this->push_to_docker_registry();
- $this->rolling_update();
+ if ($this->should_skip_build()) {
return;
}
- if ($this->application->isConfigurationChanged()) {
- $this->application_deployment_queue->addLogEntry("Configuration changed. Rebuilding image.");
- }
}
$this->clone_repository();
$this->cleanup_git();
@@ -535,15 +523,10 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->application_deployment_queue->addLogEntry("Starting deployment of {$this->customRepository}:{$this->application->git_branch} to {$this->server->name}.");
$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->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
- $this->generate_compose_file();
- $this->push_to_docker_registry();
- $this->rolling_update();
+ if ($this->should_skip_build()) {
return;
}
}
@@ -611,7 +594,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
ray('additional_servers');
$forceFail = true;
}
- if ($this->application->additional_servers()->wherePivot('server_id', $this->server->id)->count() > 0) {
+ if ($this->is_this_additional_server) {
ray('this is an additional_servers, no pushy pushy');
return;
}
@@ -626,8 +609,8 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
],
);
if ($this->application->docker_registry_image_tag) {
- // Tag image with latest
- $this->application_deployment_queue->addLogEntry("Tagging and pushing image with latest tag.");
+ // Tag image with docker_registry_image_tag
+ $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
@@ -637,7 +620,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
],
);
}
- $this->application_deployment_queue->addLogEntry("Image pushed to docker registry.");
} catch (Exception $e) {
$this->application_deployment_queue->addLogEntry("Failed to push image to docker registry. Please check debug logs for more information.");
if ($forceFail) {
@@ -668,9 +650,9 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
}
} else {
$this->dockerImageTag = str($this->commit)->substr(0, 128);
- if ($this->application->docker_registry_image_tag) {
- $this->dockerImageTag = $this->application->docker_registry_image_tag;
- }
+ // if ($this->application->docker_registry_image_tag) {
+ // $this->dockerImageTag = $this->application->docker_registry_image_tag;
+ // }
if ($this->application->docker_registry_image_name) {
$this->build_image_name = "{$this->application->docker_registry_image_name}:{$this->dockerImageTag}-build";
$this->production_image_name = "{$this->application->docker_registry_image_name}:{$this->dockerImageTag}";
@@ -685,19 +667,42 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->application_deployment_queue->addLogEntry("Restarting {$this->customRepository}:{$this->application->git_branch} on {$this->server->name}.");
$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 ($this->should_skip_build()) {
+ return;
+ }
+ }
+ private function should_skip_build()
+ {
if (str($this->saved_outputs->get('local_image_found'))->isNotEmpty()) {
- $this->application_deployment_queue->addLogEntry("Image found ({$this->production_image_name}) with the same Git Commit SHA. Restarting container.");
- $this->generate_compose_file();
- $this->rolling_update();
- $this->post_deployment();
+ if ($this->is_this_additional_server) {
+ $this->application_deployment_queue->addLogEntry("Image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
+ $this->generate_compose_file();
+ $this->push_to_docker_registry();
+ $this->rolling_update();
+ if ($this->restart_only) {
+ $this->post_deployment();
+ }
+ return true;
+ }
+ if (!$this->application->isConfigurationChanged()) {
+ $this->application_deployment_queue->addLogEntry("No configuration changed & image found ({$this->production_image_name}) with the same Git Commit SHA. Build step skipped.");
+ $this->generate_compose_file();
+ $this->push_to_docker_registry();
+ $this->rolling_update();
+ return true;
+ } else {
+ $this->application_deployment_queue->addLogEntry("Configuration changed. Rebuilding image.");
+ }
} else {
- $this->application_deployment_queue->addLogEntry("Image not found ({$this->production_image_name}). Redeploying the application.");
+ $this->application_deployment_queue->addLogEntry("Image not found ({$this->production_image_name}). Building new image.");
+ }
+ if ($this->restart_only) {
$this->restart_only = false;
$this->decide_what_to_do();
}
+ return false;
}
private function check_image_locally_or_remotely()
{
@@ -864,7 +869,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
]
);
}
-
}
}
@@ -1031,7 +1035,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
$this->prepare_builder_image();
$this->check_git_if_build_needed();
$this->clone_repository();
- $this->set_base_dir();
$this->cleanup_git();
if ($this->application->build_pack === 'nixpacks') {
$this->generate_nixpacks_confs();
@@ -1153,10 +1156,6 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted
]));
}
}
- private function set_base_dir()
- {
- $this->application_deployment_queue->addLogEntry("Setting base directory to {$this->workdir}.");
- }
private function set_coolify_variables()
{
$this->coolify_variables = "SOURCE_COMMIT={$this->commit} ";
diff --git a/app/Jobs/ApplicationDeploymentJobNew.php b/app/Jobs/ApplicationDeploymentJobNew.php
index 6c9c59b36..dedd736da 100644
--- a/app/Jobs/ApplicationDeploymentJobNew.php
+++ b/app/Jobs/ApplicationDeploymentJobNew.php
@@ -720,7 +720,6 @@ class ApplicationDeploymentJobNew implements ShouldQueue, ShouldBeEncrypted
],
);
}
- $this->application_deployment_queue->addLogEntry("Image pushed to docker registry.");
} catch (Exception $e) {
$this->application_deployment_queue->addLogEntry("Failed to push image to docker registry. Please check debug logs for more information.");
if ($forceFail) {
diff --git a/app/Jobs/PullTemplatesAndVersions.php b/app/Jobs/PullTemplatesFromCDN.php
similarity index 60%
rename from app/Jobs/PullTemplatesAndVersions.php
rename to app/Jobs/PullTemplatesFromCDN.php
index c4c2619ca..66e7611a7 100644
--- a/app/Jobs/PullTemplatesAndVersions.php
+++ b/app/Jobs/PullTemplatesFromCDN.php
@@ -12,7 +12,7 @@ use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
-class PullTemplatesAndVersions implements ShouldQueue, ShouldBeEncrypted
+class PullTemplatesFromCDN implements ShouldQueue, ShouldBeEncrypted
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
@@ -23,21 +23,6 @@ class PullTemplatesAndVersions implements ShouldQueue, ShouldBeEncrypted
}
public function handle(): void
{
- try {
- if (!isDev() && !isCloud()) {
- ray('PullTemplatesAndVersions versions.json');
- $response = Http::retry(3, 1000)->get('https://cdn.coollabs.io/coolify/versions.json');
- if ($response->successful()) {
- $versions = $response->json();
- File::put(base_path('versions.json'), json_encode($versions, JSON_PRETTY_PRINT));
- } else {
- send_internal_notification('PullTemplatesAndVersions failed with: ' . $response->status() . ' ' . $response->body());
- }
- }
- } catch (\Throwable $e) {
- send_internal_notification('PullTemplatesAndVersions failed with: ' . $e->getMessage());
- ray($e->getMessage());
- }
try {
if (!isDev()) {
ray('PullTemplatesAndVersions service-templates');
diff --git a/app/Jobs/PullVersionsFromCDN.php b/app/Jobs/PullVersionsFromCDN.php
new file mode 100644
index 000000000..0d4084a30
--- /dev/null
+++ b/app/Jobs/PullVersionsFromCDN.php
@@ -0,0 +1,41 @@
+get('https://cdn.coollabs.io/coolify/versions.json');
+ if ($response->successful()) {
+ $versions = $response->json();
+ File::put(base_path('versions.json'), json_encode($versions, JSON_PRETTY_PRINT));
+ } else {
+ send_internal_notification('PullTemplatesAndVersions failed with: ' . $response->status() . ' ' . $response->body());
+ }
+ }
+ } catch (\Throwable $e) {
+ send_internal_notification('PullTemplatesAndVersions failed with: ' . $e->getMessage());
+ ray($e->getMessage());
+ }
+ }
+}
diff --git a/app/Livewire/Project/Application/General.php b/app/Livewire/Project/Application/General.php
index 718312d2d..cca55d1b0 100644
--- a/app/Livewire/Project/Application/General.php
+++ b/app/Livewire/Project/Application/General.php
@@ -287,7 +287,7 @@ class General extends Component
if ($this->application->additional_servers->count() === 0) {
foreach ($domains as $domain) {
if (!validate_dns_entry($domain, $this->application->destination->server)) {
- $showToaster && $this->dispatch('error', "Validating DNS ($domain) failed.", "Make sure you have added the DNS records correctly.
Check this documentation for further help.");
+ $showToaster && $this->dispatch('error', "Validating DNS failed.", "Make sure you have added the DNS records correctly.
$domain->{$this->application->destination->server->ip}
Check this documentation for further help.");
}
}
}
@@ -352,7 +352,7 @@ class General extends Component
$domain = data_get($service, 'domain');
if ($domain) {
if (!validate_dns_entry($domain, $this->application->destination->server)) {
- $showToaster && $this->dispatch('error', "Validating DNS ($domain) failed.", "Make sure you have added the DNS records correctly.
Check this documentation for further help.");
+ $showToaster && $this->dispatch('error', "Validating DNS failed.", "Make sure you have added the DNS records correctly.
$domain->{$this->application->destination->server->ip}
Check this documentation for further help.");
}
check_domain_usage(resource: $this->application);
}
diff --git a/app/Livewire/Project/Application/Previews.php b/app/Livewire/Project/Application/Previews.php
index d057479ea..1f4a144a9 100644
--- a/app/Livewire/Project/Application/Previews.php
+++ b/app/Livewire/Project/Application/Previews.php
@@ -2,10 +2,12 @@
namespace App\Livewire\Project\Application;
+use App\Actions\Docker\GetContainersStatus;
use App\Models\Application;
use App\Models\ApplicationPreview;
use Illuminate\Support\Collection;
use Livewire\Component;
+use Spatie\Url\Url;
use Visus\Cuid2\Cuid2;
class Previews extends Component
@@ -16,6 +18,9 @@ class Previews extends Component
public Collection $pull_requests;
public int $rate_limit_remaining;
+ protected $rules = [
+ 'application.previews.*.fqdn' => 'string|nullable',
+ ];
public function mount()
{
$this->pull_requests = collect();
@@ -33,7 +38,71 @@ class Previews extends Component
return handleError($e, $this);
}
}
+ public function save_preview($preview_id)
+ {
+ try {
+ $success = true;
+ $preview = $this->application->previews->find($preview_id);
+ if (isset($preview->fqdn)) {
+ $preview->fqdn = str($preview->fqdn)->replaceEnd(',', '')->trim();
+ $preview->fqdn = str($preview->fqdn)->replaceStart(',', '')->trim();
+ $preview->fqdn = str($preview->fqdn)->trim()->lower();
+ if (!validate_dns_entry($preview->fqdn, $this->application->destination->server)) {
+ $this->dispatch('error', "Validating DNS failed.", "Make sure you have added the DNS records correctly.
$preview->fqdn->{$this->application->destination->server->ip}
Check this documentation for further help.");
+ $success = false;
+ }
+ check_domain_usage(resource: $this->application, domain: $preview->fqdn);
+ }
+ if (!$preview) {
+ throw new \Exception('Preview not found');
+ }
+ $success && $preview->save();
+ $success && $this->dispatch('success', 'Preview saved.
Do not forget to redeploy the preview to apply the changes.');
+ } catch (\Throwable $e) {
+ return handleError($e, $this);
+ }
+ }
+ public function generate_preview($preview_id)
+ {
+ $preview = $this->application->previews->find($preview_id);
+ if (!$preview) {
+ $this->dispatch('error', 'Preview not found.');
+ return;
+ }
+ $fqdn = generateFqdn($this->application->destination->server, $this->application->uuid);
+
+ $url = Url::fromString($fqdn);
+ $template = $this->application->preview_url_template;
+ $host = $url->getHost();
+ $schema = $url->getScheme();
+ $random = new Cuid2(7);
+ $preview_fqdn = str_replace('{{random}}', $random, $template);
+ $preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
+ $preview_fqdn = str_replace('{{pr_id}}', $preview_id, $preview_fqdn);
+ $preview_fqdn = "$schema://$preview_fqdn";
+ $preview->fqdn = $preview_fqdn;
+ $preview->save();
+ $this->dispatch('success', 'Domain generated.');
+ }
+ public function add(int $pull_request_id, string|null $pull_request_html_url = null)
+ {
+ try {
+ $this->setDeploymentUuid();
+ $found = ApplicationPreview::where('application_id', $this->application->id)->where('pull_request_id', $pull_request_id)->first();
+ if (!$found && !is_null($pull_request_html_url)) {
+ ApplicationPreview::create([
+ 'application_id' => $this->application->id,
+ 'pull_request_id' => $pull_request_id,
+ 'pull_request_html_url' => $pull_request_html_url
+ ]);
+ }
+ $this->application->generate_preview_fqdn($pull_request_id);
+ $this->application->refresh();
+ } catch (\Throwable $e) {
+ return handleError($e, $this);
+ }
+ }
public function deploy(int $pull_request_id, string|null $pull_request_html_url = null)
{
try {
@@ -71,6 +140,25 @@ class Previews extends Component
}
public function stop(int $pull_request_id)
+ {
+ try {
+ if ($this->application->destination->server->isSwarm()) {
+ instant_remote_process(["docker stack rm {$this->application->uuid}-{$pull_request_id}"], $this->application->destination->server);
+ } else {
+ $containers = getCurrentApplicationContainerStatus($this->application->destination->server, $this->application->id, $pull_request_id);
+ foreach ($containers as $container) {
+ $name = str_replace('/', '', $container['Names']);
+ instant_remote_process(["docker rm -f $name"], $this->application->destination->server, throwError: false);
+ }
+ }
+ GetContainersStatus::dispatchSync($this->application->destination->server);
+ $this->application->refresh();
+ } catch (\Throwable $e) {
+ return handleError($e, $this);
+ }
+ }
+
+ public function delete(int $pull_request_id)
{
try {
if ($this->application->destination->server->isSwarm()) {
diff --git a/app/Livewire/Project/Shared/GetLogs.php b/app/Livewire/Project/Shared/GetLogs.php
index e14cd6113..0060fa16e 100644
--- a/app/Livewire/Project/Shared/GetLogs.php
+++ b/app/Livewire/Project/Shared/GetLogs.php
@@ -43,6 +43,11 @@ class GetLogs extends Component
$this->showTimeStamps = $this->resource->is_include_timestamps;
}
}
+ if ($this->resource?->getMorphClass() === 'App\Models\Application') {
+ if (str($this->container)->contains('-pr-')) {
+ $this->pull_request = "Pull Request: " . str($this->container)->afterLast('-pr-')->beforeLast('_')->value();
+ }
+ }
}
}
public function doSomethingWithThisChunkOfOutput($output)
@@ -77,13 +82,6 @@ class GetLogs extends Component
if (!$this->server->isFunctional()) {
return;
}
- if ($this->resource?->getMorphClass() === 'App\Models\Application') {
- if (str($this->container)->contains('-pr-')) {
- $this->pull_request = "Pull Request: " . str($this->container)->afterLast('-pr-')->beforeLast('_')->value();
- } else {
- $this->pull_request = 'branch';
- }
- }
if (!$refresh && ($this->resource?->getMorphClass() === 'App\Models\Service' || str($this->container)->contains('-pr-'))) return;
if (!$this->numberOfLines) {
$this->numberOfLines = 1000;
diff --git a/app/Livewire/Project/Shared/Logs.php b/app/Livewire/Project/Shared/Logs.php
index f1d70bf28..52a7b568d 100644
--- a/app/Livewire/Project/Shared/Logs.php
+++ b/app/Livewire/Project/Shared/Logs.php
@@ -103,6 +103,14 @@ class Logs extends Component
}
}
$this->containers = $this->containers->sort();
+ if (data_get($this->query,'pull_request_id')) {
+ $this->containers = $this->containers->filter(function ($container) {
+ return str_contains($container, $this->query['pull_request_id']);
+ });
+ ray($this->containers);
+
+ }
+
$this->loadMetrics();
} catch (\Exception $e) {
return handleError($e, $this);
diff --git a/app/Livewire/Settings/Configuration.php b/app/Livewire/Settings/Configuration.php
index 54dbe1bdb..68dc59a7f 100644
--- a/app/Livewire/Settings/Configuration.php
+++ b/app/Livewire/Settings/Configuration.php
@@ -70,9 +70,8 @@ class Configuration extends Component
$this->validate();
if ($this->settings->is_dns_validation_enabled && $this->settings->fqdn) {
- ray('asdf');
if (!validate_dns_entry($this->settings->fqdn, $this->server)) {
- $this->dispatch('error', "Validating DNS ({$this->settings->fqdn}) failed.
Make sure you have added the DNS records correctly.
Check this documentation for further help.");
+ $this->dispatch('error', "Validating DNS failed.
Make sure you have added the DNS records correctly.
{$this->settings->fqdn}->{$this->server->ip}
Check this documentation for further help.");
$error_show = true;
}
}
diff --git a/app/Models/Application.php b/app/Models/Application.php
index 21c5dfea8..e0ed328f9 100644
--- a/app/Models/Application.php
+++ b/app/Models/Application.php
@@ -1052,4 +1052,29 @@ class Application extends BaseModel
}
}
}
+ function generate_preview_fqdn(int $pull_request_id) {
+ $preview = ApplicationPreview::findPreviewByApplicationAndPullId($this->id, $pull_request_id);
+ if (is_null(data_get($preview, 'fqdn')) && $this->fqdn) {
+ if (str($this->fqdn)->contains(',')) {
+ $url = Url::fromString(str($this->fqdn)->explode(',')[0]);
+ $preview_fqdn = getFqdnWithoutPort(str($this->fqdn)->explode(',')[0]);
+ } else {
+ $url = Url::fromString($this->fqdn);
+ if (data_get($preview, 'fqdn')) {
+ $preview_fqdn = getFqdnWithoutPort(data_get($preview, 'fqdn'));
+ }
+ }
+ $template = $this->preview_url_template;
+ $host = $url->getHost();
+ $schema = $url->getScheme();
+ $random = new Cuid2(7);
+ $preview_fqdn = str_replace('{{random}}', $random, $template);
+ $preview_fqdn = str_replace('{{domain}}', $host, $preview_fqdn);
+ $preview_fqdn = str_replace('{{pr_id}}', $pull_request_id, $preview_fqdn);
+ $preview_fqdn = "$schema://$preview_fqdn";
+ $preview->fqdn = $preview_fqdn;
+ $preview->save();
+ }
+ return $preview;
+ }
}
diff --git a/bootstrap/helpers/applications.php b/bootstrap/helpers/applications.php
index 23558cd87..39d21bcca 100644
--- a/bootstrap/helpers/applications.php
+++ b/bootstrap/helpers/applications.php
@@ -2,7 +2,6 @@
use App\Enums\ApplicationDeploymentStatus;
use App\Jobs\ApplicationDeploymentJob;
-use App\Jobs\ApplicationDeploymentJobNew;
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use App\Models\Server;
@@ -43,26 +42,14 @@ function queue_application_deployment(Application $application, string $deployme
'only_this_server' => $only_this_server
]);
- if (isDev()) {
- if ($no_questions_asked) {
- dispatch(new ApplicationDeploymentJobNew(
- application_deployment_queue_id: $deployment->id,
- ));
- } else if (next_queuable($server_id, $application_id)) {
- dispatch(new ApplicationDeploymentJobNew(
- application_deployment_queue_id: $deployment->id,
- ));
- }
- } else {
- if ($no_questions_asked) {
- dispatch(new ApplicationDeploymentJob(
- application_deployment_queue_id: $deployment->id,
- ));
- } else if (next_queuable($server_id, $application_id)) {
- dispatch(new ApplicationDeploymentJob(
- application_deployment_queue_id: $deployment->id,
- ));
- }
+ if ($no_questions_asked) {
+ dispatch(new ApplicationDeploymentJob(
+ application_deployment_queue_id: $deployment->id,
+ ));
+ } else if (next_queuable($server_id, $application_id)) {
+ dispatch(new ApplicationDeploymentJob(
+ application_deployment_queue_id: $deployment->id,
+ ));
}
}
function force_start_deployment(ApplicationDeploymentQueue $deployment)
@@ -70,15 +57,10 @@ function force_start_deployment(ApplicationDeploymentQueue $deployment)
$deployment->update([
'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
]);
- if (isDev()) {
- dispatch(new ApplicationDeploymentJobNew(
- application_deployment_queue_id: $deployment->id,
- ));
- } else {
- dispatch(new ApplicationDeploymentJob(
- application_deployment_queue_id: $deployment->id,
- ));
- }
+
+ dispatch(new ApplicationDeploymentJob(
+ application_deployment_queue_id: $deployment->id,
+ ));
}
function queue_next_deployment(Application $application)
{
@@ -88,15 +70,10 @@ function queue_next_deployment(Application $application)
$next_found->update([
'status' => ApplicationDeploymentStatus::IN_PROGRESS->value,
]);
- if (isDev()) {
- dispatch(new ApplicationDeploymentJobNew(
- application_deployment_queue_id: $next_found->id,
- ));
- } else {
- dispatch(new ApplicationDeploymentJob(
- application_deployment_queue_id: $next_found->id,
- ));
- }
+
+ dispatch(new ApplicationDeploymentJob(
+ application_deployment_queue_id: $next_found->id,
+ ));
}
}
diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php
index f6841f6ac..0ce578758 100644
--- a/bootstrap/helpers/docker.php
+++ b/bootstrap/helpers/docker.php
@@ -465,13 +465,32 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
$appUuid = $appUuid . '-pr-' . $pull_request_id;
}
$labels = collect([]);
- if ($application->fqdn) {
- if ($pull_request_id !== 0) {
- $domains = Str::of(data_get($preview, 'fqdn'))->explode(',');
- } else {
+ if ($pull_request_id === 0) {
+ if ($application->fqdn) {
$domains = Str::of(data_get($application, 'fqdn'))->explode(',');
+ $labels = $labels->merge(fqdnLabelsForTraefik(
+ uuid: $appUuid,
+ domains: $domains,
+ onlyPort: $onlyPort,
+ is_force_https_enabled: $application->isForceHttpsEnabled(),
+ is_gzip_enabled: $application->isGzipEnabled(),
+ is_stripprefix_enabled: $application->isStripprefixEnabled()
+ ));
+ // Add Caddy labels
+ $labels = $labels->merge(fqdnLabelsForCaddy(
+ network: $application->destination->network,
+ uuid: $appUuid,
+ domains: $domains,
+ onlyPort: $onlyPort,
+ is_force_https_enabled: $application->isForceHttpsEnabled(),
+ is_gzip_enabled: $application->isGzipEnabled(),
+ is_stripprefix_enabled: $application->isStripprefixEnabled()
+ ));
+ }
+ } else {
+ if ($preview->fqdn) {
+ $domains = Str::of(data_get($preview, 'fqdn'))->explode(',');
}
- // Add Traefik labels
$labels = $labels->merge(fqdnLabelsForTraefik(
uuid: $appUuid,
domains: $domains,
@@ -490,6 +509,7 @@ function generateLabelsApplication(Application $application, ?ApplicationPreview
is_gzip_enabled: $application->isGzipEnabled(),
is_stripprefix_enabled: $application->isStripprefixEnabled()
));
+
}
return $labels->all();
}
diff --git a/config/sentry.php b/config/sentry.php
index 5fb383738..e4861e285 100644
--- a/config/sentry.php
+++ b/config/sentry.php
@@ -7,7 +7,7 @@ return [
// The release version of your application
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
- 'release' => '4.0.0-beta.290',
+ 'release' => '4.0.0-beta.291',
// When left empty or `null` the Laravel environment will be used
'environment' => config('app.env'),
diff --git a/config/version.php b/config/version.php
index 27aa1f62e..2d27ac881 100644
--- a/config/version.php
+++ b/config/version.php
@@ -1,3 +1,3 @@
'Are you sure?',
- 'buttonTitle' => 'Open Modal',
'isErrorButton' => false,
+ 'buttonTitle' => 'REWRITE THIS BUTTON TITLE PLEASSSSEEEE',
'buttonFullWidth' => false,
+ 'customButton' => null,
'disabled' => false,
'action' => 'delete',
'content' => null,
])