diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index a2a97a3446..601c9b582b 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -210,6 +210,7 @@ class ServicesController extends Controller $application->fqdn = $containerUrls; $application->save(); + updateCompose($application); }); if (! empty($errors)) { diff --git a/tests/Feature/ServiceUrlsApiPersistenceTest.php b/tests/Feature/ServiceUrlsApiPersistenceTest.php new file mode 100644 index 0000000000..270a79d19e --- /dev/null +++ b/tests/Feature/ServiceUrlsApiPersistenceTest.php @@ -0,0 +1,78 @@ +set('app.maintenance.store', 'array'); + InstanceSettings::forceCreate(['id' => 0, 'is_api_enabled' => true]); + + $this->team = Team::factory()->create(); + $this->user = User::factory()->create(); + $this->team->members()->attach($this->user->id, ['role' => 'owner']); + + $plainTextToken = Str::random(40); + $token = $this->user->tokens()->create([ + 'name' => 'test-token', + 'token' => hash('sha256', $plainTextToken), + 'abilities' => ['*'], + 'team_id' => $this->team->id, + ]); + $this->bearerToken = $token->getKey().'|'.$plainTextToken; + + $server = Server::factory()->create(['team_id' => $this->team->id]); + $destination = StandaloneDocker::where('server_id', $server->id)->first(); + $project = Project::factory()->create(['team_id' => $this->team->id]); + $environment = Environment::factory()->create(['project_id' => $project->id]); + + $this->service = Service::factory()->create([ + 'environment_id' => $environment->id, + 'server_id' => $server->id, + 'destination_id' => $destination->id, + 'destination_type' => $destination->getMorphClass(), + 'docker_compose_raw' => "services:\n frontend:\n image: nginx:alpine\n environment:\n - SERVICE_FQDN_FRONTEND_80\n", + ]); + $this->service->parse(isNew: true); +}); + +function serviceMagicEnvValue(Service $service, string $key): ?string +{ + return $service->environment_variables()->where('key', $key)->value('value'); +} + +it('keeps a domain set through the services API urls field after the compose is parsed again', function () { + $this->withHeaders(['Authorization' => 'Bearer '.$this->bearerToken]) + ->patchJson("/api/v1/services/{$this->service->uuid}", [ + 'urls' => [['name' => 'frontend', 'url' => 'https://example.com']], + ]) + ->assertOk() + ->assertJsonPath('domains.0', 'https://example.com'); + + $assertDomain = function (): void { + $service = $this->service->fresh(); + expect($service->applications()->where('name', 'frontend')->value('fqdn'))->toBe('https://example.com') + ->and(serviceMagicEnvValue($service, 'SERVICE_URL_FRONTEND'))->toBe('https://example.com') + ->and(serviceMagicEnvValue($service, 'SERVICE_URL_FRONTEND_80'))->toBe('https://example.com:80') + ->and(serviceMagicEnvValue($service, 'SERVICE_FQDN_FRONTEND'))->toBe('example.com') + ->and(serviceMagicEnvValue($service, 'SERVICE_FQDN_FRONTEND_80'))->toBe('example.com:80'); + }; + + $assertDomain(); + + // StartService parses the compose again before every deploy. + $this->service->fresh()->parse(); + + $assertDomain(); +});