Coverage for src / rhiza / models / lock.py: 100%
31 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-06-15 18:22 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-06-15 18:22 +0000
1"""Lock model for Rhiza configuration."""
3from dataclasses import dataclass, field
4from typing import Any
6from rhiza.models._base import YamlSerializable
7from rhiza.models._git_utils import _normalize_to_list
8from rhiza.models.template import GitHost
11@dataclass(frozen=True, kw_only=True)
12class TemplateLock(YamlSerializable):
13 """Represents the structure of .rhiza/template.lock.
15 Attributes:
16 sha: The commit SHA of the last-synced template.
17 repo: The template repository (e.g., "jebel-quant/rhiza").
18 host: The git hosting platform (e.g., "github", "gitlab").
19 ref: The branch or ref that was synced (e.g., "main").
20 include: List of paths included from the template.
21 exclude: List of paths excluded from the template.
22 templates: List of template bundle names.
23 files: List of file paths that were synced.
24 synced_at: ISO 8601 UTC timestamp of when the sync was performed.
25 strategy: The sync strategy used (e.g., "merge", "diff", "materialize").
26 """
28 sha: str
29 repo: str = ""
30 host: GitHost | str = GitHost.GITHUB
31 ref: str = "main"
32 include: list[str] = field(default_factory=list)
33 exclude: list[str] = field(default_factory=list)
34 templates: list[str] = field(default_factory=list)
35 profiles: list[str] = field(default_factory=list)
36 files: list[str] = field(default_factory=list)
37 synced_at: str = ""
38 strategy: str = ""
40 @classmethod
41 def from_config(cls, config: dict[str, Any]) -> "TemplateLock":
42 """Create a TemplateLock instance from a configuration dictionary.
44 Args:
45 config: Dictionary containing lock configuration.
47 Returns:
48 A new TemplateLock instance.
49 """
50 return cls(
51 sha=config.get("sha", ""),
52 repo=config.get("repo", ""),
53 host=config.get("host", GitHost.GITHUB),
54 ref=config.get("ref", "main"),
55 include=_normalize_to_list(config.get("include")),
56 exclude=_normalize_to_list(config.get("exclude")),
57 templates=_normalize_to_list(config.get("templates")),
58 profiles=_normalize_to_list(config.get("profiles")),
59 files=_normalize_to_list(config.get("files")),
60 synced_at=config.get("synced_at", ""),
61 strategy=config.get("strategy", ""),
62 )
64 @property
65 def config(self) -> dict[str, Any]:
66 """Return the lock's current state as a configuration dictionary."""
67 config: dict[str, Any] = {
68 "sha": self.sha,
69 "repo": self.repo,
70 "host": str(self.host),
71 "ref": self.ref,
72 "include": self.include,
73 "exclude": self.exclude,
74 "templates": self.templates,
75 "files": self.files,
76 }
77 if self.profiles:
78 config["profiles"] = self.profiles
79 if self.synced_at:
80 config["synced_at"] = self.synced_at
81 if self.strategy:
82 config["strategy"] = self.strategy
83 return config