Merge remote-tracking branch 'origin/next' into next

This commit is contained in:
Andras Bacsai
2026-07-03 10:09:50 +02:00
14 changed files with 600 additions and 38 deletions
@@ -17,6 +17,7 @@ use Database\Seeders\StandaloneDockerSeeder;
use Database\Seeders\TeamSeeder;
use Database\Seeders\UserSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Collection;
uses(RefreshDatabase::class);
@@ -33,6 +34,11 @@ function seedRailpackExamplePrerequisites(): void
]);
}
function limaServers(): Collection
{
return collect(DevelopmentRailpackExamplesSeeder::LIMA_SERVERS);
}
it('can seed the railpack examples directly on a clean development database', function () {
config()->set('app.env', 'local');
@@ -44,14 +50,51 @@ it('can seed the railpack examples directly on a clean development database', fu
expect(StandaloneDocker::query()->find(0))->not->toBeNull();
expect(GithubApp::query()->find(0))->not->toBeNull();
expect(GitlabApp::query()->find(1))->not->toBeNull();
expect(Project::query()->where('uuid', DevelopmentRailpackExamplesSeeder::PROJECT_UUID)->exists())->toBeTrue();
expect(Application::query()->count())->toBe(count(DevelopmentRailpackExamplesSeeder::examples()));
expect(Application::query()->count())->toBe(count(DevelopmentRailpackExamplesSeeder::examples()) * limaServers()->count());
$project = Project::query()
->where('uuid', DevelopmentRailpackExamplesSeeder::PROJECT_UUID)
->first();
expect($project)
->not->toBeNull()
->and($project->environments)->toHaveCount(limaServers()->count());
foreach (limaServers() as $limaServer) {
$server = Server::query()->where('uuid', $limaServer['server_uuid'])->first();
expect($server)->not->toBeNull();
expect($server->settings->sentinel_custom_url)->toBe('http://host.lima.internal:8000');
expect(StandaloneDocker::query()->whereRelation('server', 'uuid', $limaServer['server_uuid'])->exists())->toBeTrue();
expect($project->environments()->where('uuid', $limaServer['environment_uuid'])->exists())->toBeTrue();
}
});
it('seeds the railpack examples in development mode', function () {
config()->set('app.env', 'local');
seedRailpackExamplePrerequisites();
$legacyProject = Project::query()->create([
'uuid' => 'railpack-examples-lima-ubuntu-2404',
'name' => 'Railpack Examples - lima-ubuntu-2404',
'description' => 'Legacy generated Railpack examples project',
'team_id' => 0,
]);
Application::query()->create([
'uuid' => 'lima-ubuntu-2404-railpack-nextjs-ssr',
'name' => 'Legacy Railpack Next.js SSR Example',
'repository_project_id' => DevelopmentRailpackExamplesSeeder::REPOSITORY_PROJECT_ID,
'git_repository' => DevelopmentRailpackExamplesSeeder::GIT_REPOSITORY,
'git_branch' => DevelopmentRailpackExamplesSeeder::GIT_BRANCH,
'build_pack' => 'railpack',
'ports_exposes' => '3000',
'environment_id' => $legacyProject->environments()->first()->id,
'destination_id' => 0,
'destination_type' => StandaloneDocker::class,
'source_id' => 0,
'source_type' => GithubApp::class,
]);
$this->seed(DevelopmentRailpackExamplesSeeder::class);
$project = Project::query()
@@ -61,30 +104,58 @@ it('seeds the railpack examples in development mode', function () {
expect($project)
->not->toBeNull()
->and($project->name)->toBe('Railpack Examples')
->and($project->environments)->toHaveCount(1)
->and($project->environments->first()->uuid)->toBe(DevelopmentRailpackExamplesSeeder::ENVIRONMENT_UUID);
->and($project->environments)->toHaveCount(limaServers()->count());
expect(Project::query()->pluck('uuid')->sort()->values()->all())->toBe([
'project',
DevelopmentRailpackExamplesSeeder::PROJECT_UUID,
]);
expect(Application::query()->where('uuid', 'lima-ubuntu-2404-railpack-nextjs-ssr')->exists())->toBeFalse();
$applications = $project->applications()->with('settings')->orderBy('uuid')->get();
expect($applications)->toHaveCount(count(DevelopmentRailpackExamplesSeeder::examples()));
expect($applications)->toHaveCount(count(DevelopmentRailpackExamplesSeeder::examples()) * limaServers()->count());
expect($applications->every(fn (Application $application) => $application->build_pack === 'railpack'))->toBeTrue();
$examples = collect(DevelopmentRailpackExamplesSeeder::examples())->keyBy('uuid');
expect($applications->every(
fn (Application $application) => $application->git_repository === ($examples->get($application->uuid)['git_repository'] ?? DevelopmentRailpackExamplesSeeder::GIT_REPOSITORY)
fn (Application $application) => $application->git_repository === ($examples->get(str($application->uuid)->after('-')->value())['git_repository'] ?? DevelopmentRailpackExamplesSeeder::GIT_REPOSITORY)
))->toBeTrue();
expect($applications->every(
fn (Application $application) => $application->git_branch === ($examples->get($application->uuid)['git_branch'] ?? DevelopmentRailpackExamplesSeeder::GIT_BRANCH)
fn (Application $application) => $application->git_branch === ($examples->get(str($application->uuid)->after('-')->value())['git_branch'] ?? DevelopmentRailpackExamplesSeeder::GIT_BRANCH)
))->toBeTrue();
$nestjs = $applications->firstWhere('uuid', 'railpack-nestjs');
$angularStatic = $applications->firstWhere('uuid', 'railpack-angular-static');
$eleventyStatic = $applications->firstWhere('uuid', 'railpack-eleventy-static');
$pythonFlask = $applications->firstWhere('uuid', 'railpack-python-flask');
$goGin = $applications->firstWhere('uuid', 'railpack-go-gin');
$rust = $applications->firstWhere('uuid', 'railpack-rust');
$githubDeployKey = $applications->firstWhere('uuid', 'railpack-github-deploy-key');
$gitlabDeployKey = $applications->firstWhere('uuid', 'railpack-gitlab-deploy-key');
$gitlabPublic = $applications->firstWhere('uuid', 'railpack-gitlab-public-example');
foreach (limaServers() as $limaServer) {
$limaEnvironment = $project->environments()
->where('uuid', $limaServer['environment_uuid'])
->first();
expect($limaEnvironment)
->not->toBeNull()
->and($limaEnvironment->name)->toBe($limaServer['environment_name']);
$limaApplications = $limaEnvironment->applications()->with('settings', 'destination.server')->orderBy('uuid')->get();
expect($limaApplications)->toHaveCount(count(DevelopmentRailpackExamplesSeeder::examples()));
expect($limaApplications->every(fn (Application $application) => $application->build_pack === 'railpack'))->toBeTrue();
expect($limaApplications->every(fn (Application $application) => str($application->uuid)->startsWith($limaServer['uuid_prefix'])))->toBeTrue();
expect($limaApplications->every(fn (Application $application) => $application->destination->server->uuid === $limaServer['server_uuid']))->toBeTrue();
expect($limaApplications->every(
fn (Application $application) => $application->git_repository === ($examples->get(str($application->uuid)->after($limaServer['uuid_prefix'])->value())['git_repository'] ?? DevelopmentRailpackExamplesSeeder::GIT_REPOSITORY)
))->toBeTrue();
expect($limaApplications->every(
fn (Application $application) => $application->git_branch === ($examples->get(str($application->uuid)->after($limaServer['uuid_prefix'])->value())['git_branch'] ?? DevelopmentRailpackExamplesSeeder::GIT_BRANCH)
))->toBeTrue();
}
$nestjs = $applications->firstWhere('uuid', 'ubuntu24-railpack-nestjs');
$angularStatic = $applications->firstWhere('uuid', 'ubuntu24-railpack-angular-static');
$eleventyStatic = $applications->firstWhere('uuid', 'ubuntu24-railpack-eleventy-static');
$pythonFlask = $applications->firstWhere('uuid', 'ubuntu24-railpack-python-flask');
$goGin = $applications->firstWhere('uuid', 'ubuntu24-railpack-go-gin');
$rust = $applications->firstWhere('uuid', 'ubuntu24-railpack-rust');
$githubDeployKey = $applications->firstWhere('uuid', 'ubuntu24-railpack-github-deploy-key');
$gitlabDeployKey = $applications->firstWhere('uuid', 'ubuntu24-railpack-gitlab-deploy-key');
$gitlabPublic = $applications->firstWhere('uuid', 'ubuntu24-railpack-gitlab-public-example');
expect($nestjs)
->not->toBeNull()
@@ -156,6 +227,12 @@ it('skips the railpack examples outside development mode', function () {
expect(Project::query()->where('uuid', DevelopmentRailpackExamplesSeeder::PROJECT_UUID)->exists())->toBeFalse();
expect(Application::query()->where('uuid', 'railpack-nextjs-ssr')->exists())->toBeFalse();
foreach (limaServers() as $limaServer) {
expect(Project::query()->where('uuid', 'railpack-examples-lima-ubuntu-2404')->exists())->toBeFalse();
expect(Project::query()->where('uuid', 'railpack-examples-lima-ubuntu-2604')->exists())->toBeFalse();
expect(Application::query()->where('uuid', $limaServer['uuid_prefix'].'railpack-nextjs-ssr')->exists())->toBeFalse();
}
});
it('is idempotent when run multiple times', function () {
@@ -170,5 +247,14 @@ it('is idempotent when run multiple times', function () {
->first();
expect($project)->not->toBeNull();
expect($project->applications()->count())->toBe(count(DevelopmentRailpackExamplesSeeder::examples()));
expect($project->applications()->count())->toBe(count(DevelopmentRailpackExamplesSeeder::examples()) * limaServers()->count());
foreach (limaServers() as $limaServer) {
$limaEnvironment = $project->environments()
->where('uuid', $limaServer['environment_uuid'])
->first();
expect($limaEnvironment)->not->toBeNull();
expect($limaEnvironment->applications()->count())->toBe(count(DevelopmentRailpackExamplesSeeder::examples()));
}
});
+31
View File
@@ -0,0 +1,31 @@
<?php
use App\Models\Project;
use Database\Seeders\PrivateKeySeeder;
use Database\Seeders\ProjectSeeder;
use Database\Seeders\TeamSeeder;
use Database\Seeders\UserSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('seeds the first project with lima environments', function () {
$this->seed([
UserSeeder::class,
TeamSeeder::class,
PrivateKeySeeder::class,
ProjectSeeder::class,
]);
$project = Project::query()
->where('uuid', 'project')
->first();
expect($project)
->not->toBeNull()
->and($project->name)->toBe('My first project')
->and($project->environments()->pluck('uuid', 'name')->all())->toBe([
'ubuntu24' => 'ubuntu24',
'ubuntu26' => 'ubuntu26',
]);
});
@@ -0,0 +1,96 @@
<?php
use App\Enums\ProxyStatus;
use App\Enums\ProxyTypes;
use App\Models\InstanceSettings;
use App\Models\PrivateKey;
use App\Models\Server;
use App\Models\Team;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
InstanceSettings::unguarded(function () {
InstanceSettings::query()->create([
'id' => 0,
'is_registration_enabled' => true,
]);
});
$this->user = User::factory()->create();
$this->team = Team::factory()->create(['show_boarding' => false]);
$this->team->members()->attach($this->user->id, ['role' => 'owner']);
$this->actingAs($this->user);
session(['currentTeam' => $this->team]);
$this->privateKey = PrivateKey::create([
'team_id' => $this->team->id,
'name' => 'Test Key',
'private_key' => '-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk
hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA
AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV
uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA==
-----END OPENSSH PRIVATE KEY-----',
]);
});
it('shows the lima start command on lima server general pages in development', function () {
config()->set('app.env', 'local');
foreach (limaStartCommandDefinitions() as $definition) {
$server = createServerForLimaStartCommandTest($definition['uuid'], $definition['port']);
$this->get(route('server.show', ['server_uuid' => $server->uuid]))
->assertSuccessful()
->assertSee('Start this Lima VM locally')
->assertSee($definition['command']);
}
});
it('does not show the lima start command outside development', function () {
config()->set('app.env', 'testing');
$server = createServerForLimaStartCommandTest('lima-ubuntu-2404', 2222);
$this->get(route('server.show', ['server_uuid' => $server->uuid]))
->assertSuccessful()
->assertDontSee('Start this Lima VM locally')
->assertDontSee('limactl start --yes --name=coolify-lima-ubuntu-2404 docker/lima/ubuntu-2404.yaml');
});
function createServerForLimaStartCommandTest(string $uuid, int $port): Server
{
return Server::factory()->create([
'uuid' => $uuid,
'name' => $uuid,
'ip' => 'host.docker.internal',
'port' => $port,
'team_id' => test()->team->id,
'private_key_id' => test()->privateKey->id,
'proxy' => [
'type' => ProxyTypes::TRAEFIK->value,
'status' => ProxyStatus::EXITED->value,
],
]);
}
function limaStartCommandDefinitions(): array
{
return [
[
'uuid' => 'lima-ubuntu-2404',
'port' => 2222,
'command' => 'limactl start --yes --name=coolify-lima-ubuntu-2404 docker/lima/ubuntu-2404.yaml',
],
[
'uuid' => 'lima-ubuntu-2604',
'port' => 2223,
'command' => 'limactl start --yes --name=coolify-lima-ubuntu-2604 docker/lima/ubuntu-2604.yaml',
],
];
}
+66
View File
@@ -0,0 +1,66 @@
<?php
use App\Models\Server;
use Database\Seeders\PrivateKeySeeder;
use Database\Seeders\ServerSeeder;
use Database\Seeders\TeamSeeder;
use Database\Seeders\UserSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Symfony\Component\Yaml\Yaml;
uses(RefreshDatabase::class);
function limaServerDefinitions(): array
{
return [
['uuid' => 'lima-ubuntu-2404', 'port' => 2222, 'template' => 'ubuntu-2404.yaml', 'memory' => '2GiB', 'disk' => '20GiB'],
['uuid' => 'lima-ubuntu-2604', 'port' => 2223, 'template' => 'ubuntu-2604.yaml', 'memory' => '2GiB', 'disk' => '20GiB'],
];
}
it('seeds the development testing host and lima servers', function () {
$this->seed([
UserSeeder::class,
TeamSeeder::class,
PrivateKeySeeder::class,
ServerSeeder::class,
]);
$testingHost = Server::query()->where('uuid', 'localhost')->first();
expect($testingHost)
->not->toBeNull()
->and($testingHost->ip)->toBe('coolify-testing-host');
foreach (limaServerDefinitions() as $definition) {
$limaServer = Server::query()->where('uuid', $definition['uuid'])->first();
expect($limaServer)
->not->toBeNull()
->and($limaServer->name)->toBe($definition['uuid'])
->and($limaServer->ip)->toBe('host.docker.internal')
->and($limaServer->port)->toBe($definition['port'])
->and($limaServer->user)->toBe('root')
->and($limaServer->team_id)->toBe(0)
->and($limaServer->private_key_id)->toBe(1)
->and($limaServer->settings)->not->toBeNull()
->and($limaServer->settings->sentinel_custom_url)->toBe('http://host.lima.internal:8000')
->and($limaServer->destinations())->toHaveCount(1);
}
});
it('keeps the lima templates aligned with the seeded servers', function () {
foreach (limaServerDefinitions() as $definition) {
$template = Yaml::parseFile(base_path("docker/lima/{$definition['template']}"));
$script = data_get($template, 'provision.0.script');
expect(data_get($template, 'ssh.localPort'))
->toBe($definition['port'])
->and(data_get($template, 'memory'))->toBe($definition['memory'])
->and(data_get($template, 'disk'))->toBe($definition['disk'])
->and(data_get($template, 'containerd.system'))->toBeFalse()
->and(data_get($template, 'containerd.user'))->toBeFalse()
->and(data_get($template, 'networks'))->toBeNull()
->and($script)->toContain('ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFuGmoeGq/pojrsyP1pszcNVuZx9iFkCELtxrh31QJ68');
}
});