Coverage for src / rhiza / commands / migrate.py: 100%
71 statements
« prev ^ index » next coverage.py v7.13.1, created at 2025-12-29 01:59 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2025-12-29 01:59 +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/rhiza/` which contains template configuration.
6"""
8import shutil
9from pathlib import Path
11from loguru import logger
13from rhiza.models import RhizaTemplate
16def migrate(target: Path) -> None:
17 """Migrate project to use the new .rhiza folder structure.
19 This command performs the following actions:
20 1. Creates the `.rhiza/` directory in the project root
21 2. Moves template.yml from `.github/rhiza/` or `.github/` to `.rhiza/template.yml`
22 3. Moves `.rhiza.history` to `.rhiza/history` if it exists
23 4. Provides instructions for next steps
25 The `.rhiza/` folder will contain:
26 - `template.yml` - Template configuration (replaces `.github/rhiza/template.yml`)
27 - `history` - List of files managed by Rhiza templates (replaces `.rhiza.history`)
28 - Future: Additional state, cache, or metadata files
30 Args:
31 target (Path): Path to the target repository.
32 """
33 # Resolve to absolute path
34 target = target.resolve()
36 logger.info(f"Migrating Rhiza structure in: {target}")
37 logger.info("This will create the .rhiza folder and migrate configuration files")
39 # Create .rhiza directory
40 rhiza_dir = target / ".rhiza"
41 if not rhiza_dir.exists():
42 logger.info(f"Creating .rhiza directory at: {rhiza_dir.relative_to(target)}")
43 rhiza_dir.mkdir(exist_ok=True)
44 logger.success(f"✓ Created {rhiza_dir.relative_to(target)}")
45 else:
46 logger.debug(f".rhiza directory already exists at: {rhiza_dir.relative_to(target)}")
48 # Track what was migrated for summary
49 migrations_performed = []
51 # Migrate template.yml from .github to .rhiza if it exists
52 github_dir = target / ".github"
53 new_template_file = rhiza_dir / "template.yml"
55 # Check possible locations for template.yml in .github
56 possible_template_locations = [
57 github_dir / "rhiza" / "template.yml",
58 github_dir / "template.yml",
59 ]
61 template_migrated = False
62 for old_template_file in possible_template_locations:
63 if old_template_file.exists():
64 if new_template_file.exists():
65 logger.info(".rhiza/template.yml already exists")
66 logger.info(f"Skipping migration of {old_template_file.relative_to(target)}")
67 logger.info(f"Note: Old file at {old_template_file.relative_to(target)} still exists")
68 else:
69 logger.info(f"Found template.yml at: {old_template_file.relative_to(target)}")
70 logger.info(f"Moving to new location: {new_template_file.relative_to(target)}")
72 # Move the template file to new location (not copy)
73 shutil.move(str(old_template_file), str(new_template_file))
74 logger.success("✓ Moved template.yml to .rhiza/template.yml")
75 migrations_performed.append("Moved template.yml to .rhiza/template.yml")
76 template_migrated = True
77 break
79 if not template_migrated:
80 if new_template_file.exists():
81 logger.info(".rhiza/template.yml already exists (no migration needed)")
82 else:
83 logger.warning("No existing template.yml file found in .github")
84 logger.info("You may need to run 'rhiza init' to create a template configuration")
86 # Ensure the .rhiza folder is included in template.yml include list (if template exists)
87 template_file = new_template_file
88 if template_file.exists():
89 # Load existing template configuration
90 template = RhizaTemplate.from_yaml(template_file)
91 template_include = template.include or []
92 if ".rhiza" not in template_include:
93 logger.warning("The .rhiza folder is not included in your template.yml")
94 template_include.append(".rhiza")
95 logger.info("The .rhiza folder is added to your template.yml to ensure it's included in your repository")
97 # Save the updated template.yml
98 template.include = template_include
99 template.to_yaml(template_file)
100 else:
101 logger.debug("No template.yml present in .rhiza; skipping include update")
103 # Migrate .rhiza.history to .rhiza/history if it exists
104 old_history_file = target / ".rhiza.history"
105 new_history_file = rhiza_dir / "history"
107 if old_history_file.exists():
108 if new_history_file.exists():
109 logger.info(".rhiza/history already exists")
110 logger.info(f"Skipping migration of {old_history_file.relative_to(target)}")
111 logger.info(f"Note: Old file at {old_history_file.relative_to(target)} still exists")
112 else:
113 logger.info("Found existing .rhiza.history file")
114 logger.info(f"Moving to new location: {new_history_file.relative_to(target)}")
116 # Move the history file to new location
117 shutil.move(str(old_history_file), str(new_history_file))
118 logger.success("✓ Moved history file to .rhiza/history")
119 migrations_performed.append("Moved history tracking to .rhiza/history")
120 else:
121 if new_history_file.exists():
122 logger.debug(".rhiza/history already exists (no migration needed)")
123 else:
124 logger.debug("No existing .rhiza.history file to migrate")
126 # Summary
127 logger.success("✓ Migration completed successfully")
129 if migrations_performed:
130 logger.info("\nMigration Summary:")
131 logger.info(" - Created .rhiza/ folder")
132 for migration in migrations_performed:
133 logger.info(f" - {migration}")
134 else:
135 logger.info("\nNo files needed migration (already using .rhiza structure)")
137 logger.info(
138 "\nNext steps:\n"
139 " 1. Review changes:\n"
140 " git status\n"
141 " git diff\n\n"
142 " 2. Update other commands to use new .rhiza/ location\n"
143 " (Future rhiza versions will automatically use .rhiza/)\n\n"
144 " 3. Commit the migration:\n"
145 " git add .\n"
146 ' git commit -m "chore: migrate to .rhiza folder structure"\n'
147 )