refactor(railpack): extract static image build, fix port logic, bump to v0.22.0
Extract build_railpack_static_image() into its own method, prevent port override when is_static is set, bump Railpack to 0.22.0, and improve test setup with beforeEach and correct polymorphic env var fields.
This commit is contained in:
parent
793077d74f
commit
cddbaf581f
7 changed files with 93 additions and 62 deletions
|
|
@ -483,7 +483,7 @@ private function decide_what_to_do()
|
||||||
} elseif ($this->application->build_pack === 'railpack') {
|
} elseif ($this->application->build_pack === 'railpack') {
|
||||||
$this->deploy_railpack_buildpack();
|
$this->deploy_railpack_buildpack();
|
||||||
} else {
|
} else {
|
||||||
throw new \RuntimeException("Unsupported build pack: {$this->application->build_pack}");
|
throw new DeploymentException("Unsupported build pack: {$this->application->build_pack}");
|
||||||
}
|
}
|
||||||
$this->post_deployment();
|
$this->post_deployment();
|
||||||
}
|
}
|
||||||
|
|
@ -2517,35 +2517,40 @@ private function build_railpack_image(): void
|
||||||
|
|
||||||
// Step 3: If static, copy built assets into nginx image
|
// Step 3: If static, copy built assets into nginx image
|
||||||
if ($this->application->settings->is_static) {
|
if ($this->application->settings->is_static) {
|
||||||
$publishDir = trim($this->application->publish_directory, '/');
|
$this->build_railpack_static_image();
|
||||||
$publishDir = $publishDir ? "/{$publishDir}" : '';
|
}
|
||||||
$dockerfile = base64_encode("FROM {$this->application->static_image}
|
}
|
||||||
|
|
||||||
|
private function build_railpack_static_image(): void
|
||||||
|
{
|
||||||
|
$publishDir = trim($this->application->publish_directory, '/');
|
||||||
|
$publishDir = $publishDir ? "/{$publishDir}" : '';
|
||||||
|
$dockerfile = base64_encode("FROM {$this->application->static_image}
|
||||||
WORKDIR /usr/share/nginx/html/
|
WORKDIR /usr/share/nginx/html/
|
||||||
LABEL coolify.deploymentId={$this->deployment_uuid}
|
LABEL coolify.deploymentId={$this->deployment_uuid}
|
||||||
COPY --from={$this->build_image_name} /app{$publishDir} .
|
COPY --from={$this->build_image_name} /app{$publishDir} .
|
||||||
COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
COPY ./nginx.conf /etc/nginx/conf.d/default.conf");
|
||||||
|
|
||||||
if (str($this->application->custom_nginx_configuration)->isNotEmpty()) {
|
if (str($this->application->custom_nginx_configuration)->isNotEmpty()) {
|
||||||
$nginx_config = base64_encode($this->application->custom_nginx_configuration);
|
$nginx_config = base64_encode($this->application->custom_nginx_configuration);
|
||||||
} else {
|
} else {
|
||||||
$nginx_config = $this->application->settings->is_spa
|
$nginx_config = $this->application->settings->is_spa
|
||||||
? base64_encode(defaultNginxConfiguration('spa'))
|
? base64_encode(defaultNginxConfiguration('spa'))
|
||||||
: base64_encode(defaultNginxConfiguration());
|
: base64_encode(defaultNginxConfiguration());
|
||||||
}
|
|
||||||
|
|
||||||
$static_build = $this->dockerBuildkitSupported
|
|
||||||
? "DOCKER_BUILDKIT=1 docker build {$this->addHosts} --network host -f {$this->workdir}/Dockerfile --progress plain -t {$this->production_image_name} {$this->workdir}"
|
|
||||||
: "docker build {$this->addHosts} --network host -f {$this->workdir}/Dockerfile -t {$this->production_image_name} {$this->workdir}";
|
|
||||||
|
|
||||||
$base64_static_build = base64_encode($static_build);
|
|
||||||
$this->execute_remote_command(
|
|
||||||
[executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d | tee {$this->workdir}/Dockerfile > /dev/null")],
|
|
||||||
[executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d | tee {$this->workdir}/nginx.conf > /dev/null")],
|
|
||||||
[executeInDocker($this->deployment_uuid, "echo '{$base64_static_build}' | base64 -d | tee ".self::BUILD_SCRIPT_PATH.' > /dev/null'), 'hidden' => true],
|
|
||||||
[executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_SCRIPT_PATH), 'hidden' => true],
|
|
||||||
[executeInDocker($this->deployment_uuid, 'bash '.self::BUILD_SCRIPT_PATH), 'hidden' => true],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$static_build = $this->dockerBuildkitSupported
|
||||||
|
? "DOCKER_BUILDKIT=1 docker build {$this->addHosts} --network host -f {$this->workdir}/Dockerfile --progress plain -t {$this->production_image_name} {$this->workdir}"
|
||||||
|
: "docker build {$this->addHosts} --network host -f {$this->workdir}/Dockerfile -t {$this->production_image_name} {$this->workdir}";
|
||||||
|
|
||||||
|
$base64_static_build = base64_encode($static_build);
|
||||||
|
$this->execute_remote_command(
|
||||||
|
[executeInDocker($this->deployment_uuid, "echo '{$dockerfile}' | base64 -d | tee {$this->workdir}/Dockerfile > /dev/null")],
|
||||||
|
[executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d | tee {$this->workdir}/nginx.conf > /dev/null")],
|
||||||
|
[executeInDocker($this->deployment_uuid, "echo '{$base64_static_build}' | base64 -d | tee ".self::BUILD_SCRIPT_PATH.' > /dev/null'), 'hidden' => true],
|
||||||
|
[executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_SCRIPT_PATH), 'hidden' => true],
|
||||||
|
[executeInDocker($this->deployment_uuid, 'bash '.self::BUILD_SCRIPT_PATH), 'hidden' => true],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function generate_coolify_env_variables(bool $forBuildTime = false): Collection
|
private function generate_coolify_env_variables(bool $forBuildTime = false): Collection
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,9 @@ public function updatedBuildPack()
|
||||||
{
|
{
|
||||||
if ($this->build_pack === 'nixpacks' || $this->build_pack === 'railpack') {
|
if ($this->build_pack === 'nixpacks' || $this->build_pack === 'railpack') {
|
||||||
$this->show_is_static = true;
|
$this->show_is_static = true;
|
||||||
$this->port = 3000;
|
if (! $this->is_static) {
|
||||||
|
$this->port = 3000;
|
||||||
|
}
|
||||||
} elseif ($this->build_pack === 'static') {
|
} elseif ($this->build_pack === 'static') {
|
||||||
$this->show_is_static = false;
|
$this->show_is_static = false;
|
||||||
$this->is_static = false;
|
$this->is_static = false;
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,9 @@ public function updatedBuildPack()
|
||||||
{
|
{
|
||||||
if ($this->build_pack === 'nixpacks' || $this->build_pack === 'railpack') {
|
if ($this->build_pack === 'nixpacks' || $this->build_pack === 'railpack') {
|
||||||
$this->show_is_static = true;
|
$this->show_is_static = true;
|
||||||
$this->port = 3000;
|
if (! $this->is_static) {
|
||||||
|
$this->port = 3000;
|
||||||
|
}
|
||||||
} elseif ($this->build_pack === 'static') {
|
} elseif ($this->build_pack === 'static') {
|
||||||
$this->show_is_static = false;
|
$this->show_is_static = false;
|
||||||
$this->is_static = false;
|
$this->is_static = false;
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,9 @@ public function updatedBuildPack()
|
||||||
{
|
{
|
||||||
if ($this->build_pack === 'nixpacks' || $this->build_pack === 'railpack') {
|
if ($this->build_pack === 'nixpacks' || $this->build_pack === 'railpack') {
|
||||||
$this->show_is_static = true;
|
$this->show_is_static = true;
|
||||||
$this->port = 3000;
|
if (! $this->isStatic) {
|
||||||
|
$this->port = 3000;
|
||||||
|
}
|
||||||
} elseif ($this->build_pack === 'static') {
|
} elseif ($this->build_pack === 'static') {
|
||||||
$this->show_is_static = false;
|
$this->show_is_static = false;
|
||||||
$this->isStatic = false;
|
$this->isStatic = false;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ ARG PACK_VERSION=0.38.2
|
||||||
# https://github.com/railwayapp/nixpacks/releases
|
# https://github.com/railwayapp/nixpacks/releases
|
||||||
ARG NIXPACKS_VERSION=1.41.0
|
ARG NIXPACKS_VERSION=1.41.0
|
||||||
# https://github.com/railwayapp/railpack/releases
|
# https://github.com/railwayapp/railpack/releases
|
||||||
ARG RAILPACK_VERSION=0.21.0
|
ARG RAILPACK_VERSION=0.22.0
|
||||||
# https://github.com/jdx/mise/releases — must match railpack's pinned version (https://raw.githubusercontent.com/railwayapp/railpack/refs/heads/main/core/mise/version.txt)
|
# https://github.com/jdx/mise/releases — must match railpack's pinned version (https://raw.githubusercontent.com/railwayapp/railpack/refs/heads/main/core/mise/version.txt)
|
||||||
ARG MISE_VERSION=2026.3.12
|
ARG MISE_VERSION=2026.3.12
|
||||||
# https://github.com/minio/mc/releases
|
# https://github.com/minio/mc/releases
|
||||||
|
|
|
||||||
|
|
@ -78,26 +78,29 @@
|
||||||
|
|
||||||
// Add environment variables that should be deleted
|
// Add environment variables that should be deleted
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
'application_id' => $application->id,
|
'resourceable_type' => Application::class,
|
||||||
|
'resourceable_id' => $application->id,
|
||||||
'key' => 'SERVICE_FQDN_APP',
|
'key' => 'SERVICE_FQDN_APP',
|
||||||
'value' => 'app.example.com',
|
'value' => 'app.example.com',
|
||||||
'is_build_time' => false,
|
'is_buildtime' => false,
|
||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
'application_id' => $application->id,
|
'resourceable_type' => Application::class,
|
||||||
|
'resourceable_id' => $application->id,
|
||||||
'key' => 'SERVICE_URL_APP',
|
'key' => 'SERVICE_URL_APP',
|
||||||
'value' => 'http://app.example.com',
|
'value' => 'http://app.example.com',
|
||||||
'is_build_time' => false,
|
'is_buildtime' => false,
|
||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
EnvironmentVariable::create([
|
EnvironmentVariable::create([
|
||||||
'application_id' => $application->id,
|
'resourceable_type' => Application::class,
|
||||||
|
'resourceable_id' => $application->id,
|
||||||
'key' => 'REGULAR_VAR',
|
'key' => 'REGULAR_VAR',
|
||||||
'value' => 'should_remain',
|
'value' => 'should_remain',
|
||||||
'is_build_time' => false,
|
'is_buildtime' => false,
|
||||||
'is_preview' => false,
|
'is_preview' => false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -154,6 +157,34 @@
|
||||||
'docker_compose_raw' => 'version: "3.8"\nservices:\n app:\n image: nginx',
|
'docker_compose_raw' => 'version: "3.8"\nservices:\n app:\n image: nginx',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Add environment variables that should be deleted
|
||||||
|
EnvironmentVariable::create([
|
||||||
|
'resourceable_type' => Application::class,
|
||||||
|
'resourceable_id' => $application->id,
|
||||||
|
'key' => 'SERVICE_FQDN_APP',
|
||||||
|
'value' => 'app.example.com',
|
||||||
|
'is_buildtime' => false,
|
||||||
|
'is_preview' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
EnvironmentVariable::create([
|
||||||
|
'resourceable_type' => Application::class,
|
||||||
|
'resourceable_id' => $application->id,
|
||||||
|
'key' => 'SERVICE_URL_APP',
|
||||||
|
'value' => 'http://app.example.com',
|
||||||
|
'is_buildtime' => false,
|
||||||
|
'is_preview' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
EnvironmentVariable::create([
|
||||||
|
'resourceable_type' => Application::class,
|
||||||
|
'resourceable_id' => $application->id,
|
||||||
|
'key' => 'REGULAR_VAR',
|
||||||
|
'value' => 'should_remain',
|
||||||
|
'is_buildtime' => false,
|
||||||
|
'is_preview' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
$application->build_pack = 'railpack';
|
$application->build_pack = 'railpack';
|
||||||
$application->save();
|
$application->save();
|
||||||
$application->refresh();
|
$application->refresh();
|
||||||
|
|
@ -161,6 +192,13 @@
|
||||||
expect($application->build_pack)->toBe('railpack');
|
expect($application->build_pack)->toBe('railpack');
|
||||||
expect($application->docker_compose_domains)->toBeNull();
|
expect($application->docker_compose_domains)->toBeNull();
|
||||||
expect($application->docker_compose_raw)->toBeNull();
|
expect($application->docker_compose_raw)->toBeNull();
|
||||||
|
|
||||||
|
// Verify SERVICE_FQDN_* and SERVICE_URL_* were deleted
|
||||||
|
expect($application->environment_variables()->where('key', 'SERVICE_FQDN_APP')->count())->toBe(0);
|
||||||
|
expect($application->environment_variables()->where('key', 'SERVICE_URL_APP')->count())->toBe(0);
|
||||||
|
|
||||||
|
// Verify regular variables remain
|
||||||
|
expect($application->environment_variables()->where('key', 'REGULAR_VAR')->count())->toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('model does not clear dockerfile fields when switching to dockerfile', function () {
|
test('model does not clear dockerfile fields when switching to dockerfile', function () {
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,15 @@
|
||||||
uses(RefreshDatabase::class);
|
uses(RefreshDatabase::class);
|
||||||
|
|
||||||
describe('Application Railpack Support', function () {
|
describe('Application Railpack Support', function () {
|
||||||
test('could_set_build_commands returns true for railpack', function () {
|
beforeEach(function () {
|
||||||
$team = Team::factory()->create();
|
$team = Team::factory()->create();
|
||||||
$project = Project::factory()->create(['team_id' => $team->id]);
|
$project = Project::factory()->create(['team_id' => $team->id]);
|
||||||
$environment = Environment::factory()->create(['project_id' => $project->id]);
|
$this->environment = Environment::factory()->create(['project_id' => $project->id]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('could_set_build_commands returns true for railpack', function () {
|
||||||
$application = Application::factory()->create([
|
$application = Application::factory()->create([
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $this->environment->id,
|
||||||
'build_pack' => 'railpack',
|
'build_pack' => 'railpack',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -24,12 +26,8 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
test('could_set_build_commands returns true for nixpacks', function () {
|
test('could_set_build_commands returns true for nixpacks', function () {
|
||||||
$team = Team::factory()->create();
|
|
||||||
$project = Project::factory()->create(['team_id' => $team->id]);
|
|
||||||
$environment = Environment::factory()->create(['project_id' => $project->id]);
|
|
||||||
|
|
||||||
$application = Application::factory()->create([
|
$application = Application::factory()->create([
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $this->environment->id,
|
||||||
'build_pack' => 'nixpacks',
|
'build_pack' => 'nixpacks',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -37,12 +35,8 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
test('could_set_build_commands returns false for dockerfile', function () {
|
test('could_set_build_commands returns false for dockerfile', function () {
|
||||||
$team = Team::factory()->create();
|
|
||||||
$project = Project::factory()->create(['team_id' => $team->id]);
|
|
||||||
$environment = Environment::factory()->create(['project_id' => $project->id]);
|
|
||||||
|
|
||||||
$application = Application::factory()->create([
|
$application = Application::factory()->create([
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $this->environment->id,
|
||||||
'build_pack' => 'dockerfile',
|
'build_pack' => 'dockerfile',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -50,12 +44,8 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
test('railpack_environment_variables returns only RAILPACK_ prefixed vars', function () {
|
test('railpack_environment_variables returns only RAILPACK_ prefixed vars', function () {
|
||||||
$team = Team::factory()->create();
|
|
||||||
$project = Project::factory()->create(['team_id' => $team->id]);
|
|
||||||
$environment = Environment::factory()->create(['project_id' => $project->id]);
|
|
||||||
|
|
||||||
$application = Application::factory()->create([
|
$application = Application::factory()->create([
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $this->environment->id,
|
||||||
'build_pack' => 'railpack',
|
'build_pack' => 'railpack',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -92,12 +82,8 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
test('runtime_environment_variables excludes RAILPACK_ and NIXPACKS_ prefixed vars', function () {
|
test('runtime_environment_variables excludes RAILPACK_ and NIXPACKS_ prefixed vars', function () {
|
||||||
$team = Team::factory()->create();
|
|
||||||
$project = Project::factory()->create(['team_id' => $team->id]);
|
|
||||||
$environment = Environment::factory()->create(['project_id' => $project->id]);
|
|
||||||
|
|
||||||
$application = Application::factory()->create([
|
$application = Application::factory()->create([
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $this->environment->id,
|
||||||
'build_pack' => 'railpack',
|
'build_pack' => 'railpack',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -134,12 +120,8 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
test('railpack_environment_variables_preview returns only RAILPACK_ prefixed preview vars', function () {
|
test('railpack_environment_variables_preview returns only RAILPACK_ prefixed preview vars', function () {
|
||||||
$team = Team::factory()->create();
|
|
||||||
$project = Project::factory()->create(['team_id' => $team->id]);
|
|
||||||
$environment = Environment::factory()->create(['project_id' => $project->id]);
|
|
||||||
|
|
||||||
$application = Application::factory()->create([
|
$application = Application::factory()->create([
|
||||||
'environment_id' => $environment->id,
|
'environment_id' => $this->environment->id,
|
||||||
'build_pack' => 'railpack',
|
'build_pack' => 'railpack',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue