Merge remote-tracking branch 'origin/main' into release/v4.5

This commit is contained in:
github-actions[bot]
2026-10-08 10:24:23 +00:00
8 changed files with 140 additions and 21 deletions
+24
View File
@@ -3053,6 +3053,7 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
}
}
$this->reuse_commit_message();
$this->set_coolify_variables();
// Restart helper container with actual SOURCE_COMMIT value
@@ -3062,6 +3063,29 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
}
}
/**
* The commit message is read from the cloned repository. Deployments that skip the build or fail
* before the clone reuse the message stored by an earlier deployment of the same commit.
*/
private function reuse_commit_message(): void
{
if (filled($this->application_deployment_queue->commit_message) || $this->shouldResolveBranchHeadCommit()) {
return;
}
$commitMessage = ApplicationDeploymentQueue::query()
->where('application_id', $this->application->id)
->where('commit', $this->commit)
->whereNotNull('commit_message')
->where('commit_message', '!=', '')
->latest('id')
->value('commit_message');
if (filled($commitMessage)) {
$this->application_deployment_queue->update(['commit_message' => $commitMessage]);
}
}
private function shouldResolveBranchHeadCommit(): bool
{
$commit = trim($this->commit);
+12 -8
View File
@@ -83,14 +83,16 @@
<x-reicon name="projects" class="size-4" />
@endif
</div>
<div class="min-w-0 flex-1">
<div class="min-w-0 flex-1 self-center">
<h3
class="truncate text-[13px]! leading-4! font-semibold! text-black dark:text-fg">
{{ $project->name }}
</h3>
<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">
{{ $project->description }}
</p>
@if (filled($project->description))
<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">
{{ $project->description }}
</p>
@endif
</div>
</div>
@@ -204,14 +206,16 @@
class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.1] dark:bg-white/[0.04] dark:text-fg-dim">
<x-reicon name="servers" class="size-4" />
</div>
<div class="min-w-0 flex-1">
<div class="min-w-0 flex-1 self-center">
<h3
class="truncate text-[13px]! leading-4! font-semibold! text-black dark:text-fg">
{{ $server->name }}
</h3>
<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">
{{ $server->description }}
</p>
@if (filled($server->description))
<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">
{{ $server->description }}
</p>
@endif
</div>
@if ($serverStatusType !== 'success')
<span data-tooltip="{{ $serverStatus }}"
@@ -116,12 +116,13 @@
<x-reicon name="projects" class="size-4" />
</template>
</div>
<div class="min-w-0 flex-1">
<div class="min-w-0 flex-1 self-center">
<h2
class="truncate text-[13px]! leading-4! font-semibold! text-black dark:text-fg"
x-text="project.name"></h2>
<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint"
x-text="project.description || ''"></p>
x-show="project.description?.trim()"
x-text="project.description"></p>
</div>
</div>
@@ -147,13 +147,15 @@
class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.1] dark:bg-white/[0.04] dark:text-fg-dim">
<x-reicon name="servers" class="size-4" />
</div>
<div class="min-w-0 flex-1">
<div class="min-w-0 flex-1 self-center">
<h2 class="truncate text-[13px]! leading-4! font-semibold! text-black dark:text-fg">
{{ $serverRow['name'] }}
</h2>
<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">
{{ $serverRow['description'] }}
</p>
@if (filled($serverRow['description']))
<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">
{{ $serverRow['description'] }}
</p>
@endif
</div>
@if ($serverRow['statusType'] !== 'success')
<span data-tooltip="{{ $serverRow['status'] }}"
@@ -68,7 +68,7 @@
class="flex size-9 shrink-0 items-center justify-center rounded-lg bg-neutral-100 text-neutral-500 dark:bg-white/[0.06] dark:text-fg-dim">
<x-reicon name="keys" class="size-4" />
</div>
<div class="min-w-0">
<div class="min-w-0 self-center">
<div class="flex flex-wrap items-center gap-2">
<p class="truncate text-sm font-medium text-neutral-950 dark:text-fg">
{{ $privateKey->name }}
@@ -77,9 +77,11 @@
<x-status-badge status="Active" type="success" />
@endif
</div>
<p class="mt-1 text-xs text-neutral-500 dark:text-fg-dim">
{{ $privateKey->description }}
</p>
@if (filled($privateKey->description))
<p class="mt-1 text-xs text-neutral-500 dark:text-fg-dim">
{{ $privateKey->description }}
</p>
@endif
</div>
</div>
<div class="flex shrink-0 items-center gap-2">
@@ -33,7 +33,7 @@
href="{{ route('shared-variables.environment.show', ['project_uuid' => $project->uuid, 'environment_uuid' => $environment->uuid]) }}" {{ wireNavigate() }}>
<div class="flex items-start gap-3">
<div class="flex size-8 shrink-0 items-center justify-center rounded-lg border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-white/[0.08] dark:bg-white/[0.04] dark:text-fg-dim"><x-reicon name="layers" class="size-4" /></div>
<div class="min-w-0 flex-1"><h3 class="truncate text-[13px]! leading-4! font-semibold! text-black dark:text-fg">{{ $environment->name }}</h3><p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">{{ $environment->description }}</p></div>
<div class="min-w-0 flex-1 self-center"><h3 class="truncate text-[13px]! leading-4! font-semibold! text-black dark:text-fg">{{ $environment->name }}</h3>@if (filled($environment->description))<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">{{ $environment->description }}</p>@endif</div>
</div>
</a>
@endforeach
@@ -31,9 +31,11 @@
<x-reicon name="projects" class="size-4" />
@endif
</div>
<div class="min-w-0 flex-1">
<div class="min-w-0 flex-1 self-center">
<h2 class="truncate text-[13px]! leading-4! font-semibold! text-black dark:text-fg">{{ $project->name }}</h2>
<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">{{ $project->description }}</p>
@if (filled($project->description))
<p class="mt-0.5 truncate text-[11px] text-neutral-500 dark:text-fg-faint">{{ $project->description }}</p>
@endif
</div>
</div>
<div class="mt-auto pt-4 text-[11px] text-neutral-500 dark:text-fg-dim">
@@ -0,0 +1,84 @@
<?php
use App\Jobs\ApplicationDeploymentJob;
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use App\Models\Environment;
use App\Models\Project;
use App\Models\Server;
use App\Models\StandaloneDocker;
use App\Models\Team;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
$team = Team::factory()->create();
$this->server = Server::factory()->create(['team_id' => $team->id]);
$destination = StandaloneDocker::where('server_id', $this->server->id)->firstOrFail();
$project = Project::factory()->create(['team_id' => $team->id]);
$environment = $project->environments()->first() ?? Environment::factory()->create(['project_id' => $project->id]);
$this->application = Application::factory()->create([
'environment_id' => $environment->id,
'destination_id' => $destination->id,
'destination_type' => $destination->getMorphClass(),
]);
});
function createCommitMessageDeployment(Application $application, Server $server, string $commit, ?string $commitMessage = null): ApplicationDeploymentQueue
{
return ApplicationDeploymentQueue::create([
'application_id' => $application->id,
'deployment_uuid' => new_public_id(),
'server_id' => $server->id,
'commit' => $commit,
'commit_message' => $commitMessage,
]);
}
function reuseCommitMessage(ApplicationDeploymentQueue $deployment, Application $application, string $commit): void
{
$reflection = new ReflectionClass(ApplicationDeploymentJob::class);
$job = $reflection->newInstanceWithoutConstructor();
$reflection->getProperty('application')->setValue($job, $application);
$reflection->getProperty('application_deployment_queue')->setValue($job, $deployment);
$reflection->getProperty('commit')->setValue($job, $commit);
$reflection->getMethod('reuse_commit_message')->invoke($job);
}
test('copies the commit message from an earlier deployment of the same commit', function () {
$commit = str_repeat('a', 40);
createCommitMessageDeployment($this->application, $this->server, $commit, 'feat: add portfolio work page');
$deployment = createCommitMessageDeployment($this->application, $this->server, $commit);
reuseCommitMessage($deployment, $this->application, $commit);
expect($deployment->fresh()->commit_message)->toBe('feat: add portfolio work page');
});
test('does not copy a commit message from another commit or application', function () {
$commit = str_repeat('a', 40);
createCommitMessageDeployment($this->application, $this->server, str_repeat('b', 40), 'other commit');
$otherApplication = Application::factory()->create([
'environment_id' => $this->application->environment_id,
'destination_id' => $this->application->destination_id,
'destination_type' => $this->application->destination_type,
]);
createCommitMessageDeployment($otherApplication, $this->server, $commit, 'other application');
$deployment = createCommitMessageDeployment($this->application, $this->server, $commit);
reuseCommitMessage($deployment, $this->application, $commit);
expect($deployment->fresh()->commit_message)->toBeNull();
});
test('does not look up a commit message for an unresolved HEAD commit', function () {
createCommitMessageDeployment($this->application, $this->server, 'HEAD', 'stale message');
$deployment = createCommitMessageDeployment($this->application, $this->server, 'HEAD');
reuseCommitMessage($deployment, $this->application, 'HEAD');
expect($deployment->fresh()->commit_message)->toBeNull();
});