feat(railpack): expose COOLIFY_* vars at build time and generalize buildpack control flag

Mirrors Nixpacks behavior: inject COOLIFY_* and SOURCE_COMMIT into
railpack build variables so apps (e.g. SPAs baking public URLs) can
read them via /run/secrets/<KEY>.

Rename is_nixpacks → is_buildpack_control to cover both NIXPACKS_ and
RAILPACK_ prefixed keys. Update the env variable view and appends list
accordingly.

Promote generate_coolify_env_variables to protected for testability.
This commit is contained in:
Andras Bacsai committed 2026-04-30 18:31:41 +02:00
1 parent 21eac6654f
commit b6ca6b1b20
5 files changed
+122 -14

No files matched your search

@@ -48,6 +48,7 @@ it('generates escaped railpack env args from resolved values and includes instal
$job = Mockery::mock(ApplicationDeploymentJob::class)->makePartial();
$job->shouldAllowMockingProtectedMethods();
$job->shouldReceive('generate_coolify_env_variables')->andReturn(collect([]));
$reflection = new ReflectionClass(ApplicationDeploymentJob::class);
$applicationProperty = $reflection->getProperty('application');
@@ -102,6 +103,7 @@ it('uses preview railpack environment variables for preview deployments', functi
$job = Mockery::mock(ApplicationDeploymentJob::class)->makePartial();
$job->shouldAllowMockingProtectedMethods();
$job->shouldReceive('generate_coolify_env_variables')->andReturn(collect([]));
$reflection = new ReflectionClass(ApplicationDeploymentJob::class);
$applicationProperty = $reflection->getProperty('application');
@@ -124,3 +126,70 @@ it('uses preview railpack environment variables for preview deployments', functi
'RAILPACK_PREVIEW_ONLY' => 'preview-value',
]);
});
it('merges coolify env variables into railpack build variables', function () {
$application = Mockery::mock(Application::class);
$application->shouldReceive('getAttribute')->with('install_command')->andReturn(null);
$userVar = Mockery::mock(EnvironmentVariable::class)->makePartial();
$userVar->forceFill([
'key' => 'MY_BUILD_VAR',
'is_literal' => false,
'is_multiline' => false,
]);
$userVar->shouldReceive('getResolvedValueWithServer')->once()->with(Mockery::type(Server::class))->andReturn('hello');
$envQuery = Mockery::mock();
$envQuery->shouldReceive('where')->with('is_buildtime', true)->once()->andReturnSelf();
$envQuery->shouldReceive('get')->once()->andReturn(collect([$userVar]));
$application->shouldReceive('environment_variables')->once()->andReturn($envQuery);
$job = Mockery::mock(ApplicationDeploymentJob::class)->makePartial();
$job->shouldAllowMockingProtectedMethods();
$job->shouldReceive('generate_coolify_env_variables')
->with(true)
->andReturn(collect([
'COOLIFY_URL' => 'https://app.example.com',
'COOLIFY_FQDN' => 'app.example.com',
'COOLIFY_BRANCH' => 'main',
'COOLIFY_RESOURCE_UUID' => 'app-uuid',
'SOURCE_COMMIT' => 'abc123',
'EMPTY_VAR' => '',
'NULL_VAR' => null,
]));
$reflection = new ReflectionClass(ApplicationDeploymentJob::class);
$applicationProperty = $reflection->getProperty('application');
$applicationProperty->setAccessible(true);
$applicationProperty->setValue($job, $application);
$pullRequestProperty = $reflection->getProperty('pull_request_id');
$pullRequestProperty->setAccessible(true);
$pullRequestProperty->setValue($job, 0);
$mainServerProperty = $reflection->getProperty('mainServer');
$mainServerProperty->setAccessible(true);
$mainServerProperty->setValue($job, Mockery::mock(Server::class));
$method = $reflection->getMethod('generate_railpack_env_variables');
$method->setAccessible(true);
$variables = $method->invoke($job);
expect($variables->all())->toBe([
'MY_BUILD_VAR' => 'hello',
'COOLIFY_URL' => 'https://app.example.com',
'COOLIFY_FQDN' => 'app.example.com',
'COOLIFY_BRANCH' => 'main',
'COOLIFY_RESOURCE_UUID' => 'app-uuid',
'SOURCE_COMMIT' => 'abc123',
]);
$envArgsProperty = $reflection->getProperty('env_railpack_args');
$envArgsProperty->setAccessible(true);
$envArgs = $envArgsProperty->getValue($job);
expect($envArgs)->toContain("--env 'COOLIFY_URL=https://app.example.com'");
expect($envArgs)->toContain("--env 'SOURCE_COMMIT=abc123'");
expect($envArgs)->not->toContain('EMPTY_VAR');
expect($envArgs)->not->toContain('NULL_VAR');
});
@@ -0,0 +1,37 @@
<?php
use App\Models\EnvironmentVariable;
it('flags NIXPACKS_ keys as buildpack control variables', function () {
$env = new EnvironmentVariable;
$env->key = 'NIXPACKS_NODE_VERSION';
expect($env->is_buildpack_control)->toBeTrue();
});
it('flags RAILPACK_ keys as buildpack control variables', function () {
$env = new EnvironmentVariable;
$env->key = 'RAILPACK_NODE_VERSION';
expect($env->is_buildpack_control)->toBeTrue();
});
it('does not flag user-defined keys as buildpack control variables', function () {
$env = new EnvironmentVariable;
$env->key = 'MY_BUILD_VAR';
expect($env->is_buildpack_control)->toBeFalse();
});
it('does not flag empty key as buildpack control variable', function () {
$env = new EnvironmentVariable;
expect($env->is_buildpack_control)->toBeFalse();
});
it('lists is_buildpack_control in appends and drops legacy is_nixpacks', function () {
$env = new EnvironmentVariable;
expect($env->getAppends())->toContain('is_buildpack_control');
expect($env->getAppends())->not->toContain('is_nixpacks');
});