From 0991f8e2ca8a91827547b086f0e2cd7aaee21ad3 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:48:30 +0100 Subject: [PATCH] fix(application): clarify deployment type precedence logic - Prioritize real private keys (id > 0) first - Check source second before falling back to zero key - Remove isDev() check that was restricting zero key behavior in dev - Remove exception throw, use 'other' as safe fallback - Expand test coverage to validate all precedence scenarios --- app/Models/Application.php | 21 ++++++--- tests/Unit/ApplicationDeploymentTypeTest.php | 47 +++++++++++++++++++- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/app/Models/Application.php b/app/Models/Application.php index 9f59445d8..82e4d6311 100644 --- a/app/Models/Application.php +++ b/app/Models/Application.php @@ -989,17 +989,24 @@ public function isPRDeployable(): bool public function deploymentType() { - if (isDev() && data_get($this, 'private_key_id') === 0) { + $privateKeyId = data_get($this, 'private_key_id'); + + // Real private key (id > 0) always takes precedence + if ($privateKeyId !== null && $privateKeyId > 0) { return 'deploy_key'; } - if (! is_null(data_get($this, 'private_key_id'))) { - return 'deploy_key'; - } elseif (data_get($this, 'source')) { + + // GitHub/GitLab App source + if (data_get($this, 'source')) { return 'source'; - } else { - return 'other'; } - throw new \Exception('No deployment type found'); + + // Localhost key (id = 0) when no source is configured + if ($privateKeyId === 0) { + return 'deploy_key'; + } + + return 'other'; } public function could_set_build_commands(): bool diff --git a/tests/Unit/ApplicationDeploymentTypeTest.php b/tests/Unit/ApplicationDeploymentTypeTest.php index d240181f1..be7c7d528 100644 --- a/tests/Unit/ApplicationDeploymentTypeTest.php +++ b/tests/Unit/ApplicationDeploymentTypeTest.php @@ -1,11 +1,54 @@ private_key_id = 5; + + expect($application->deploymentType())->toBe('deploy_key'); +}); + +it('returns deploy_key when private_key_id is a real key even with source', function () { + $application = Mockery::mock(Application::class)->makePartial(); + $application->private_key_id = 5; + $application->shouldReceive('getAttribute')->with('source')->andReturn(new GithubApp); + $application->shouldReceive('getAttribute')->with('private_key_id')->andReturn(5); + + expect($application->deploymentType())->toBe('deploy_key'); +}); + +it('returns source when private_key_id is null and source exists', function () { + $application = Mockery::mock(Application::class)->makePartial(); + $application->private_key_id = null; + $application->shouldReceive('getAttribute')->with('source')->andReturn(new GithubApp); + $application->shouldReceive('getAttribute')->with('private_key_id')->andReturn(null); + + expect($application->deploymentType())->toBe('source'); +}); + +it('returns source when private_key_id is zero and source exists', function () { + $application = Mockery::mock(Application::class)->makePartial(); + $application->private_key_id = 0; + $application->shouldReceive('getAttribute')->with('source')->andReturn(new GithubApp); + $application->shouldReceive('getAttribute')->with('private_key_id')->andReturn(0); + + expect($application->deploymentType())->toBe('source'); +}); + +it('returns deploy_key when private_key_id is zero and no source', function () { + $application = new Application; $application->private_key_id = 0; $application->source = null; expect($application->deploymentType())->toBe('deploy_key'); }); + +it('returns other when private_key_id is null and no source', function () { + $application = Mockery::mock(Application::class)->makePartial(); + $application->shouldReceive('getAttribute')->with('source')->andReturn(null); + $application->shouldReceive('getAttribute')->with('private_key_id')->andReturn(null); + + expect($application->deploymentType())->toBe('other'); +});