mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-19 06:15:00 +00:00
Merge branch 'next' into shadow/add-shared-server-env
This commit is contained in:
227 files changed
+9960
-15827
No files matched your search
@@ -87,9 +87,6 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
private bool $use_build_server = false;
|
||||
|
||||
// Save original server between phases
|
||||
private Server $original_server;
|
||||
|
||||
private Server $mainServer;
|
||||
|
||||
private bool $is_this_additional_server = false;
|
||||
@@ -325,18 +322,14 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if ($buildServers->count() === 0) {
|
||||
$this->application_deployment_queue->addLogEntry('No suitable build server found. Using the deployment server.');
|
||||
$this->build_server = $this->server;
|
||||
$this->original_server = $this->server;
|
||||
} else {
|
||||
$this->build_server = $buildServers->random();
|
||||
$this->application_deployment_queue->build_server_id = $this->build_server->id;
|
||||
$this->application_deployment_queue->addLogEntry("Found a suitable build server ({$this->build_server->name}).");
|
||||
$this->original_server = $this->server;
|
||||
$this->use_build_server = true;
|
||||
}
|
||||
} else {
|
||||
// Set build server & original_server to the same as deployment server
|
||||
$this->build_server = $this->server;
|
||||
$this->original_server = $this->server;
|
||||
}
|
||||
$this->detectBuildKitCapabilities();
|
||||
$this->decide_what_to_do();
|
||||
@@ -937,7 +930,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
if ($this->preserveRepository) {
|
||||
if ($this->use_build_server) {
|
||||
$this->server = $this->original_server;
|
||||
$this->server = $this->mainServer;
|
||||
}
|
||||
if (str($this->configuration_dir)->isNotEmpty()) {
|
||||
$this->execute_remote_command(
|
||||
@@ -960,7 +953,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
if (isset($this->docker_compose_base64)) {
|
||||
if ($this->use_build_server) {
|
||||
$this->server = $this->original_server;
|
||||
$this->server = $this->mainServer;
|
||||
}
|
||||
$readme = generate_readme_file($this->application->name, $this->application_deployment_queue->updated_at);
|
||||
|
||||
@@ -1342,7 +1335,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
|
||||
// Also create in configuration directory
|
||||
if ($this->use_build_server) {
|
||||
$this->server = $this->original_server;
|
||||
$this->server = $this->mainServer;
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"touch $this->configuration_dir/.env",
|
||||
@@ -1359,7 +1352,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
} else {
|
||||
// For non-Docker Compose deployments, clean up any existing .env files
|
||||
if ($this->use_build_server) {
|
||||
$this->server = $this->original_server;
|
||||
$this->server = $this->mainServer;
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
'command' => "rm -f $this->configuration_dir/.env",
|
||||
@@ -1397,17 +1390,21 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, "echo '$envs_base64' | base64 -d | tee $this->workdir/.env > /dev/null"),
|
||||
],
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, "cat $this->workdir/.env"),
|
||||
'hidden' => true,
|
||||
|
||||
]
|
||||
);
|
||||
|
||||
if (isDev()) {
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, "cat $this->workdir/.env"),
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
// Write .env file to configuration directory
|
||||
if ($this->use_build_server) {
|
||||
$this->server = $this->original_server;
|
||||
$this->server = $this->mainServer;
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
"echo '$envs_base64' | base64 -d | tee $this->configuration_dir/.env > /dev/null",
|
||||
@@ -1656,12 +1653,17 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, "echo '$envs_base64' | base64 -d | tee ".self::BUILD_TIME_ENV_PATH.' > /dev/null'),
|
||||
],
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_TIME_ENV_PATH),
|
||||
'hidden' => true,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
if (isDev()) {
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_TIME_ENV_PATH),
|
||||
'hidden' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
} elseif ($this->build_pack === 'dockercompose' || $this->build_pack === 'dockerfile') {
|
||||
// For Docker Compose and Dockerfile, create an empty .env file even if there are no build-time variables
|
||||
// This ensures the file exists when referenced in build commands
|
||||
@@ -1744,7 +1746,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
} else {
|
||||
if ($this->use_build_server) {
|
||||
$this->write_deployment_configurations();
|
||||
$this->server = $this->original_server;
|
||||
$this->server = $this->mainServer;
|
||||
}
|
||||
if (count($this->application->ports_mappings_array) > 0 || (bool) $this->application->settings->is_consistent_container_name_enabled || str($this->application->settings->custom_internal_name)->isNotEmpty() || $this->pull_request_id !== 0 || str($this->application->custom_docker_run_options)->contains('--ip') || str($this->application->custom_docker_run_options)->contains('--ip6')) {
|
||||
$this->application_deployment_queue->addLogEntry('----------------------------------------');
|
||||
@@ -1913,7 +1915,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
private function create_workdir()
|
||||
{
|
||||
if ($this->use_build_server) {
|
||||
$this->server = $this->original_server;
|
||||
$this->server = $this->mainServer;
|
||||
$this->execute_remote_command(
|
||||
[
|
||||
'command' => "mkdir -p {$this->configuration_dir}",
|
||||
@@ -2271,7 +2273,14 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
$this->nixpacks_plan = json_encode($parsed, JSON_PRETTY_PRINT);
|
||||
$this->nixpacks_plan_json = collect($parsed);
|
||||
$this->application_deployment_queue->addLogEntry("Final Nixpacks plan: {$this->nixpacks_plan}", hidden: true);
|
||||
|
||||
if (isDev()) {
|
||||
$this->application_deployment_queue->addLogEntry("Final Nixpacks plan: {$this->nixpacks_plan}", hidden: true);
|
||||
} else {
|
||||
$parsedForLog = $parsed;
|
||||
unset($parsedForLog['variables']); // remove variables section to avoid exposing ENVs in production logs
|
||||
$this->application_deployment_queue->addLogEntry('Final Nixpacks plan: '.json_encode($parsedForLog, JSON_PRETTY_PRINT), hidden: true);
|
||||
}
|
||||
if ($this->nixpacks_type === 'rust') {
|
||||
// temporary: disable healthcheck for rust because the start phase does not have curl/wget
|
||||
$this->application->health_check_enabled = false;
|
||||
@@ -2567,7 +2576,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
if (! is_null($this->application->limits_cpuset)) {
|
||||
data_set($docker_compose, 'services.'.$this->container_name.'.cpuset', $this->application->limits_cpuset);
|
||||
}
|
||||
if ($this->server->isSwarm()) {
|
||||
if ($this->mainServer->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');
|
||||
@@ -2617,7 +2626,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
} else {
|
||||
$docker_compose['services'][$this->container_name]['labels'] = $labels;
|
||||
}
|
||||
if ($this->server->isLogDrainEnabled() && $this->application->isLogDrainEnabled()) {
|
||||
if ($this->mainServer->isLogDrainEnabled() && $this->application->isLogDrainEnabled()) {
|
||||
$docker_compose['services'][$this->container_name]['logging'] = generate_fluentd_configuration();
|
||||
}
|
||||
if ($this->application->settings->is_gpu_enabled) {
|
||||
|
||||
@@ -54,8 +54,9 @@ class ApplicationPullRequestUpdateJob implements ShouldBeEncrypted, ShouldQueue
|
||||
ProcessStatus::CLOSED => '', // Already handled above, but included for completeness
|
||||
};
|
||||
$this->build_logs_url = base_url()."/project/{$this->application->environment->project->uuid}/environment/{$this->application->environment->uuid}/application/{$this->application->uuid}/deployment/{$this->deployment_uuid}";
|
||||
$application_logs_url = base_url()."/project/{$this->application->environment->project->uuid}/environment/{$this->application->environment->uuid}/application/{$this->application->uuid}/logs";
|
||||
|
||||
$this->body .= '[Open Build Logs]('.$this->build_logs_url.")\n\n\n";
|
||||
$this->body .= '[Open Build Logs]('.$this->build_logs_url.') | [Open Application Logs]('.$application_logs_url.")\n\n\n";
|
||||
$this->body .= 'Last updated at: '.now()->toDateTimeString().' CET';
|
||||
if ($this->preview->pull_request_issue_comment_id) {
|
||||
$this->update_comment();
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use App\Actions\Application\CleanupPreviewDeployment;
|
||||
use App\Enums\ProcessStatus;
|
||||
use App\Models\Application;
|
||||
use App\Models\ApplicationPreview;
|
||||
use App\Models\GithubApp;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
|
||||
class ProcessGithubPullRequestWebhook implements ShouldBeEncrypted, ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public int $tries = 3;
|
||||
|
||||
public int $timeout = 60;
|
||||
|
||||
public array $backoff = [30, 60, 120];
|
||||
|
||||
public function __construct(
|
||||
public int $applicationId,
|
||||
public ?int $githubAppId,
|
||||
public string $action,
|
||||
public int $pullRequestId,
|
||||
public string $pullRequestHtmlUrl,
|
||||
public ?string $beforeSha,
|
||||
public ?string $afterSha,
|
||||
public string $commitSha,
|
||||
public ?string $authorAssociation,
|
||||
public string $fullName,
|
||||
) {
|
||||
$this->onQueue('high');
|
||||
}
|
||||
|
||||
public function handle(): void
|
||||
{
|
||||
$application = Application::find($this->applicationId);
|
||||
if (! $application) {
|
||||
return;
|
||||
}
|
||||
|
||||
$githubApp = $this->githubAppId ? GithubApp::find($this->githubAppId) : null;
|
||||
|
||||
if ($this->action === 'closed' || $this->action === 'close') {
|
||||
$this->handleClosedAction($application);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->action === 'opened' || $this->action === 'synchronize' || $this->action === 'reopened') {
|
||||
$this->handleOpenAction($application, $githubApp);
|
||||
}
|
||||
}
|
||||
|
||||
private function handleClosedAction(Application $application): void
|
||||
{
|
||||
$found = ApplicationPreview::where('application_id', $application->id)
|
||||
->where('pull_request_id', $this->pullRequestId)
|
||||
->first();
|
||||
|
||||
if ($found) {
|
||||
ApplicationPullRequestUpdateJob::dispatchSync(
|
||||
application: $application,
|
||||
preview: $found,
|
||||
status: ProcessStatus::CLOSED
|
||||
);
|
||||
|
||||
CleanupPreviewDeployment::run($application, $this->pullRequestId, $found);
|
||||
}
|
||||
}
|
||||
|
||||
private function handleOpenAction(Application $application, ?GithubApp $githubApp): void
|
||||
{
|
||||
if (! $application->isPRDeployable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if PR deployments from public contributors are restricted
|
||||
if (! $application->settings->is_pr_deployments_public_enabled) {
|
||||
$trustedAssociations = ['OWNER', 'MEMBER', 'COLLABORATOR', 'CONTRIBUTOR'];
|
||||
if (! in_array($this->authorAssociation, $trustedAssociations)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get changed files for watch path filtering
|
||||
$changed_files = collect();
|
||||
$repository_parts = explode('/', $this->fullName);
|
||||
$owner = $repository_parts[0] ?? '';
|
||||
$repo = $repository_parts[1] ?? '';
|
||||
|
||||
if ($this->action === 'synchronize' && $this->beforeSha && $this->afterSha) {
|
||||
// For synchronize events, get files changed between before and after commits
|
||||
$changed_files = collect(getGithubCommitRangeFiles($githubApp, $owner, $repo, $this->beforeSha, $this->afterSha));
|
||||
} elseif ($this->action === 'opened' || $this->action === 'reopened') {
|
||||
// For opened/reopened events, get all files in the PR
|
||||
$changed_files = collect(getGithubPullRequestFiles($githubApp, $owner, $repo, $this->pullRequestId));
|
||||
}
|
||||
|
||||
// Apply watch path filtering
|
||||
$is_watch_path_triggered = $application->isWatchPathsTriggered($changed_files);
|
||||
if (! $is_watch_path_triggered && ! blank($application->watch_paths)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create ApplicationPreview if not exists
|
||||
$found = ApplicationPreview::where('application_id', $application->id)
|
||||
->where('pull_request_id', $this->pullRequestId)
|
||||
->first();
|
||||
|
||||
if (! $found) {
|
||||
if ($application->build_pack === 'dockercompose') {
|
||||
$preview = ApplicationPreview::create([
|
||||
'git_type' => 'github',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $this->pullRequestId,
|
||||
'pull_request_html_url' => $this->pullRequestHtmlUrl,
|
||||
'docker_compose_domains' => $application->docker_compose_domains,
|
||||
]);
|
||||
$preview->generate_preview_fqdn_compose();
|
||||
} else {
|
||||
$preview = ApplicationPreview::create([
|
||||
'git_type' => 'github',
|
||||
'application_id' => $application->id,
|
||||
'pull_request_id' => $this->pullRequestId,
|
||||
'pull_request_html_url' => $this->pullRequestHtmlUrl,
|
||||
]);
|
||||
$preview->generate_preview_fqdn();
|
||||
}
|
||||
}
|
||||
|
||||
// Queue the deployment
|
||||
$deployment_uuid = new Cuid2;
|
||||
queue_application_deployment(
|
||||
application: $application,
|
||||
pull_request_id: $this->pullRequestId,
|
||||
deployment_uuid: $deployment_uuid,
|
||||
force_rebuild: false,
|
||||
commit: $this->commitSha,
|
||||
is_webhook: true,
|
||||
git_type: 'github'
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user