Coverage for src / rhiza / models / lock.py: 100%

28 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-02 07:04 +0000

1"""Lock model for Rhiza configuration.""" 

2 

3from dataclasses import dataclass, field 

4from typing import Any 

5 

6from rhiza.models._base import YamlSerializable 

7from rhiza.models._git_utils import _normalize_to_list 

8from rhiza.models.template import GitHost 

9 

10 

11@dataclass(frozen=True, kw_only=True) 

12class TemplateLock(YamlSerializable): 

13 """Represents the structure of .rhiza/template.lock. 

14 

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 """ 

27 

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 files: list[str] = field(default_factory=list) 

36 synced_at: str = "" 

37 strategy: str = "" 

38 

39 @classmethod 

40 def from_config(cls, config: dict[str, Any]) -> "TemplateLock": 

41 """Create a TemplateLock instance from a configuration dictionary. 

42 

43 Args: 

44 config: Dictionary containing lock configuration. 

45 

46 Returns: 

47 A new TemplateLock instance. 

48 """ 

49 return cls( 

50 sha=config.get("sha", ""), 

51 repo=config.get("repo", ""), 

52 host=config.get("host", GitHost.GITHUB), 

53 ref=config.get("ref", "main"), 

54 include=_normalize_to_list(config.get("include")), 

55 exclude=_normalize_to_list(config.get("exclude")), 

56 templates=_normalize_to_list(config.get("templates")), 

57 files=_normalize_to_list(config.get("files")), 

58 synced_at=config.get("synced_at", ""), 

59 strategy=config.get("strategy", ""), 

60 ) 

61 

62 @property 

63 def config(self) -> dict[str, Any]: 

64 """Return the lock's current state as a configuration dictionary.""" 

65 config: dict[str, Any] = { 

66 "sha": self.sha, 

67 "repo": self.repo, 

68 "host": str(self.host), 

69 "ref": self.ref, 

70 "include": self.include, 

71 "exclude": self.exclude, 

72 "templates": self.templates, 

73 "files": self.files, 

74 } 

75 if self.synced_at: 

76 config["synced_at"] = self.synced_at 

77 if self.strategy: 

78 config["strategy"] = self.strategy 

79 return config