Allow explicit runtime channel selection

This commit is contained in:
Jeppe Bundgaard
2026-05-20 19:39:23 +02:00
parent f7ff9f0a3b
commit 8a1ec91b9e
2 changed files with 137 additions and 8 deletions
@@ -276,8 +276,11 @@ it('updates existing frontend Coolify applications away from legacy Nixpacks det
expect($payload['build_pack'])->toBe('dockerfile');
expect($payload['ports_exposes'])->toBe('80');
expect($payload['dockerfile_location'])->toBe('/Dockerfile.coolify-frontend');
expect($payload)->not->toHaveKey('publish_directory');
expect($payload)->not->toHaveKey('is_static');
expect($payload['install_command'])->toBe('');
expect($payload['build_command'])->toBe('');
expect($payload['publish_directory'])->toBe('');
expect($payload['is_static'])->toBeFalse();
expect($payload['is_spa'])->toBeFalse();
});
it('can use the Coolify instance default GitHub App when source targets do not store it yet', function (): void {
@@ -654,6 +657,77 @@ it('normalizes channel-prefixed API ingress paths before route dispatch', functi
}
});
it('allows explicit runtime selection of any enabled release channel', function (): void {
$db = $GLOBALS['db'] ?? null;
try {
$GLOBALS['db'] = new class {
public function prepare(string $sql): object
{
return new class {
/** @var array<int,mixed> */
private array $params = [];
public function bind_param(string $types, mixed &...$params): void
{
$this->params = $params;
}
public function execute(): void
{
}
public function get_result(): object
{
$slug = (string)($this->params[0] ?? '');
return new class($slug) {
public function __construct(private readonly string $slug)
{
}
public function fetch_all(int $mode): array
{
if ($this->slug !== 'internal') {
return [];
}
return [[
'id' => 4,
'slug' => 'internal',
'name' => 'Internal',
'enabled' => 1,
'default_channel' => 0,
'deleted_at' => null,
]];
}
};
}
};
}
};
$manager = new release_manager();
$chooseRuntimeChannel = new ReflectionMethod(release_manager::class, 'chooseRuntimeChannel');
$chooseRuntimeChannel->setAccessible(true);
$channel = $chooseRuntimeChannel->invoke($manager, [
'id' => 1,
'slug' => 'stable',
'enabled' => 1,
'default_channel' => 1,
], [], 'internal');
expect($channel['slug'])->toBe('internal');
} finally {
if ($db === null) {
unset($GLOBALS['db']);
} else {
$GLOBALS['db'] = $db;
}
}
});
it('requires non-default release channel runtime URLs and preserves load balancer paths', function (): void {
$manager = new release_manager();
$availability = new ReflectionMethod(release_manager::class, 'channelAvailability');
@@ -808,7 +882,8 @@ it('exposes release version git commit metadata for runtime channel cards', func
expect($version['deployed_at'])->toBe('2026-05-19 10:20:00');
});
it('chooses a requested runtime channel only when it is available to the principal', function (): void {
it('chooses requested runtime channels from available channels or enabled channel slugs', function (): void {
$db = $GLOBALS['db'] ?? null;
$manager = new release_manager();
$choose = new ReflectionMethod(release_manager::class, 'chooseRuntimeChannel');
$choose->setAccessible(true);
@@ -826,9 +901,42 @@ it('chooses a requested runtime channel only when it is available to the princip
'default_channel' => 0,
];
expect($choose->invoke($manager, $stable, [$stable, $canary], 'canary'))->toBe($canary);
expect($choose->invoke($manager, $stable, [$stable, $canary], 'unknown'))->toBe($stable);
expect($choose->invoke($manager, $canary, [$stable, $canary], ''))->toBe($canary);
try {
$GLOBALS['db'] = new class {
public function prepare(string $sql): object
{
return new class {
public function bind_param(string $types, mixed &...$params): void
{
}
public function execute(): void
{
}
public function get_result(): object
{
return new class {
public function fetch_all(int $mode): array
{
return [];
}
};
}
};
}
};
expect($choose->invoke($manager, $stable, [$stable, $canary], 'canary'))->toBe($canary);
expect($choose->invoke($manager, $stable, [$stable, $canary], 'unknown'))->toBe($stable);
expect($choose->invoke($manager, $canary, [$stable, $canary], ''))->toBe($canary);
} finally {
if ($db === null) {
unset($GLOBALS['db']);
} else {
$GLOBALS['db'] = $db;
}
}
});
it('normalizes release assignment subject suggestions without leaking private fields', function (): void {