fix: fixed bootstrap overwrtting .env file and improved bool handling for js use

This commit is contained in:
2026-01-05 09:35:04 +01:00
parent 28c6bdeaa2
commit f023b24aa7
2 changed files with 18 additions and 15 deletions

View File

@@ -311,7 +311,7 @@ class SettingsBootstrap:
def _write_env(self) -> None: def _write_env(self) -> None:
""" """
Write .env file using .env.example as template. Write .env file using .env.example as template.
This preserves the structure, comments, and formatting of .env.example This preserves the structure, comments, and formatting of .env.example
while updating only the values of variables defined in the schema. while updating only the values of variables defined in the schema.
Custom variables from existing .env are appended at the end. Custom variables from existing .env are appended at the end.
@@ -335,43 +335,44 @@ class SettingsBootstrap:
output_lines = [] output_lines = []
for line in template_lines: for line in template_lines:
stripped = line.strip() stripped = line.strip()
# Keep comments and empty lines as-is # Keep comments and empty lines as-is
if not stripped or stripped.startswith("#"): if not stripped or stripped.startswith("#"):
output_lines.append(line) output_lines.append(line)
continue continue
# Check if line contains a variable assignment # Check if line contains a variable assignment
if "=" in line: if "=" in line:
key, _ = line.split("=", 1) key, _ = line.split("=", 1)
key = key.strip() key = key.strip()
processed_keys.add(key) processed_keys.add(key)
# Check if this variable is in our schema # Check if this variable is in our schema
definition = self.schema.get(key) definition = self.schema.get(key)
if definition: if definition:
# Update with resolved value (including computed settings) # Update with resolved value (including computed settings)
value = self.resolved_settings.get(key, "") value = self.resolved_settings.get(key, "")
# Convert Python booleans to lowercase for .env compatibility # Convert Python booleans to lowercase for .env compatibility
if isinstance(value, bool): if isinstance(value, bool):
value = "true" if value else "false" value = "true" if value else "false"
output_lines.append(f"{key}={value}\n") output_lines.append(f"{key}={value}\n")
# Variable not in schema
# If it exists in current .env, use that value, otherwise keep template
elif key in self.existing_env:
output_lines.append(f"{key}={self.existing_env[key]}\n")
else: else:
# Variable not in schema output_lines.append(line)
# If it exists in current .env, use that value, otherwise keep template
if key in self.existing_env:
output_lines.append(f"{key}={self.existing_env[key]}\n")
else:
output_lines.append(line)
else: else:
# Keep any other lines as-is # Keep any other lines as-is
output_lines.append(line) output_lines.append(line)
# Append custom variables from existing .env that aren't in .env.example # Append custom variables from existing .env that aren't in .env.example
custom_vars = {k: v for k, v in self.existing_env.items() if k not in processed_keys} custom_vars = {
k: v for k, v in self.existing_env.items() if k not in processed_keys
}
if custom_vars: if custom_vars:
output_lines.append("\n# --- CUSTOM VARIABLES ---\n") output_lines.append("\n# --- CUSTOM VARIABLES ---\n")
output_lines.append("# Variables added manually (not in .env.example)\n") output_lines.append("# Variables added manually (not in .env.example)\n")

View File

@@ -150,7 +150,9 @@ class TestTemplatePreservation:
class TestSecretPreservation: class TestSecretPreservation:
"""Test that secrets are never overwritten.""" """Test that secrets are never overwritten."""
def test_preserves_existing_secrets(self, test_toml_with_all_types, test_env_example): def test_preserves_existing_secrets(
self, test_toml_with_all_types, test_env_example
):
"""Test that existing secrets are preserved across multiple bootstraps.""" """Test that existing secrets are preserved across multiple bootstraps."""
from alfred.settings_schema import load_schema from alfred.settings_schema import load_schema