Coverage for src / rhiza / commands / migrate.py: 100%
87 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"""Command for migrating to the new .rhiza folder structure.
3This module implements the `migrate` command. It helps transition projects to use
4the new `.rhiza/` folder structure for storing Rhiza state and configuration files,
5separate from `.github/` which contains GitHub-specific configurations.
6"""
8import shutil
9from pathlib import Path
11from loguru import logger
13from rhiza.models import RhizaTemplate
16def _create_rhiza_directory(target: Path) -> Path:
17 """Create .rhiza directory if it doesn't exist.
19 Args:
20 target: Target repository path.
22 Returns:
23 Path to .rhiza directory.
24 """
25 rhiza_dir = target / ".rhiza"
26 if not rhiza_dir.exists():
27 logger.info(f"Creating .rhiza directory at: {rhiza_dir.relative_to(target)}")
28 rhiza_dir.mkdir(exist_ok=True)
29 logger.success(f"✓ Created {rhiza_dir.relative_to(target)}")
30 else:
31 logger.debug(f".rhiza directory already exists at: {rhiza_dir.relative_to(target)}")
32 return rhiza_dir
35def _migrate_template_file(target: Path, rhiza_dir: Path) -> tuple[bool, list[str]]:
36 """Migrate template.yml from .github to .rhiza.
38 Args:
39 target: Target repository path.
40 rhiza_dir: Path to .rhiza directory.
42 Returns:
43 Tuple of (migration_performed, migrations_list).
44 """
45 github_dir = target / ".github"
46 new_template_file = rhiza_dir / "template.yml"
48 possible_template_locations = [
49 github_dir / "rhiza" / "template.yml",
50 github_dir / "template.yml",
51 ]
53 migrations_performed = []
54 template_migrated = False
56 for old_template_file in possible_template_locations:
57 if old_template_file.exists():
58 if new_template_file.exists():
59 logger.info(".rhiza/template.yml already exists")
60 logger.info(f"Skipping migration of {old_template_file.relative_to(target)}")
61 logger.info(f"Note: Old file at {old_template_file.relative_to(target)} still exists")
62 else:
63 logger.info(f"Found template.yml at: {old_template_file.relative_to(target)}")
64 logger.info(f"Moving to new location: {new_template_file.relative_to(target)}")
65 shutil.move(str(old_template_file), str(new_template_file))
66 logger.success("✓ Moved template.yml to .rhiza/template.yml")
67 migrations_performed.append("Moved template.yml to .rhiza/template.yml")
68 template_migrated = True
69 break
71 if not template_migrated:
72 if new_template_file.exists():
73 logger.info(".rhiza/template.yml already exists (no migration needed)")
74 else:
75 logger.warning("No existing template.yml file found in .github")
76 logger.info("You may need to run 'rhiza init' to create a template configuration")
78 return template_migrated or new_template_file.exists(), migrations_performed
81def _ensure_rhiza_in_include(template_file: Path) -> None:
82 """Ensure .rhiza folder is in template.yml include list.
84 Args:
85 template_file: Path to template.yml file.
86 """
87 if not template_file.exists():
88 logger.debug("No template.yml present in .rhiza; skipping include update")
89 return
91 template = RhizaTemplate.from_yaml(template_file)
92 template_include = template.include or []
93 if ".rhiza" not in template_include:
94 logger.warning("The .rhiza folder is not included in your template.yml")
95 template_include.append(".rhiza")
96 logger.info("The .rhiza folder is added to your template.yml to ensure it's included in your repository")
97 template.include = template_include
98 template.to_yaml(template_file)
101def _migrate_history_file(target: Path, rhiza_dir: Path) -> list[str]:
102 """Migrate .rhiza.history to .rhiza/history.
104 Args:
105 target: Target repository path.
106 rhiza_dir: Path to .rhiza directory.
108 Returns:
109 List of migrations performed.
110 """
111 old_history_file = target / ".rhiza.history"
112 new_history_file = rhiza_dir / "history"
113 migrations_performed = []
115 if old_history_file.exists():
116 if new_history_file.exists():
117 logger.info(".rhiza/history already exists")
118 logger.info(f"Skipping migration of {old_history_file.relative_to(target)}")
119 logger.info(f"Note: Old file at {old_history_file.relative_to(target)} still exists")
120 else:
121 logger.info("Found existing .rhiza.history file")
122 logger.info(f"Moving to new location: {new_history_file.relative_to(target)}")
123 shutil.move(str(old_history_file), str(new_history_file))
124 logger.success("✓ Moved history file to .rhiza/history")
125 migrations_performed.append("Moved history tracking to .rhiza/history")
126 else:
127 if new_history_file.exists():
128 logger.debug(".rhiza/history already exists (no migration needed)")
129 else:
130 logger.debug("No existing .rhiza.history file to migrate")
132 return migrations_performed
135def _print_migration_summary(migrations_performed: list[str]) -> None:
136 """Print migration summary.
138 Args:
139 migrations_performed: List of migrations performed.
140 """
141 logger.success("✓ Migration completed successfully")
143 if migrations_performed:
144 logger.info("\nMigration Summary:")
145 logger.info(" - Created .rhiza/ folder")
146 for migration in migrations_performed:
147 logger.info(f" - {migration}")
148 else:
149 logger.info("\nNo files needed migration (already using .rhiza structure)")
151 logger.info(
152 "\nNext steps:\n"
153 " 1. Review changes:\n"
154 " git status\n"
155 " git diff\n\n"
156 " 2. Update other commands to use new .rhiza/ location\n"
157 " (Future rhiza versions will automatically use .rhiza/)\n\n"
158 " 3. Commit the migration:\n"
159 " git add .\n"
160 ' git commit -m "chore: migrate to .rhiza folder structure"\n'
161 )
164def migrate(target: Path) -> None:
165 """Migrate project to use the new .rhiza folder structure.
167 This command performs the following actions:
168 1. Creates the `.rhiza/` directory in the project root
169 2. Moves template.yml from `.github/rhiza/` or `.github/` to `.rhiza/template.yml`
170 3. Moves `.rhiza.history` to `.rhiza/history` if it exists
171 4. Provides instructions for next steps
173 The `.rhiza/` folder will contain:
174 - `template.yml` - Template configuration (replaces `.github/rhiza/template.yml`)
175 - `history` - List of files managed by Rhiza templates (replaces `.rhiza.history`)
176 - Future: Additional state, cache, or metadata files
178 Args:
179 target (Path): Path to the target repository.
180 """
181 target = target.resolve()
182 logger.info(f"Migrating Rhiza structure in: {target}")
183 logger.info("This will create the .rhiza folder and migrate configuration files")
185 # Create .rhiza directory
186 rhiza_dir = _create_rhiza_directory(target)
188 # Migrate template file
189 template_exists, template_migrations = _migrate_template_file(target, rhiza_dir)
191 # Ensure .rhiza is in include list
192 if template_exists:
193 _ensure_rhiza_in_include(rhiza_dir / "template.yml")
195 # Migrate history file
196 history_migrations = _migrate_history_file(target, rhiza_dir)
198 # Print summary
199 all_migrations = template_migrations + history_migrations
200 _print_migration_summary(all_migrations)