fix: auto-inject environment variables into custom Docker Compose commands

This commit is contained in:
Andras Bacsai 2025-11-18 13:07:03 +01:00
parent f8e3bb54a3
commit 274c37e333

View file

@ -41,6 +41,12 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
{
use Dispatchable, EnvironmentVariableAnalyzer, ExecuteRemoteCommand, InteractsWithQueue, Queueable, SerializesModels;
private const BUILD_TIME_ENV_PATH = '/artifacts/build-time.env';
private const BUILD_SCRIPT_PATH = '/artifacts/build.sh';
private const NIXPACKS_PLAN_PATH = '/artifacts/thegameplan.json';
public $tries = 1;
public $timeout = 3600;
@ -652,17 +658,12 @@ private function deploy_docker_compose_buildpack()
$this->save_buildtime_environment_variables();
if ($this->docker_compose_custom_build_command) {
$build_command = $this->docker_compose_custom_build_command;
// Inject --env-file flag if not already present in custom command
// This ensures build-time environment variables are available during the build
if (! str_contains($build_command, '--env-file')) {
$build_command = str_replace(
'docker compose',
'docker compose --env-file /artifacts/build-time.env',
$build_command
);
}
// Auto-inject -f (compose file) and --env-file flags using helper function
$build_command = injectDockerComposeFlags(
$this->docker_compose_custom_build_command,
"{$this->workdir}{$this->docker_compose_location}",
self::BUILD_TIME_ENV_PATH
);
// Prepend DOCKER_BUILDKIT=1 if BuildKit is supported
if ($this->dockerBuildkitSupported) {
@ -688,7 +689,7 @@ private function deploy_docker_compose_buildpack()
$command = "DOCKER_BUILDKIT=1 {$command}";
}
// Use build-time .env file from /artifacts (outside Docker context to prevent it from being in the image)
$command .= ' --env-file /artifacts/build-time.env';
$command .= ' --env-file '.self::BUILD_TIME_ENV_PATH;
if ($this->force_rebuild) {
$command .= " --project-name {$this->application->uuid} --project-directory {$this->workdir} -f {$this->workdir}{$this->docker_compose_location} build --pull --no-cache";
} else {
@ -736,9 +737,16 @@ private function deploy_docker_compose_buildpack()
$server_workdir = $this->application->workdir();
if ($this->application->settings->is_raw_compose_deployment_enabled) {
if ($this->docker_compose_custom_start_command) {
// Auto-inject -f (compose file) and --env-file flags using helper function
$start_command = injectDockerComposeFlags(
$this->docker_compose_custom_start_command,
"{$server_workdir}{$this->docker_compose_location}",
"{$server_workdir}/.env"
);
$this->write_deployment_configurations();
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "cd {$this->workdir} && {$this->docker_compose_custom_start_command}"), 'hidden' => true],
[executeInDocker($this->deployment_uuid, "cd {$this->workdir} && {$start_command}"), 'hidden' => true],
);
} else {
$this->write_deployment_configurations();
@ -754,9 +762,18 @@ private function deploy_docker_compose_buildpack()
}
} else {
if ($this->docker_compose_custom_start_command) {
// Auto-inject -f (compose file) and --env-file flags using helper function
// Use $this->workdir for non-preserve-repository mode
$workdir_path = $this->preserveRepository ? $server_workdir : $this->workdir;
$start_command = injectDockerComposeFlags(
$this->docker_compose_custom_start_command,
"{$workdir_path}{$this->docker_compose_location}",
"{$workdir_path}/.env"
);
$this->write_deployment_configurations();
$this->execute_remote_command(
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$this->docker_compose_custom_start_command}"), 'hidden' => true],
[executeInDocker($this->deployment_uuid, "cd {$this->basedir} && {$start_command}"), 'hidden' => true],
);
} else {
$command = "{$this->coolify_variables} docker compose";
@ -1555,10 +1572,10 @@ private function save_buildtime_environment_variables()
$this->execute_remote_command(
[
executeInDocker($this->deployment_uuid, "echo '$envs_base64' | base64 -d | tee /artifacts/build-time.env > /dev/null"),
executeInDocker($this->deployment_uuid, "echo '$envs_base64' | base64 -d | tee ".self::BUILD_TIME_ENV_PATH.' > /dev/null'),
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build-time.env'),
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_TIME_ENV_PATH),
'hidden' => true,
],
);
@ -1569,7 +1586,7 @@ private function save_buildtime_environment_variables()
$this->execute_remote_command(
[
executeInDocker($this->deployment_uuid, 'touch /artifacts/build-time.env'),
executeInDocker($this->deployment_uuid, 'touch '.self::BUILD_TIME_ENV_PATH),
]
);
}
@ -2695,15 +2712,15 @@ private function build_static_image()
executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d | tee {$this->workdir}/nginx.conf > /dev/null"),
],
[
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee ".self::BUILD_SCRIPT_PATH.' > /dev/null'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'bash '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
]
);
@ -2711,7 +2728,7 @@ private function build_static_image()
}
/**
* Wrap a docker build command with environment export from /artifacts/build-time.env
* Wrap a docker build command with environment export from build-time .env file
* This enables shell interpolation of variables (e.g., APP_URL=$COOLIFY_URL)
*
* @param string $build_command The docker build command to wrap
@ -2719,7 +2736,7 @@ private function build_static_image()
*/
private function wrap_build_command_with_env_export(string $build_command): string
{
return "cd {$this->workdir} && set -a && source /artifacts/build-time.env && set +a && {$build_command}";
return "cd {$this->workdir} && set -a && source ".self::BUILD_TIME_ENV_PATH." && set +a && {$build_command}";
}
private function build_image()
@ -2758,10 +2775,10 @@ private function build_image()
}
if ($this->application->build_pack === 'nixpacks') {
$this->nixpacks_plan = base64_encode($this->nixpacks_plan);
$this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d | tee /artifacts/thegameplan.json > /dev/null"), 'hidden' => true]);
$this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d | tee ".self::NIXPACKS_PLAN_PATH.' > /dev/null'), 'hidden' => true]);
if ($this->force_rebuild) {
$this->execute_remote_command([
executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --no-cache --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"),
executeInDocker($this->deployment_uuid, 'nixpacks build -c '.self::NIXPACKS_PLAN_PATH." --no-cache --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"),
'hidden' => true,
], [
executeInDocker($this->deployment_uuid, "cat {$this->workdir}/.nixpacks/Dockerfile"),
@ -2781,7 +2798,7 @@ private function build_image()
}
} else {
$this->execute_remote_command([
executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"),
executeInDocker($this->deployment_uuid, 'nixpacks build -c '.self::NIXPACKS_PLAN_PATH." --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->build_image_name} {$this->workdir} -o {$this->workdir}"),
'hidden' => true,
], [
executeInDocker($this->deployment_uuid, "cat {$this->workdir}/.nixpacks/Dockerfile"),
@ -2805,19 +2822,19 @@ private function build_image()
$base64_build_command = base64_encode($build_command);
$this->execute_remote_command(
[
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee ".self::BUILD_SCRIPT_PATH.' > /dev/null'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'bash '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
]
);
$this->execute_remote_command([executeInDocker($this->deployment_uuid, 'rm /artifacts/thegameplan.json'), 'hidden' => true]);
$this->execute_remote_command([executeInDocker($this->deployment_uuid, 'rm '.self::NIXPACKS_PLAN_PATH), 'hidden' => true]);
} else {
// Dockerfile buildpack
if ($this->dockerBuildkitSupported && $this->application->settings->use_build_secrets) {
@ -2849,15 +2866,15 @@ private function build_image()
$base64_build_command = base64_encode($build_command);
$this->execute_remote_command(
[
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee ".self::BUILD_SCRIPT_PATH.' > /dev/null'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'bash '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
]
);
@ -2888,15 +2905,15 @@ private function build_image()
executeInDocker($this->deployment_uuid, "echo '{$nginx_config}' | base64 -d | tee {$this->workdir}/nginx.conf > /dev/null"),
],
[
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee ".self::BUILD_SCRIPT_PATH.' > /dev/null'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'bash '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
]
);
@ -2923,25 +2940,25 @@ private function build_image()
$base64_build_command = base64_encode($build_command);
$this->execute_remote_command(
[
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee ".self::BUILD_SCRIPT_PATH.' > /dev/null'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'bash '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
]
);
} else {
if ($this->application->build_pack === 'nixpacks') {
$this->nixpacks_plan = base64_encode($this->nixpacks_plan);
$this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d | tee /artifacts/thegameplan.json > /dev/null"), 'hidden' => true]);
$this->execute_remote_command([executeInDocker($this->deployment_uuid, "echo '{$this->nixpacks_plan}' | base64 -d | tee ".self::NIXPACKS_PLAN_PATH.' > /dev/null'), 'hidden' => true]);
if ($this->force_rebuild) {
$this->execute_remote_command([
executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --no-cache --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"),
executeInDocker($this->deployment_uuid, 'nixpacks build -c '.self::NIXPACKS_PLAN_PATH." --no-cache --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"),
'hidden' => true,
], [
executeInDocker($this->deployment_uuid, "cat {$this->workdir}/.nixpacks/Dockerfile"),
@ -2962,7 +2979,7 @@ private function build_image()
}
} else {
$this->execute_remote_command([
executeInDocker($this->deployment_uuid, "nixpacks build -c /artifacts/thegameplan.json --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"),
executeInDocker($this->deployment_uuid, 'nixpacks build -c '.self::NIXPACKS_PLAN_PATH." --cache-key '{$this->application->uuid}' --no-error-without-start -n {$this->production_image_name} {$this->workdir} -o {$this->workdir}"),
'hidden' => true,
], [
executeInDocker($this->deployment_uuid, "cat {$this->workdir}/.nixpacks/Dockerfile"),
@ -2985,19 +3002,19 @@ private function build_image()
$base64_build_command = base64_encode($build_command);
$this->execute_remote_command(
[
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee ".self::BUILD_SCRIPT_PATH.' > /dev/null'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'bash '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
]
);
$this->execute_remote_command([executeInDocker($this->deployment_uuid, 'rm /artifacts/thegameplan.json'), 'hidden' => true]);
$this->execute_remote_command([executeInDocker($this->deployment_uuid, 'rm '.self::NIXPACKS_PLAN_PATH), 'hidden' => true]);
} else {
// Dockerfile buildpack
if ($this->dockerBuildkitSupported && $this->application->settings->use_build_secrets) {
@ -3030,15 +3047,15 @@ private function build_image()
$base64_build_command = base64_encode($build_command);
$this->execute_remote_command(
[
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee /artifacts/build.sh > /dev/null"),
executeInDocker($this->deployment_uuid, "echo '{$base64_build_command}' | base64 -d | tee ".self::BUILD_SCRIPT_PATH.' > /dev/null'),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'cat /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'cat '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
],
[
executeInDocker($this->deployment_uuid, 'bash /artifacts/build.sh'),
executeInDocker($this->deployment_uuid, 'bash '.self::BUILD_SCRIPT_PATH),
'hidden' => true,
]
);