Coverage for src / rhiza / commands / migrate.py: 100%
89 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 07:04 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 07:04 +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 dataclasses
9import shutil
10from pathlib import Path
12from loguru import logger
14from rhiza.models import RhizaTemplate
17def _create_rhiza_directory(target: Path) -> Path:
18 """Create .rhiza directory if it doesn't exist.
20 Args:
21 target: Target repository path.
23 Returns:
24 Path to .rhiza directory.
25 """
26 rhiza_dir = target / ".rhiza"
27 if not rhiza_dir.exists():
28 logger.info(f"Creating .rhiza directory at: {rhiza_dir.relative_to(target)}")
29 rhiza_dir.mkdir(exist_ok=True)
30 logger.success(f"✓ Created {rhiza_dir.relative_to(target)}")
31 else:
32 logger.debug(f".rhiza directory already exists at: {rhiza_dir.relative_to(target)}")
33 return rhiza_dir
36def _migrate_template_file(target: Path, rhiza_dir: Path) -> tuple[bool, list[str]]:
37 """Migrate template.yml from .github to .rhiza.
39 Args:
40 target: Target repository path.
41 rhiza_dir: Path to .rhiza directory.
43 Returns:
44 Tuple of (migration_performed, migrations_list).
45 """
46 github_dir = target / ".github"
47 new_template_file = rhiza_dir / "template.yml"
49 possible_template_locations = [
50 github_dir / "rhiza" / "template.yml",
51 github_dir / "template.yml",
52 ]
54 migrations_performed = []
55 template_migrated = False
57 for old_template_file in possible_template_locations:
58 if old_template_file.exists():
59 if new_template_file.exists():
60 logger.info(".rhiza/template.yml already exists")
61 logger.info(f"Skipping migration of {old_template_file.relative_to(target)}")
62 logger.info(f"Note: Old file at {old_template_file.relative_to(target)} still exists")
63 else:
64 logger.info(f"Found template.yml at: {old_template_file.relative_to(target)}")
65 logger.info(f"Moving to new location: {new_template_file.relative_to(target)}")
66 shutil.move(str(old_template_file), str(new_template_file))
67 logger.success("✓ Moved template.yml to .rhiza/template.yml")
68 migrations_performed.append("Moved template.yml to .rhiza/template.yml")
69 template_migrated = True
70 break
72 if not template_migrated:
73 if new_template_file.exists():
74 logger.info(".rhiza/template.yml already exists (no migration needed)")
75 else:
76 logger.warning("No existing template.yml file found in .github")
77 logger.info("You may need to run 'rhiza init' to create a template configuration")
79 return template_migrated or new_template_file.exists(), migrations_performed
82def _ensure_rhiza_in_include(template_file: Path) -> None:
83 """Ensure .rhiza folder is in template.yml include list.
85 Args:
86 template_file: Path to template.yml file.
87 """
88 if not template_file.exists():
89 logger.debug("No template.yml present in .rhiza; skipping include update")
90 return
92 template = RhizaTemplate.from_yaml(template_file)
93 template_include = template.include or []
94 if ".rhiza" not in template_include:
95 logger.warning("The .rhiza folder is not included in your template.yml")
96 template_include.append(".rhiza")
97 logger.info("The .rhiza folder is added to your template.yml to ensure it's included in your repository")
98 template = dataclasses.replace(template, include=template_include)
99 template.to_yaml(template_file)
102def _migrate_history_file(target: Path, rhiza_dir: Path) -> list[str]:
103 """Migrate .rhiza.history to .rhiza/history.
105 Args:
106 target: Target repository path.
107 rhiza_dir: Path to .rhiza directory.
109 Returns:
110 List of migrations performed.
111 """
112 old_history_file = target / ".rhiza.history"
113 new_history_file = rhiza_dir / "history"
114 migrations_performed = []
116 if old_history_file.exists():
117 if new_history_file.exists():
118 logger.info(".rhiza/history already exists")
119 logger.info(f"Skipping migration of {old_history_file.relative_to(target)}")
120 logger.info(f"Note: Old file at {old_history_file.relative_to(target)} still exists")
121 else:
122 logger.info("Found existing .rhiza.history file")
123 logger.info(f"Moving to new location: {new_history_file.relative_to(target)}")
124 shutil.move(str(old_history_file), str(new_history_file))
125 logger.success("✓ Moved history file to .rhiza/history")
126 migrations_performed.append("Moved history tracking to .rhiza/history")
127 else:
128 if new_history_file.exists():
129 logger.debug(".rhiza/history already exists (no migration needed)")
130 else:
131 logger.debug("No existing .rhiza.history file to migrate")
133 return migrations_performed
136def _print_migration_summary(migrations_performed: list[str]) -> None:
137 """Print migration summary.
139 Args:
140 migrations_performed: List of migrations performed.
141 """
142 logger.success("✓ Migration completed successfully")
144 if migrations_performed:
145 logger.info("\nMigration Summary:")
146 logger.info(" - Created .rhiza/ folder")
147 for migration in migrations_performed:
148 logger.info(f" - {migration}")
149 else:
150 logger.info("\nNo files needed migration (already using .rhiza structure)")
152 logger.info(
153 "\nNext steps:\n"
154 " 1. Review changes:\n"
155 " git status\n"
156 " git diff\n\n"
157 " 2. Update other commands to use new .rhiza/ location\n"
158 " (Future rhiza versions will automatically use .rhiza/)\n\n"
159 " 3. Commit the migration:\n"
160 " git add .\n"
161 ' git commit -m "chore: migrate to .rhiza folder structure"\n'
162 )
165def migrate(target: Path) -> None:
166 """Migrate project to use the new .rhiza folder structure.
168 This command performs the following actions:
169 1. Creates the `.rhiza/` directory in the project root
170 2. Moves template.yml from `.github/rhiza/` or `.github/` to `.rhiza/template.yml`
171 3. Moves `.rhiza.history` to `.rhiza/history` if it exists
172 4. Provides instructions for next steps
174 The `.rhiza/` folder will contain:
175 - `template.yml` - Template configuration (replaces `.github/rhiza/template.yml`)
176 - `history` - List of files managed by Rhiza templates (replaces `.rhiza.history`)
177 - Future: Additional state, cache, or metadata files
179 Args:
180 target (Path): Path to the target repository.
181 """
182 logger.warning("⚠️ The 'migrate' command is deprecated and will be removed in a future release.")
183 target = target.resolve()
184 logger.info(f"Migrating Rhiza structure in: {target}")
185 logger.info("This will create the .rhiza folder and migrate configuration files")
187 # Create .rhiza directory
188 rhiza_dir = _create_rhiza_directory(target)
190 # Migrate template file
191 template_exists, template_migrations = _migrate_template_file(target, rhiza_dir)
193 # Ensure .rhiza is in include list
194 if template_exists:
195 _ensure_rhiza_in_include(rhiza_dir / "template.yml")
197 # Migrate history file
198 history_migrations = _migrate_history_file(target, rhiza_dir)
200 # Print summary
201 all_migrations = template_migrations + history_migrations
202 _print_migration_summary(all_migrations)