Skip to content

Commit 0b96a2a

Browse files
committed
Version extraction: cache vX.Y.0 for history, use actual latest tag for current
1 parent 1f1e786 commit 0b96a2a

1 file changed

Lines changed: 70 additions & 45 deletions

File tree

scripts/extract-versions.py

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@
55
Extracts API documentation for multiple versions of PathSim packages by checking out
66
historical git tags and running the extraction script.
77
8+
Version strategy:
9+
- Historical versions: Only vX.Y.0 tags (first patch of each minor version)
10+
- Latest version: Always the actual most recent tag (e.g., v0.16.4)
11+
812
Smart extraction mode (default):
9-
- Only extracts versions that are missing from cache
10-
- Always re-extracts the latest version
13+
- Only extracts missing vX.Y.0 versions from cache
14+
- Always re-extracts the latest version (actual latest tag)
1115
- Respects minimum supported version per package
1216
1317
Usage:
1418
python scripts/extract-versions.py # Smart extract (missing + latest)
15-
python scripts/extract-versions.py --all # Force extract all versions
19+
python scripts/extract-versions.py --all # Force extract all vX.Y.0 versions + latest
1620
python scripts/extract-versions.py --package pathsim # Single package
1721
python scripts/extract-versions.py --dry-run # Preview without extraction
1822
"""
@@ -110,19 +114,27 @@ def get_cached_versions(package_id: str) -> set[str]:
110114
return cached
111115

112116

113-
def group_by_minor_version(tags: list[str]) -> dict[str, str]:
114-
"""Group tags by minor version, keeping the latest patch for each."""
115-
versions: dict[str, tuple[str, tuple[int, int, int]]] = {}
117+
def get_minor_zero_tags(tags: list[str]) -> dict[str, str]:
118+
"""Get vX.Y.0 tags for each minor version (for historical caching)."""
119+
versions: dict[str, str] = {}
116120

117121
for tag in tags:
118-
minor = get_minor_version(tag)
119-
version_tuple = parse_version(tag)
122+
major, minor, patch = parse_version(tag)
123+
if patch == 0: # Only vX.Y.0 tags
124+
minor_str = f"{major}.{minor}"
125+
versions[minor_str] = tag
126+
127+
return versions
128+
120129

121-
if minor not in versions or version_tuple > versions[minor][1]:
122-
versions[minor] = (tag, version_tuple)
130+
def get_latest_tag(tags: list[str]) -> tuple[str, str] | None:
131+
"""Get the actual latest tag (highest version number)."""
132+
if not tags:
133+
return None
123134

124-
# Return dict of minor_version -> tag
125-
return {minor: tag for minor, (tag, _) in versions.items()}
135+
latest_tag = max(tags, key=parse_version)
136+
minor = get_minor_version(latest_tag)
137+
return (minor, latest_tag)
126138

127139

128140
def git_checkout(repo_path: Path, ref: str) -> bool:
@@ -183,8 +195,12 @@ def extract_package_versions(
183195
) -> list[dict[str, str]]:
184196
"""Extract versions for a single package.
185197
186-
Smart mode (default): Only extracts missing versions + always re-extracts latest.
187-
All mode: Extracts all versions from minimum supported version.
198+
Version strategy:
199+
- Historical versions: Only vX.Y.0 tags (first patch of each minor)
200+
- Latest version: Always the actual most recent tag (e.g., v0.16.4)
201+
202+
Smart mode (default): Only extracts missing historical versions + always re-extracts latest.
203+
All mode: Extracts all vX.Y.0 versions from minimum supported version + latest.
188204
"""
189205
repo_path = PACKAGE_REPOS.get(package_id)
190206
if not repo_path or not repo_path.exists():
@@ -207,58 +223,63 @@ def extract_package_versions(
207223

208224
print(f" Found {len(all_tags)} tags")
209225

210-
# Group by minor version
211-
minor_versions = group_by_minor_version(all_tags)
226+
# Get vX.Y.0 tags for historical versions
227+
minor_zero_versions = get_minor_zero_tags(all_tags)
212228

213229
# Filter to supported versions only
214-
supported_versions = {
215-
v: tag for v, tag in minor_versions.items()
230+
supported_historical = {
231+
v: tag for v, tag in minor_zero_versions.items()
216232
if version_gte(v, min_version)
217233
}
218234

219-
if not supported_versions:
220-
print(f" No versions >= {min_version} found")
235+
# Get the actual latest tag (could be vX.Y.Z where Z > 0)
236+
latest_info = get_latest_tag(all_tags)
237+
if not latest_info:
238+
print(f" No valid tags found")
221239
return []
222240

223-
print(f" {len(supported_versions)} supported versions: {sorted(supported_versions.keys(), key=parse_minor_version, reverse=True)}")
224-
225-
# Sort by version (newest first)
226-
sorted_versions = sorted(
227-
supported_versions.items(),
228-
key=lambda x: parse_minor_version(x[0]),
229-
reverse=True,
230-
)
241+
latest_minor, latest_tag = latest_info
242+
print(f" Latest tag: {latest_tag} (minor: {latest_minor})")
243+
print(f" Historical vX.Y.0 versions: {sorted(supported_historical.keys(), key=parse_minor_version, reverse=True)}")
231244

232245
# Determine which versions to extract
233246
cached = get_cached_versions(package_id)
234-
latest_version = sorted_versions[0][0] if sorted_versions else None
247+
248+
# Build extraction list
249+
versions_to_extract = []
235250

236251
if extract_all:
237-
versions_to_extract = sorted_versions
238-
print(f" Mode: Extract ALL ({len(versions_to_extract)} versions)")
252+
# Extract all historical vX.Y.0 versions
253+
for minor_version, tag in sorted(supported_historical.items(), key=lambda x: parse_minor_version(x[0]), reverse=True):
254+
# Skip if this is the latest minor (we'll add the actual latest tag separately)
255+
if minor_version != latest_minor:
256+
versions_to_extract.append((minor_version, tag))
257+
print(f" Mode: Extract ALL historical ({len(versions_to_extract)} versions) + latest")
239258
else:
240-
# Smart mode: only missing + latest
241-
versions_to_extract = []
242-
for minor_version, tag in sorted_versions:
243-
is_latest = minor_version == latest_version
244-
is_cached = minor_version in cached
245-
246-
if is_latest or not is_cached:
259+
# Smart mode: only missing historical + latest
260+
for minor_version, tag in sorted(supported_historical.items(), key=lambda x: parse_minor_version(x[0]), reverse=True):
261+
# Skip if this is the latest minor (we'll add the actual latest tag separately)
262+
if minor_version == latest_minor:
263+
continue
264+
if minor_version not in cached:
247265
versions_to_extract.append((minor_version, tag))
248266

249-
missing_count = len([v for v, _ in versions_to_extract if v != latest_version and v not in cached])
267+
missing_count = len(versions_to_extract)
250268
print(f" Mode: Smart extraction")
251269
print(f" Cached: {len(cached)} versions")
252-
print(f" Missing: {missing_count} versions")
253-
print(f" Latest ({latest_version}): will {'re-' if latest_version in cached else ''}extract")
254-
print(f" Total to extract: {len(versions_to_extract)} versions")
270+
print(f" Missing historical: {missing_count} versions")
271+
272+
# Always add the latest tag (uses actual latest, not necessarily vX.Y.0)
273+
versions_to_extract.append((latest_minor, latest_tag))
274+
print(f" Latest ({latest_tag}): will {'re-' if latest_minor in cached else ''}extract")
275+
print(f" Total to extract: {len(versions_to_extract)} versions")
255276

256277
extracted = []
257278
output_dir = VERSIONS_DIR / package_id
258279
output_dir.mkdir(parents=True, exist_ok=True)
259280

260281
for minor_version, tag in versions_to_extract:
261-
is_latest = minor_version == latest_version
282+
is_latest = minor_version == latest_minor
262283
is_cached = minor_version in cached
263284
status = "LATEST" if is_latest else ("NEW" if not is_cached else "cached")
264285

@@ -322,8 +343,12 @@ def main():
322343
chem: %(chem)s
323344
vehicle: %(vehicle)s
324345
346+
Version strategy:
347+
- Historical: Only vX.Y.0 tags (first patch of each minor)
348+
- Latest: Actual most recent tag (e.g., v0.16.4)
349+
325350
By default, uses smart extraction:
326-
- Only extracts versions that are missing from cache
351+
- Only extracts missing vX.Y.0 versions from cache
327352
- Always re-extracts the latest version
328353
- Respects minimum supported versions
329354
""" % MIN_SUPPORTED_VERSIONS
@@ -337,7 +362,7 @@ def main():
337362
"--all", "-a",
338363
action="store_true",
339364
dest="extract_all",
340-
help="Force extract all versions (ignore cache)"
365+
help="Force extract all vX.Y.0 versions + latest (ignore cache)"
341366
)
342367
parser.add_argument(
343368
"--dry-run", "-n",

0 commit comments

Comments
 (0)