-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathupgrade_specs.py
More file actions
170 lines (127 loc) · 5.11 KB
/
upgrade_specs.py
File metadata and controls
170 lines (127 loc) · 5.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/env python3
"""
Spec Version Upgrader
Automatically upgrades spec files to the latest template version.
"""
import re
from pathlib import Path
from typing import Dict, List, Tuple
def get_spec_version(spec_content: str) -> str:
"""Extract spec version from content"""
match = re.search(r"\*\*Spec Version:\*\*\s+(\d+\.\d+\.\d+)", spec_content)
if match:
return match.group(1)
# Check comment version (older format)
match = re.search(r"Spec Template Version:\s+(\d+\.\d+\.\d+)", spec_content)
if match:
return match.group(1)
return "0.0.0" # Unknown/very old
def upgrade_to_1_0_0(spec_content: str, spec_id: str) -> str:
"""Upgrade spec to version 1.0.0 format"""
# Check if already has version
if "**Spec Version:**" in spec_content:
return spec_content
# Extract title
title_match = re.search(r"^#\s+(.+)$", spec_content, re.MULTILINE)
if not title_match:
raise ValueError(f"Could not find title in spec: {spec_id}")
title_line = title_match.group(0)
# Insert version info after title
version_block = """
<!--
Spec Template Version: 1.0.0
Created: 2025-01-24
Last Updated: 2025-01-24
-->
**Spec Version:** 1.0.0
"""
# Replace title with title + version block
upgraded = spec_content.replace(title_line, title_line + "\n" + version_block, 1)
return upgraded
def upgrade_spec_file(spec_path: Path, target_version: str = "1.0.0") -> Tuple[bool, str]:
"""
Upgrade a single spec file to target version
Returns:
(success: bool, message: str)
"""
try:
content = spec_path.read_text()
current_version = get_spec_version(content)
if current_version == target_version:
return True, f"Already at version {target_version}"
# Apply upgrades based on version
if current_version < "1.0.0" and target_version >= "1.0.0":
content = upgrade_to_1_0_0(content, spec_path.stem)
# Future upgrades would go here:
# if current_version < "1.1.0" and target_version >= "1.1.0":
# content = upgrade_to_1_1_0(content, spec_path.stem)
# Write back
spec_path.write_text(content)
return True, f"Upgraded from {current_version} to {target_version}"
except Exception as e:
return False, f"Error: {str(e)}"
def find_all_specs() -> List[Path]:
"""Find all spec files (excluding template)"""
specs_dir = Path("specs")
return [f for f in specs_dir.glob("*.md") if f.name != ".template.md"]
def upgrade_all_specs(target_version: str = "1.0.0", dry_run: bool = False) -> Dict[str, Tuple[bool, str]]:
"""
Upgrade all spec files to target version
Args:
target_version: Target template version
dry_run: If True, don't write changes
Returns:
Dict mapping spec_id to (success, message)
"""
results = {}
specs = find_all_specs()
for spec_path in specs:
spec_id = spec_path.stem
if dry_run:
content = spec_path.read_text()
current_version = get_spec_version(content)
results[spec_id] = (True, f"Would upgrade from {current_version} to {target_version}")
else:
success, message = upgrade_spec_file(spec_path, target_version)
results[spec_id] = (success, message)
return results
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Upgrade spec files to latest template version")
parser.add_argument("--version", default="1.0.0", help="Target version (default: 1.0.0)")
parser.add_argument("--dry-run", action="store_true", help="Show what would be changed without modifying files")
parser.add_argument("--spec", help="Upgrade specific spec file (e.g., scatter-basic-001)")
args = parser.parse_args()
print("🔄 Spec Version Upgrader")
print(f"Target version: {args.version}")
print(f"Dry run: {args.dry_run}")
print("=" * 60)
if args.spec:
# Upgrade single spec
spec_path = Path(f"specs/{args.spec}.md")
if not spec_path.exists():
print(f"❌ Spec not found: {spec_path}")
exit(1)
if args.dry_run:
content = spec_path.read_text()
current = get_spec_version(content)
print(f"📄 {args.spec}")
print(f" Current: {current}")
print(f" Would upgrade to: {args.version}")
else:
success, message = upgrade_spec_file(spec_path, args.version)
status = "✅" if success else "❌"
print(f"{status} {args.spec}: {message}")
else:
# Upgrade all specs
results = upgrade_all_specs(args.version, args.dry_run)
total = len(results)
succeeded = sum(1 for success, _ in results.values() if success)
failed = total - succeeded
for spec_id, (success, message) in results.items():
status = "✅" if success else "❌"
print(f"{status} {spec_id}: {message}")
print("=" * 60)
print(f"Total: {total} | Succeeded: {succeeded} | Failed: {failed}")
if failed > 0:
exit(1)