diff --git a/tools/scripts/sync_repo_metadata.py b/tools/scripts/sync_repo_metadata.py index f2631432..773d1d3c 100644 --- a/tools/scripts/sync_repo_metadata.py +++ b/tools/scripts/sync_repo_metadata.py @@ -52,18 +52,25 @@ def parse_args() -> argparse.Namespace: description="Synchronize repository metadata across README and package.json." ) parser.add_argument("--dry-run", action="store_true", help="Preview updates without writing files.") + parser.add_argument( + "--refresh-volatile", + action="store_true", + help="Refresh live star count and updated_at when syncing README metadata.", + ) return parser.parse_args() def main() -> int: args = parse_args() base_dir = find_repo_root(os.path.dirname(__file__)) - metadata = load_metadata(base_dir) + metadata = load_metadata(base_dir, refresh_volatile=args.refresh_volatile) print("Repository metadata") print(json.dumps(metadata, indent=2)) - readme_metadata = update_readme(dry_run=args.dry_run) + readme_metadata = update_readme( + dry_run=args.dry_run, refresh_volatile=args.refresh_volatile + ) package_updated = update_package_description(base_dir, metadata, args.dry_run) print_manual_github_about(readme_metadata) diff --git a/tools/scripts/update_readme.py b/tools/scripts/update_readme.py index 0dbf3c20..3d65b1d5 100644 --- a/tools/scripts/update_readme.py +++ b/tools/scripts/update_readme.py @@ -11,6 +11,10 @@ from datetime import datetime, timezone GITHUB_REPO = "sickn33/antigravity-awesome-skills" SYNC_COMMENT_RE = re.compile(r"") +SYNC_COMMENT_FIELDS_RE = re.compile( + r"" +) def configure_utf8_output() -> None: @@ -91,7 +95,22 @@ def fetch_star_count(repo: str) -> int | None: return int(stars) if isinstance(stars, int) else None -def load_metadata(base_dir: str, repo: str = GITHUB_REPO) -> dict: +def parse_existing_sync_metadata(current_readme: str) -> dict[str, str | int] | None: + match = SYNC_COMMENT_FIELDS_RE.search(current_readme) + if not match: + return None + + return { + "version": match.group("version"), + "skills": int(match.group("skills")), + "stars": int(match.group("stars")), + "updated_at": match.group("updated_at"), + } + + +def load_metadata( + base_dir: str, repo: str = GITHUB_REPO, refresh_volatile: bool = False +) -> dict: readme_path = os.path.join(base_dir, "README.md") package_path = os.path.join(base_dir, "package.json") index_path = os.path.join(base_dir, "skills_index.json") @@ -105,6 +124,7 @@ def load_metadata(base_dir: str, repo: str = GITHUB_REPO) -> dict: with open(readme_path, "r", encoding="utf-8") as file: current_readme = file.read() + existing_sync_metadata = parse_existing_sync_metadata(current_readme) current_star_match = re.search(r"⭐%20([\d%2C\+]+)%20Stars", current_readme) current_stars = None if current_star_match: @@ -113,8 +133,29 @@ def load_metadata(base_dir: str, repo: str = GITHUB_REPO) -> dict: if compact.isdigit(): current_stars = int(compact) - live_stars = fetch_star_count(repo) - total_stars = live_stars if live_stars is not None else current_stars or 0 + existing_stars = None + existing_updated_at = None + if existing_sync_metadata: + stars = existing_sync_metadata.get("stars") + updated_at = existing_sync_metadata.get("updated_at") + if isinstance(stars, int): + existing_stars = stars + if isinstance(updated_at, str): + existing_updated_at = updated_at + + live_stars = fetch_star_count(repo) if refresh_volatile else None + total_stars = ( + live_stars + if live_stars is not None + else existing_stars + if existing_stars is not None + else current_stars or 0 + ) + updated_at = ( + datetime.now(timezone.utc).replace(microsecond=0).isoformat() + if refresh_volatile or existing_updated_at is None + else existing_updated_at + ) return { "repo": repo, @@ -125,8 +166,9 @@ def load_metadata(base_dir: str, repo: str = GITHUB_REPO) -> dict: "star_badge_count": format_star_badge_count(total_stars), "star_milestone": format_star_milestone(total_stars), "star_celebration": format_star_celebration(total_stars), - "updated_at": datetime.now(timezone.utc).replace(microsecond=0).isoformat(), + "updated_at": updated_at, "used_live_star_count": live_stars is not None, + "refreshed_volatile": refresh_volatile, } @@ -221,10 +263,10 @@ def apply_metadata(content: str, metadata: dict) -> str: return f"{sync_comment}\n{content.lstrip()}" -def update_readme(dry_run: bool = False) -> dict: +def update_readme(dry_run: bool = False, refresh_volatile: bool = False) -> dict: base_dir = find_repo_root(os.path.dirname(__file__)) readme_path = os.path.join(base_dir, "README.md") - metadata = load_metadata(base_dir) + metadata = load_metadata(base_dir, refresh_volatile=refresh_volatile) print(f"📖 Reading README from: {readme_path}") print(f"🔢 Total skills found: {metadata['total_skills']}") @@ -252,10 +294,15 @@ def update_readme(dry_run: bool = False) -> dict: def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Sync generated metadata into README.md.") parser.add_argument("--dry-run", action="store_true", help="Compute metadata without writing files.") + parser.add_argument( + "--refresh-volatile", + action="store_true", + help="Refresh live star count and updated_at instead of preserving existing values.", + ) return parser.parse_args() if __name__ == "__main__": configure_utf8_output() args = parse_args() - update_readme(dry_run=args.dry_run) + update_readme(dry_run=args.dry_run, refresh_volatile=args.refresh_volatile) diff --git a/walkthrough.md b/walkthrough.md index ce55f1c0..d9ea2987 100644 --- a/walkthrough.md +++ b/walkthrough.md @@ -12,3 +12,13 @@ - `npm run chain` - `npm run catalog` - Final release prep, issue closure comments, and verification were completed on `main`. + +# Maintenance Walkthrough - 2026-03-13 + +- Fixed `tools/scripts/update_readme.py` so normal `npm run readme` runs preserve the existing `registry-sync` star/timestamp values instead of rewriting them on every execution, which was causing non-deterministic PR drift failures in CI. +- Updated `tools/scripts/sync_repo_metadata.py` to expose the same explicit `--refresh-volatile` behavior for live star/timestamp refreshes, keeping release/metadata refresh flows available without destabilizing contributor PR checks. +- Verified the fix with: + - `python3 tools/scripts/update_readme.py --dry-run` + - `python3 tools/scripts/sync_repo_metadata.py --dry-run` + - `npm run readme` + - `npm run validate:references`