diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 8778b8d..1f14d59 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -70,6 +70,7 @@ jobs: --add-data "voxvera/src${SEP}voxvera/src" \ --add-data "voxvera/templates${SEP}voxvera/templates" \ --add-data "voxvera/resources/tor${SEP}voxvera/resources/tor" \ + --add-data "support-matrix.json${SEP}." \ --add-data "requirements.txt${SEP}." \ --name "${{ matrix.artifact_name }}" \ voxvera/cli.py diff --git a/pyproject.toml b/pyproject.toml index ac5a773..f9bbda0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ voxvera = ["templates/**", "src/**", "resources/**", "locales/**", "resources/bi [project] name = "voxvera" -version = "0.3.7" +version = "0.3.8" description = "VoxVera CLI utilities" readme = "README.md" authors = [{name = "VoxVera"}] diff --git a/scripts/build_binaries.sh b/scripts/build_binaries.sh index a8013af..95d3760 100755 --- a/scripts/build_binaries.sh +++ b/scripts/build_binaries.sh @@ -45,6 +45,7 @@ $PY_CMD --onefile \ --add-data "voxvera/src:voxvera/src" \ --add-data "voxvera/templates:voxvera/templates" \ --add-data "voxvera/resources/tor:voxvera/resources/tor" \ + --add-data "support-matrix.json:." \ --add-data "requirements.txt:." \ --name "$BINARY_NAME" \ --distpath "$ARTIFACT_DIR" \ diff --git a/tests/test_cli.py b/tests/test_cli.py index 84424f6..63242aa 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -81,6 +81,40 @@ def test_init_template(tmp_path, monkeypatch): assert (dest / "index.html").exists() +def test_init_seeds_missing_default_config(tmp_path, monkeypatch): + _setup_tmp(monkeypatch, tmp_path) + test_data_dir = tmp_path / "data" + config_path = test_data_dir / "fresh-config.json" + answers = iter([ + "Fresh Site", + "freshsite", + "Fresh Title", + "Fresh Subtitle", + "Fresh Headline", + "https://example.com", + "Read more", + "Footer bits", + "", + ]) + + monkeypatch.setattr(cli, "choose_language", lambda *a: "en") + monkeypatch.setattr(cli, "prompt", lambda questions: {question["name"]: next(answers) for question in questions}) + monkeypatch.setattr(cli, "open_editor", lambda initial: "Fresh content") + + class _Confirm: + def execute(self): + return False + + monkeypatch.setattr(cli.inquirer, "confirm", lambda **kwargs: _Confirm()) + + cli.main(["--config", str(config_path), "init"]) + + assert config_path.exists() + saved = cli.load_config(config_path) + assert saved["folder_name"] == "freshsite" + assert saved["content"] == "Fresh content" + + def test_create_from_template_persists_current_language(tmp_path, monkeypatch): _setup_tmp(monkeypatch, tmp_path) cli.load_locale("es") diff --git a/tests/test_integrity.py b/tests/test_integrity.py index 3a573db..808f02d 100644 --- a/tests/test_integrity.py +++ b/tests/test_integrity.py @@ -56,6 +56,14 @@ def test_linux_validation_runbook_and_helper_are_linked(): assert "docs/linux-hosting-validation.md" in readme assert "scripts/linux-recovery-check.sh" in runbook.read_text(encoding="utf-8") + +def test_frozen_builds_bundle_support_matrix(): + build_script = (REPO_ROOT / "scripts" / "build_binaries.sh").read_text(encoding="utf-8") + binaries_workflow = (REPO_ROOT / ".github" / "workflows" / "binaries.yml").read_text(encoding="utf-8") + + assert '--add-data "support-matrix.json:."' in build_script + assert '--add-data "support-matrix.json${SEP}."' in binaries_workflow + def test_locale_completeness(): """Verify that all non-English locales have the same keys as English.""" locales_dir = REPO_ROOT / "voxvera" / "locales" diff --git a/voxvera/__init__.py b/voxvera/__init__.py index 2edeb97..d337cc6 100644 --- a/voxvera/__init__.py +++ b/voxvera/__init__.py @@ -1,7 +1,7 @@ import sys from pathlib import Path -__version__ = "0.3.7" +__version__ = "0.3.8" # Add the vendor directory to sys.path ONLY for PyInstaller (frozen) builds. # For pip/pipx installs the system/venv packages are correct and the vendored diff --git a/voxvera/cli.py b/voxvera/cli.py index e40ee37..8ce0f8a 100644 --- a/voxvera/cli.py +++ b/voxvera/cli.py @@ -341,6 +341,18 @@ def save_config(data: dict, path: str): json.dump(normalize_config(data), fh, indent=2) +def ensure_config_exists(path: str | Path) -> Path: + """Seed a config file from the bundled defaults when missing.""" + config_path = Path(path) + if config_path.exists(): + return config_path + + config_path.parent.mkdir(parents=True, exist_ok=True) + default_config = json.loads((_src_res("config.json")).read_text(encoding="utf-8")) + config_path.write_text(json.dumps(normalize_config(default_config), indent=2), encoding="utf-8") + return config_path + + def _open_editor_terminal(initial: str) -> str: """Fallback to opening the user's $EDITOR in the terminal.""" import tempfile @@ -530,6 +542,7 @@ def resolve_new_site_folder(config_path: str, preserve_session_on_overwrite: boo def interactive_update(config_path: str): + ensure_config_exists(config_path) data = load_config(config_path) console = Console()