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.
This commit is contained in:
@@ -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"
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user