fix: prevent duplicate environment variables in buildtime.env and support nixpacks plan variable overrides (#7373)
This commit is contained in:
commit
0209bb63e2
1 changed files with 73 additions and 20 deletions
|
|
@ -1401,15 +1401,44 @@ private function generate_buildtime_environment_variables()
|
||||||
$this->application_deployment_queue->addLogEntry('[DEBUG] ========================================');
|
$this->application_deployment_queue->addLogEntry('[DEBUG] ========================================');
|
||||||
}
|
}
|
||||||
|
|
||||||
$envs = collect([]);
|
// Use associative array for automatic deduplication
|
||||||
|
$envs_dict = [];
|
||||||
|
|
||||||
|
// 1. Add nixpacks plan variables FIRST (lowest priority - can be overridden)
|
||||||
|
if ($this->build_pack === 'nixpacks' &&
|
||||||
|
isset($this->nixpacks_plan_json) &&
|
||||||
|
$this->nixpacks_plan_json->isNotEmpty()) {
|
||||||
|
|
||||||
|
$planVariables = data_get($this->nixpacks_plan_json, 'variables', []);
|
||||||
|
|
||||||
|
if (! empty($planVariables)) {
|
||||||
|
if (isDev()) {
|
||||||
|
$this->application_deployment_queue->addLogEntry('[DEBUG] Adding '.count($planVariables).' nixpacks plan variables to buildtime.env');
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($planVariables as $key => $value) {
|
||||||
|
// Skip COOLIFY_* and SERVICE_* - they'll be added later with higher priority
|
||||||
|
if (str_starts_with($key, 'COOLIFY_') || str_starts_with($key, 'SERVICE_')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$escapedValue = escapeBashEnvValue($value);
|
||||||
|
$envs_dict[$key] = $escapedValue;
|
||||||
|
|
||||||
|
if (isDev()) {
|
||||||
|
$this->application_deployment_queue->addLogEntry("[DEBUG] Nixpacks var: {$key}={$escapedValue}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Add COOLIFY variables (can override nixpacks, but shouldn't happen in practice)
|
||||||
$coolify_envs = $this->generate_coolify_env_variables(forBuildTime: true);
|
$coolify_envs = $this->generate_coolify_env_variables(forBuildTime: true);
|
||||||
|
foreach ($coolify_envs as $key => $item) {
|
||||||
|
$envs_dict[$key] = escapeBashEnvValue($item);
|
||||||
|
}
|
||||||
|
|
||||||
// Add COOLIFY variables
|
// 3. Add SERVICE_NAME, SERVICE_FQDN, SERVICE_URL variables for Docker Compose builds
|
||||||
$coolify_envs->each(function ($item, $key) use ($envs) {
|
|
||||||
$envs->push($key.'='.escapeBashEnvValue($item));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add SERVICE_NAME variables for Docker Compose builds
|
|
||||||
if ($this->build_pack === 'dockercompose') {
|
if ($this->build_pack === 'dockercompose') {
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
// Generate SERVICE_NAME for dockercompose services from processed compose
|
// Generate SERVICE_NAME for dockercompose services from processed compose
|
||||||
|
|
@ -1420,7 +1449,7 @@ private function generate_buildtime_environment_variables()
|
||||||
}
|
}
|
||||||
$services = data_get($dockerCompose, 'services', []);
|
$services = data_get($dockerCompose, 'services', []);
|
||||||
foreach ($services as $serviceName => $_) {
|
foreach ($services as $serviceName => $_) {
|
||||||
$envs->push('SERVICE_NAME_'.str($serviceName)->upper().'='.escapeBashEnvValue($serviceName));
|
$envs_dict['SERVICE_NAME_'.str($serviceName)->upper()] = escapeBashEnvValue($serviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate SERVICE_FQDN & SERVICE_URL for non-PR deployments
|
// Generate SERVICE_FQDN & SERVICE_URL for non-PR deployments
|
||||||
|
|
@ -1433,8 +1462,8 @@ private function generate_buildtime_environment_variables()
|
||||||
$coolifyScheme = $coolifyUrl->getScheme();
|
$coolifyScheme = $coolifyUrl->getScheme();
|
||||||
$coolifyFqdn = $coolifyUrl->getHost();
|
$coolifyFqdn = $coolifyUrl->getHost();
|
||||||
$coolifyUrl = $coolifyUrl->withScheme($coolifyScheme)->withHost($coolifyFqdn)->withPort(null);
|
$coolifyUrl = $coolifyUrl->withScheme($coolifyScheme)->withHost($coolifyFqdn)->withPort(null);
|
||||||
$envs->push('SERVICE_URL_'.str($forServiceName)->upper().'='.escapeBashEnvValue($coolifyUrl->__toString()));
|
$envs_dict['SERVICE_URL_'.str($forServiceName)->upper()] = escapeBashEnvValue($coolifyUrl->__toString());
|
||||||
$envs->push('SERVICE_FQDN_'.str($forServiceName)->upper().'='.escapeBashEnvValue($coolifyFqdn));
|
$envs_dict['SERVICE_FQDN_'.str($forServiceName)->upper()] = escapeBashEnvValue($coolifyFqdn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1442,7 +1471,7 @@ private function generate_buildtime_environment_variables()
|
||||||
$rawDockerCompose = Yaml::parse($this->application->docker_compose_raw);
|
$rawDockerCompose = Yaml::parse($this->application->docker_compose_raw);
|
||||||
$rawServices = data_get($rawDockerCompose, 'services', []);
|
$rawServices = data_get($rawDockerCompose, 'services', []);
|
||||||
foreach ($rawServices as $rawServiceName => $_) {
|
foreach ($rawServices as $rawServiceName => $_) {
|
||||||
$envs->push('SERVICE_NAME_'.str($rawServiceName)->upper().'='.escapeBashEnvValue(addPreviewDeploymentSuffix($rawServiceName, $this->pull_request_id)));
|
$envs_dict['SERVICE_NAME_'.str($rawServiceName)->upper()] = escapeBashEnvValue(addPreviewDeploymentSuffix($rawServiceName, $this->pull_request_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate SERVICE_FQDN & SERVICE_URL for preview deployments with PR-specific domains
|
// Generate SERVICE_FQDN & SERVICE_URL for preview deployments with PR-specific domains
|
||||||
|
|
@ -1455,17 +1484,16 @@ private function generate_buildtime_environment_variables()
|
||||||
$coolifyScheme = $coolifyUrl->getScheme();
|
$coolifyScheme = $coolifyUrl->getScheme();
|
||||||
$coolifyFqdn = $coolifyUrl->getHost();
|
$coolifyFqdn = $coolifyUrl->getHost();
|
||||||
$coolifyUrl = $coolifyUrl->withScheme($coolifyScheme)->withHost($coolifyFqdn)->withPort(null);
|
$coolifyUrl = $coolifyUrl->withScheme($coolifyScheme)->withHost($coolifyFqdn)->withPort(null);
|
||||||
$envs->push('SERVICE_URL_'.str($forServiceName)->upper().'='.escapeBashEnvValue($coolifyUrl->__toString()));
|
$envs_dict['SERVICE_URL_'.str($forServiceName)->upper()] = escapeBashEnvValue($coolifyUrl->__toString());
|
||||||
$envs->push('SERVICE_FQDN_'.str($forServiceName)->upper().'='.escapeBashEnvValue($coolifyFqdn));
|
$envs_dict['SERVICE_FQDN_'.str($forServiceName)->upper()] = escapeBashEnvValue($coolifyFqdn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add build-time user variables only
|
// 4. Add user-defined build-time variables LAST (highest priority - can override everything)
|
||||||
if ($this->pull_request_id === 0) {
|
if ($this->pull_request_id === 0) {
|
||||||
$sorted_environment_variables = $this->application->environment_variables()
|
$sorted_environment_variables = $this->application->environment_variables()
|
||||||
->where('key', 'not like', 'NIXPACKS_%')
|
|
||||||
->where('is_buildtime', true) // ONLY build-time variables
|
->where('is_buildtime', true) // ONLY build-time variables
|
||||||
->orderBy($this->application->settings->is_env_sorting_enabled ? 'key' : 'id')
|
->orderBy($this->application->settings->is_env_sorting_enabled ? 'key' : 'id')
|
||||||
->get();
|
->get();
|
||||||
|
|
@ -1483,7 +1511,12 @@ private function generate_buildtime_environment_variables()
|
||||||
// Strip outer quotes from real_value and apply proper bash escaping
|
// Strip outer quotes from real_value and apply proper bash escaping
|
||||||
$value = trim($env->real_value, "'");
|
$value = trim($env->real_value, "'");
|
||||||
$escapedValue = escapeBashEnvValue($value);
|
$escapedValue = escapeBashEnvValue($value);
|
||||||
$envs->push($env->key.'='.$escapedValue);
|
|
||||||
|
if (isDev() && isset($envs_dict[$env->key])) {
|
||||||
|
$this->application_deployment_queue->addLogEntry("[DEBUG] User override: {$env->key} (was: {$envs_dict[$env->key]}, now: {$escapedValue})");
|
||||||
|
}
|
||||||
|
|
||||||
|
$envs_dict[$env->key] = $escapedValue;
|
||||||
|
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->application_deployment_queue->addLogEntry("[DEBUG] Build-time env: {$env->key}");
|
$this->application_deployment_queue->addLogEntry("[DEBUG] Build-time env: {$env->key}");
|
||||||
|
|
@ -1495,7 +1528,12 @@ private function generate_buildtime_environment_variables()
|
||||||
} else {
|
} else {
|
||||||
// For normal vars, use double quotes to allow $VAR expansion
|
// For normal vars, use double quotes to allow $VAR expansion
|
||||||
$escapedValue = escapeBashDoubleQuoted($env->real_value);
|
$escapedValue = escapeBashDoubleQuoted($env->real_value);
|
||||||
$envs->push($env->key.'='.$escapedValue);
|
|
||||||
|
if (isDev() && isset($envs_dict[$env->key])) {
|
||||||
|
$this->application_deployment_queue->addLogEntry("[DEBUG] User override: {$env->key} (was: {$envs_dict[$env->key]}, now: {$escapedValue})");
|
||||||
|
}
|
||||||
|
|
||||||
|
$envs_dict[$env->key] = $escapedValue;
|
||||||
|
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->application_deployment_queue->addLogEntry("[DEBUG] Build-time env: {$env->key}");
|
$this->application_deployment_queue->addLogEntry("[DEBUG] Build-time env: {$env->key}");
|
||||||
|
|
@ -1507,7 +1545,6 @@ private function generate_buildtime_environment_variables()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$sorted_environment_variables = $this->application->environment_variables_preview()
|
$sorted_environment_variables = $this->application->environment_variables_preview()
|
||||||
->where('key', 'not like', 'NIXPACKS_%')
|
|
||||||
->where('is_buildtime', true) // ONLY build-time variables
|
->where('is_buildtime', true) // ONLY build-time variables
|
||||||
->orderBy($this->application->settings->is_env_sorting_enabled ? 'key' : 'id')
|
->orderBy($this->application->settings->is_env_sorting_enabled ? 'key' : 'id')
|
||||||
->get();
|
->get();
|
||||||
|
|
@ -1525,7 +1562,12 @@ private function generate_buildtime_environment_variables()
|
||||||
// Strip outer quotes from real_value and apply proper bash escaping
|
// Strip outer quotes from real_value and apply proper bash escaping
|
||||||
$value = trim($env->real_value, "'");
|
$value = trim($env->real_value, "'");
|
||||||
$escapedValue = escapeBashEnvValue($value);
|
$escapedValue = escapeBashEnvValue($value);
|
||||||
$envs->push($env->key.'='.$escapedValue);
|
|
||||||
|
if (isDev() && isset($envs_dict[$env->key])) {
|
||||||
|
$this->application_deployment_queue->addLogEntry("[DEBUG] User override: {$env->key} (was: {$envs_dict[$env->key]}, now: {$escapedValue})");
|
||||||
|
}
|
||||||
|
|
||||||
|
$envs_dict[$env->key] = $escapedValue;
|
||||||
|
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->application_deployment_queue->addLogEntry("[DEBUG] Build-time env: {$env->key}");
|
$this->application_deployment_queue->addLogEntry("[DEBUG] Build-time env: {$env->key}");
|
||||||
|
|
@ -1537,7 +1579,12 @@ private function generate_buildtime_environment_variables()
|
||||||
} else {
|
} else {
|
||||||
// For normal vars, use double quotes to allow $VAR expansion
|
// For normal vars, use double quotes to allow $VAR expansion
|
||||||
$escapedValue = escapeBashDoubleQuoted($env->real_value);
|
$escapedValue = escapeBashDoubleQuoted($env->real_value);
|
||||||
$envs->push($env->key.'='.$escapedValue);
|
|
||||||
|
if (isDev() && isset($envs_dict[$env->key])) {
|
||||||
|
$this->application_deployment_queue->addLogEntry("[DEBUG] User override: {$env->key} (was: {$envs_dict[$env->key]}, now: {$escapedValue})");
|
||||||
|
}
|
||||||
|
|
||||||
|
$envs_dict[$env->key] = $escapedValue;
|
||||||
|
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->application_deployment_queue->addLogEntry("[DEBUG] Build-time env: {$env->key}");
|
$this->application_deployment_queue->addLogEntry("[DEBUG] Build-time env: {$env->key}");
|
||||||
|
|
@ -1549,6 +1596,12 @@ private function generate_buildtime_environment_variables()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert dictionary back to collection in KEY=VALUE format
|
||||||
|
$envs = collect([]);
|
||||||
|
foreach ($envs_dict as $key => $value) {
|
||||||
|
$envs->push($key.'='.$value);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the generated environment variables
|
// Return the generated environment variables
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
$this->application_deployment_queue->addLogEntry('[DEBUG] ========================================');
|
$this->application_deployment_queue->addLogEntry('[DEBUG] ========================================');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue