From 4a8e52276ae6503ecca243ebfe6ea02377272c08 Mon Sep 17 00:00:00 2001 From: sickn33 Date: Sat, 21 Mar 2026 10:31:07 +0100 Subject: [PATCH] feat(repo): Add GitHub About sync command Expose an explicit sync:github-about workflow that updates the remote GitHub About description, homepage, and topics from the repository metadata source of truth. Add regression coverage for the generated gh commands and document the new maintainer path in the changelog and walkthrough. --- CHANGELOG.md | 1 + package.json | 1 + tools/scripts/sync_repo_metadata.py | 83 ++++++++++++++++++- .../scripts/tests/test_sync_repo_metadata.py | 31 +++++++ walkthrough.md | 1 + 5 files changed, 116 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9efd016..704f56d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Realigned README, package metadata, user docs, and GitHub About guidance to the current `1,304+` catalog state and `v8.4.0` release copy. - Automated metadata propagation for curated docs and package copy so `npm run chain` now keeps README, package description, and the main count-sensitive user/maintainer docs aligned when the skill catalog changes. +- Added an explicit `sync:github-about` automation path so GitHub About description, homepage, and topics can be refreshed from the same metadata source instead of being updated manually. ## [8.4.0] - 2026-03-20 - "Discovery, Metadata, and Release Hardening" diff --git a/package.json b/package.json index 484d629f..213881d9 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "index": "node tools/scripts/run-python.js tools/scripts/generate_index.py", "readme": "node tools/scripts/run-python.js tools/scripts/update_readme.py", "sync:metadata": "node tools/scripts/run-python.js tools/scripts/sync_repo_metadata.py", + "sync:github-about": "node tools/scripts/run-python.js tools/scripts/sync_repo_metadata.py --apply-github-about", "chain": "npm run validate && npm run index && npm run sync:metadata", "sync:all": "npm run chain", "catalog": "node tools/scripts/build-catalog.js", diff --git a/tools/scripts/sync_repo_metadata.py b/tools/scripts/sync_repo_metadata.py index ac479bf8..e34a4bb8 100644 --- a/tools/scripts/sync_repo_metadata.py +++ b/tools/scripts/sync_repo_metadata.py @@ -3,6 +3,7 @@ import argparse import json import os import re +import subprocess import sys from pathlib import Path @@ -10,6 +11,29 @@ from update_readme import configure_utf8_output, find_repo_root, load_metadata, ABOUT_DESCRIPTION_RE = re.compile(r'"description"\s*:\s*"([^"]*)"') +GITHUB_HOMEPAGE_URL = "https://sickn33.github.io/antigravity-awesome-skills/" +RECOMMENDED_TOPICS = [ + "agentic-skills", + "agent-skills", + "ai-agents", + "ai-agent-skills", + "awesome-list", + "awesome-lists", + "antigravity", + "antigravity-skills", + "autonomous-coding", + "claude-code", + "claude-code-skills", + "codex-cli", + "codex-skills", + "cursor-skills", + "developer-tools", + "gemini-cli", + "gemini-skills", + "mcp", + "ai-workflows", + "skill-library", +] README_TAGLINE_RE = re.compile( r"^> \*\*Installable GitHub library of \d[\d,]*\+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and other AI coding assistants\.\*\*$", re.MULTILINE, @@ -44,6 +68,55 @@ def build_about_description(metadata: dict) -> str: ) +def build_about_topics() -> list[str]: + return list(RECOMMENDED_TOPICS) + + +def run_cli_command(args: list[str], dry_run: bool = False) -> None: + if dry_run: + print(f"[dry-run] {' '.join(args)}") + return + + subprocess.run(args, check=True) + + +def sync_github_about( + metadata: dict, + dry_run: bool, + runner=run_cli_command, +) -> None: + description = build_about_description(metadata) + repo = metadata["repo"] + + runner( + [ + "gh", + "repo", + "edit", + repo, + "--description", + description, + "--homepage", + GITHUB_HOMEPAGE_URL, + ], + dry_run=dry_run, + ) + + topic_command = [ + "gh", + "api", + f"repos/{repo}/topics", + "--method", + "PUT", + ] + for topic in build_about_topics(): + topic_command.extend(["-f", f"names[]={topic}"]) + runner(topic_command, dry_run=dry_run) + + if not dry_run: + print(f"✅ Synced GitHub About settings for {repo}") + + def replace_if_present(content: str, pattern: re.Pattern[str], replacement: str) -> tuple[str, bool]: updated_content, count = pattern.subn(replacement, content, count=1) return updated_content, count > 0 @@ -271,7 +344,8 @@ def print_manual_github_about(metadata: dict) -> None: description = build_about_description(metadata) print("\nManual GitHub repo settings update:") print(f"- About description: {description}") - print("- Suggested topics: claude-code, cursor, gemini-cli, codex-cli, github-copilot, antigravity") + print(f"- Homepage: {GITHUB_HOMEPAGE_URL}") + print(f"- Suggested topics: {', '.join(build_about_topics())}") def parse_args() -> argparse.Namespace: @@ -284,6 +358,11 @@ def parse_args() -> argparse.Namespace: action="store_true", help="Refresh live star count and updated_at when syncing README metadata.", ) + parser.add_argument( + "--apply-github-about", + action="store_true", + help="Apply the GitHub About description, homepage, and topics to the remote repository via gh CLI.", + ) return parser.parse_args() @@ -300,6 +379,8 @@ def main() -> int: ) package_updated = update_package_description(base_dir, metadata, args.dry_run) docs_updated = sync_curated_docs(base_dir, metadata, args.dry_run) + if args.apply_github_about: + sync_github_about(metadata, dry_run=args.dry_run) print_manual_github_about(readme_metadata) if args.dry_run and not package_updated: diff --git a/tools/scripts/tests/test_sync_repo_metadata.py b/tools/scripts/tests/test_sync_repo_metadata.py index c8943215..f9ad61f7 100644 --- a/tools/scripts/tests/test_sync_repo_metadata.py +++ b/tools/scripts/tests/test_sync_repo_metadata.py @@ -120,6 +120,37 @@ If you want a faster answer than "browse all 1,273+ skills", start with a tool-s self.assertIn("1,304+ agentic skills", description) self.assertIn("installer CLI", description) + def test_sync_github_about_builds_expected_commands(self): + calls = [] + + def fake_runner(args, dry_run=False): + calls.append((args, dry_run)) + + sync_repo_metadata.sync_github_about( + { + "repo": "sickn33/antigravity-awesome-skills", + "total_skills_label": "1,304+", + }, + dry_run=True, + runner=fake_runner, + ) + + self.assertEqual(len(calls), 2) + repo_edit_args, repo_edit_dry_run = calls[0] + topics_args, topics_dry_run = calls[1] + + self.assertTrue(repo_edit_dry_run) + self.assertTrue(topics_dry_run) + self.assertEqual(repo_edit_args[:4], ["gh", "repo", "edit", "sickn33/antigravity-awesome-skills"]) + self.assertIn("--description", repo_edit_args) + self.assertIn("--homepage", repo_edit_args) + self.assertIn("https://sickn33.github.io/antigravity-awesome-skills/", repo_edit_args) + + self.assertEqual(topics_args[:4], ["gh", "api", "repos/sickn33/antigravity-awesome-skills/topics", "--method"]) + self.assertIn("PUT", topics_args) + self.assertIn("names[]=claude-code", topics_args) + self.assertIn("names[]=skill-library", topics_args) + if __name__ == "__main__": unittest.main() diff --git a/walkthrough.md b/walkthrough.md index 3de5ec38..eb59d6c1 100644 --- a/walkthrough.md +++ b/walkthrough.md @@ -126,3 +126,4 @@ - `docs/maintainers/skills-update-guide.md` - Updated the changelog `Unreleased` section so the post-`v8.4.0` main branch state documents both the imported skill families and the docs/About realignment. - Automated the recurring docs metadata maintenance by extending `tools/scripts/sync_repo_metadata.py`, wiring it into `npm run chain`, and adding a regression test so future skill-count/version updates propagate through the curated docs surface without manual patching. +- Added a remote GitHub About sync path (`npm run sync:github-about`) backed by `gh repo edit` + `gh api .../topics` so the public repository metadata can be refreshed from the same source of truth on demand.