Skip to content

Commit 92dcf9f

Browse files
iamaeroplaneclaude
andcommitted
fix(extensions): address multiple reviewer comments
- ExtensionRegistry.update() now preserves original installed_at timestamp - Add ExtensionRegistry.restore() for rollback (entry was removed) - Clean up wrongly installed extension on ID mismatch before rollback - Remove unused catalog_error parameter from _print_extension_info() Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent d6c7398 commit 92dcf9f

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

src/specify_cli/__init__.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2472,7 +2472,7 @@ def extension_info(
24722472

24732473
# Case 1: Found in catalog - show full catalog info
24742474
if ext_info:
2475-
_print_extension_info(ext_info, manager, catalog_error)
2475+
_print_extension_info(ext_info, manager)
24762476
return
24772477

24782478
# Case 2: Installed locally but catalog lookup failed or not in catalog
@@ -2522,7 +2522,7 @@ def extension_info(
25222522
raise typer.Exit(1)
25232523

25242524

2525-
def _print_extension_info(ext_info: dict, manager, catalog_error: Optional[Exception] = None):
2525+
def _print_extension_info(ext_info: dict, manager):
25262526
"""Print formatted extension info from catalog data."""
25272527
# Header
25282528
verified_badge = " [green]✓ Verified[/green]" if ext_info.get("verified") else ""
@@ -2783,6 +2783,11 @@ def extension_update(
27832783

27842784
# 7. Verify extension ID matches
27852785
if installed_manifest.id != extension_id:
2786+
# Remove the wrongly installed extension before raising
2787+
try:
2788+
manager.remove(installed_manifest.id)
2789+
except Exception:
2790+
pass # Best effort cleanup
27862791
raise ValueError(
27872792
f"Extension ID mismatch: expected '{extension_id}', got '{installed_manifest.id}'"
27882793
)
@@ -2840,9 +2845,9 @@ def extension_update(
28402845
config["hooks"][hook_name].extend(hooks)
28412846
hook_executor.save_project_config(config)
28422847

2843-
# Restore registry entry
2848+
# Restore registry entry (use restore() since entry was removed)
28442849
if backup_registry_entry:
2845-
manager.registry.update(extension_id, backup_registry_entry)
2850+
manager.registry.restore(extension_id, backup_registry_entry)
28462851

28472852
console.print(f" [green]✓[/green] Rollback successful")
28482853
except Exception as rollback_error:

src/specify_cli/extensions.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,25 @@ def update(self, extension_id: str, metadata: dict):
244244
"""
245245
if extension_id not in self.data["extensions"]:
246246
raise KeyError(f"Extension '{extension_id}' is not installed")
247+
# Preserve the original installed_at timestamp
248+
existing = self.data["extensions"][extension_id]
249+
original_installed_at = existing.get("installed_at")
250+
self.data["extensions"][extension_id] = metadata
251+
if original_installed_at and "installed_at" not in metadata:
252+
self.data["extensions"][extension_id]["installed_at"] = original_installed_at
253+
self._save()
254+
255+
def restore(self, extension_id: str, metadata: dict):
256+
"""Restore extension metadata to registry without modifying timestamps.
257+
258+
Use this method for rollback scenarios where you have a complete backup
259+
of the registry entry (including installed_at) and want to restore it
260+
exactly as it was.
261+
262+
Args:
263+
extension_id: Extension ID
264+
metadata: Complete extension metadata including installed_at
265+
"""
247266
self.data["extensions"][extension_id] = metadata
248267
self._save()
249268

0 commit comments

Comments
 (0)