Implement Keystone environment deployments

This commit is contained in:
2026-05-13 16:11:23 +01:00
parent 65d3142d03
commit aa680b25fd
175 changed files with 10258 additions and 740 deletions

View File

@@ -0,0 +1,99 @@
<?php
use App\Actions\Environments\AttachManagedService;
use App\Enums\EnvironmentAttachmentRole;
use App\Enums\EnvironmentVariableSource;
use App\Enums\OperationKind;
use App\Enums\ServiceCategory;
use App\Enums\ServiceType;
use App\Models\Application;
use App\Models\Environment;
use App\Models\Organisation;
use App\Models\Service;
it('creates a postgres database slice and managed environment variables', function () {
$organisation = Organisation::factory()->create();
$application = Application::factory()->for($organisation)->create(['name' => 'Billing API']);
$environment = Environment::factory()->for($application)->create(['name' => 'production']);
$service = Service::factory()->for($environment)->create([
'organisation_id' => $organisation->id,
'name' => 'postgres',
'category' => ServiceCategory::DATABASE,
'type' => ServiceType::POSTGRES,
'version' => '18',
'version_track' => '18',
'driver_name' => 'postgres.18',
]);
$attachment = app(AttachManagedService::class)->execute(
environment: $environment,
service: $service,
role: EnvironmentAttachmentRole::DATABASE,
);
expect($attachment->serviceSlice)
->not->toBeNull()
->and($attachment->serviceSlice->type)->toBe('database_user')
->and($environment->variables()->where('key', 'DB_CONNECTION')->first()->value)->toBe('pgsql')
->and($environment->variables()->where('key', 'DB_PASSWORD')->first()->source)->toBe(EnvironmentVariableSource::MANAGED_ATTACHMENT)
->and($environment->variables()->where('key', 'DB_PASSWORD')->first()->overridable)->toBeFalse()
->and($attachment->serviceSlice->operations()->first()->kind)->toBe(OperationKind::SLICE_PROVISION)
->and($attachment->serviceSlice->operations()->first()->steps()->first()->script)->toContain('CREATE DATABASE');
});
it('creates a valkey logical slice without silently changing queue behavior', function () {
$organisation = Organisation::factory()->create();
$application = Application::factory()->for($organisation)->create();
$environment = Environment::factory()->for($application)->create();
$service = Service::factory()->for($environment)->create([
'organisation_id' => $organisation->id,
'name' => 'valkey',
'category' => ServiceCategory::CACHE,
'type' => ServiceType::VALKEY,
'version' => '8',
'version_track' => '8',
'driver_name' => 'valkey.8',
]);
app(AttachManagedService::class)->execute(
environment: $environment,
service: $service,
role: EnvironmentAttachmentRole::CACHE,
);
expect($environment->variables()->pluck('key')->all())
->toContain('REDIS_HOST', 'REDIS_PORT', 'REDIS_DB', 'CACHE_STORE')
->not->toContain('QUEUE_CONNECTION');
$slice = $service->slices()->first();
expect($slice->config['database'])->toBe(1)
->and($slice->operations()->first()->kind)->toBe(OperationKind::SLICE_PROVISION)
->and($slice->operations()->first()->steps()->first()->script)->toContain('valkey-cli');
});
it('creates a caddy route slice with an independent provision operation', function () {
$organisation = Organisation::factory()->create();
$application = Application::factory()->for($organisation)->create();
$environment = Environment::factory()->for($application)->create();
$service = Service::factory()->for($environment)->create([
'organisation_id' => $organisation->id,
'name' => 'gateway',
'category' => ServiceCategory::GATEWAY,
'type' => ServiceType::CADDY,
'version' => '2',
'version_track' => '2',
'driver_name' => 'caddy.2',
]);
$attachment = app(AttachManagedService::class)->execute(
environment: $environment,
service: $service,
role: EnvironmentAttachmentRole::GATEWAY,
name: 'example.com',
);
expect($attachment->serviceSlice->type)->toBe('route')
->and($attachment->serviceSlice->operations()->first()->kind)->toBe(OperationKind::SLICE_PROVISION)
->and($attachment->serviceSlice->operations()->first()->steps()->first()->script)->toContain('/home/keystone/gateway/Caddyfile.d');
});