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:
sickn33
2026-03-21 10:31:07 +01:00
parent 37f46505ff
commit 4a8e52276a
5 changed files with 116 additions and 1 deletions

View File

@@ -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:

View File

@@ -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()