Coverage for src / rhiza / bundle_resolver.py: 100%
26 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-12 20:13 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-12 20:13 +0000
1"""Bundle resolution logic for template configuration.
3This module provides functions to load and resolve bundle configurations
4from the template repository's template-bundles.yml file.
5"""
7from pathlib import Path
9from rhiza.models import RhizaBundles, RhizaTemplate
12def load_bundles_from_clone(tmp_dir: Path) -> RhizaBundles | None:
13 """Load .rhiza/template-bundles.yml from cloned template repo.
15 Args:
16 tmp_dir: Path to the cloned template repository.
18 Returns:
19 RhizaBundles if template-bundles.yml exists, None otherwise.
21 Raises:
22 yaml.YAMLError: If template-bundles.yml is malformed.
23 ValueError: If template-bundles.yml is invalid.
24 """
25 bundles_file = tmp_dir / ".rhiza" / "template-bundles.yml"
26 if not bundles_file.exists():
27 return None
28 return RhizaBundles.from_yaml(bundles_file)
31def resolve_include_paths(
32 template: RhizaTemplate,
33 bundles_config: RhizaBundles | None,
34) -> list[str]:
35 """Resolve template configuration to file paths.
37 Supports:
38 - Template-based mode (templates field)
39 - Path-based mode (include field)
40 - Hybrid mode (both templates and include)
42 Args:
43 template: The template configuration.
44 bundles_config: The loaded bundles configuration, or None if not available.
46 Returns:
47 List of file paths to materialize.
49 Raises:
50 ValueError: If configuration is invalid or bundles.yml is missing.
51 """
52 paths = []
54 # Resolve templates to paths if specified
55 if template.templates:
56 if not bundles_config:
57 msg = "Template uses templates but template-bundles.yml not found in template repository"
58 raise ValueError(msg)
59 paths.extend(bundles_config.resolve_to_paths(template.templates))
61 # Add include paths if specified
62 if template.include:
63 paths.extend(template.include)
65 # At least one must be specified
66 if not paths:
67 msg = "Template configuration must specify either 'templates' or 'include'"
68 raise ValueError(msg)
70 # Deduplicate while preserving order
71 seen = set()
72 deduplicated = []
73 for path in paths:
74 if path not in seen:
75 deduplicated.append(path)
76 seen.add(path)
78 return deduplicated