chore(migration): switch org to wickra-lib and maintainer email to wickra.lib@gmail.com (#59)

Introduce repo-metadata.toml as single source of truth for repo identity
(org slug, maintainer email, canonical URLs) and add sync-metadata.yml
workflow with a Python audit script that fails CI if any tracked file
drifts back to pre-migration values.

Bulk-replace across 24 tracked files:
- kingchenc/wickra -> wickra-lib/wickra (URL segment)
- kingchencp@gmail.com -> wickra.lib@gmail.com (maintainer email)
- @kingchenc -> @wickra-lib (CODEOWNERS mention only)

Person-name credits are preserved: LICENSE copyright holder, Cargo.toml
authors handle, and CHANGELOG historical @kingchenc reference all remain
unchanged. Crate / PyPI / npm package names also untouched.

Merge this PR only after the kingchenc/wickra -> wickra-lib/wickra org
transfer has happened on the GitHub side, otherwise all badges and
repository links 404 until the transfer is performed.
This commit is contained in:
kingchenc
2026-05-30 12:18:10 +02:00
committed by GitHub
parent 0f2ff9c3c7
commit 62ab84c472
27 changed files with 290 additions and 101 deletions
+1 -1
View File
@@ -3,4 +3,4 @@
# The owner listed here is requested for review automatically on every pull
# request. See https://docs.github.com/articles/about-code-owners.
* @kingchenc
* @wickra-lib
+2 -2
View File
@@ -1,8 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Security vulnerability
url: https://github.com/kingchenc/wickra/security/advisories/new
url: https://github.com/wickra-lib/wickra/security/advisories/new
about: Report security issues privately — do not open a public issue.
- name: Question or discussion
url: https://github.com/kingchenc/wickra/discussions
url: https://github.com/wickra-lib/wickra/discussions
about: Ask usage questions and discuss ideas here.
+2 -2
View File
@@ -24,9 +24,9 @@
- [ ] New behaviour has tests; bug fixes have a regression test.
- [ ] Public API changes are mirrored in the Python / Node / WASM bindings
and their type stubs (If applicable).
- [ ] The relevant page on the [project Wiki](https://github.com/kingchenc/wickra/wiki)
- [ ] The relevant page on the [project Wiki](https://github.com/wickra-lib/wickra/wiki)
and the `README.md` are updated (If applicable). Wiki edits go to a
separate repository: `https://github.com/kingchenc/wickra.wiki.git`.
separate repository: `https://github.com/wickra-lib/wickra.wiki.git`.
- [ ] An entry was added under `## [Unreleased]` in `CHANGELOG.md`.
## Notes for reviewers
+113
View File
@@ -0,0 +1,113 @@
"""Audit that no file in the repo contains the pre-migration org slug or
maintainer email. Driven by `repo-metadata.toml` at the repo root.
This is the read-only side of the metadata pipeline. It does not patch any
files — it just fails CI when drift sneaks in. Pair with a future
`--write` mode (auto-fix + signed commit on main) once the migration has
settled.
"""
from __future__ import annotations
import argparse
import os
import subprocess
import sys
import tomllib
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
METADATA_PATH = REPO_ROOT / "repo-metadata.toml"
def load_metadata() -> dict:
with METADATA_PATH.open("rb") as f:
return tomllib.load(f)
def is_allowlisted(rel_path: str, allowlist: list[str]) -> bool:
norm = rel_path.replace(os.sep, "/")
for entry in allowlist:
entry_norm = entry.replace(os.sep, "/")
if entry_norm.endswith("/"):
if norm.startswith(entry_norm):
return True
else:
if norm == entry_norm:
return True
return False
def tracked_files() -> list[str]:
"""List git-tracked files relative to the repo root."""
out = subprocess.run(
["git", "ls-files"],
cwd=REPO_ROOT,
check=True,
capture_output=True,
text=True,
)
return [line for line in out.stdout.splitlines() if line]
def scan(forbidden: list[str], allowlist: list[str]) -> list[tuple[str, int, str, str]]:
"""Return a list of (rel_path, line_no, needle, line_text) findings.
Only git-tracked files are scanned, so local-only ghost-ignored files
(`.claude/`, drafts) never trigger false positives.
"""
findings: list[tuple[str, int, str, str]] = []
for rel_path in tracked_files():
if is_allowlisted(rel_path, allowlist):
continue
abs_path = REPO_ROOT / rel_path
if not abs_path.is_file():
continue
try:
lines = abs_path.read_text(encoding="utf-8", errors="replace").splitlines()
except (OSError, UnicodeDecodeError):
continue
for lineno, line in enumerate(lines, start=1):
for needle in forbidden:
if needle in line:
findings.append((rel_path, lineno, needle, line.strip()))
return findings
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--check", action="store_true", help="audit-only (default)")
args = parser.parse_args()
_ = args # currently only --check is supported
meta = load_metadata()
audit = meta.get("audit", {})
forbidden: list[str] = list(audit.get("forbidden", []))
allowlist: list[str] = list(audit.get("allowlist", []))
if not forbidden:
print("repo-metadata.toml [audit].forbidden is empty — nothing to scan.")
return 0
findings = scan(forbidden, allowlist)
if findings:
print(f"sync-metadata: {len(findings)} forbidden-substring hits:", file=sys.stderr)
for rel_path, lineno, needle, text in findings:
print(f" {rel_path}:{lineno}: matched {needle!r}", file=sys.stderr)
print(f" {text}", file=sys.stderr)
print(
"\nUpdate the offending lines to use the values from repo-metadata.toml,",
"or add the path to [audit].allowlist if the reference is intentional",
"(e.g. historical CHANGELOG entries).",
file=sys.stderr,
)
return 1
org = meta["repo"]["org"]
email = meta["maintainer"]["email"]
print(f"sync-metadata: clean. org={org!r} email={email!r}")
return 0
if __name__ == "__main__":
sys.exit(main())
+4 -4
View File
@@ -384,10 +384,10 @@ jobs:
node -e "
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json'));
pkg.author = 'kingchenc <kingchencp@gmail.com>';
pkg.repository = { type: 'git', url: 'https://github.com/kingchenc/wickra' };
pkg.homepage = 'https://github.com/kingchenc/wickra';
pkg.bugs = { url: 'https://github.com/kingchenc/wickra/issues' };
pkg.author = 'kingchenc <wickra.lib@gmail.com>';
pkg.repository = { type: 'git', url: 'https://github.com/wickra-lib/wickra' };
pkg.homepage = 'https://github.com/wickra-lib/wickra';
pkg.bugs = { url: 'https://github.com/wickra-lib/wickra/issues' };
pkg.license = 'PolyForm-Noncommercial-1.0.0';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
"
+22
View File
@@ -0,0 +1,22 @@
name: sync-metadata
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
audit:
name: metadata audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Audit repo-metadata.toml drift
run: python .github/scripts/sync-metadata.py --check