From a1a65682279079d2867f703fbc49301e7d3e97eb Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 4 Mar 2026 20:26:58 +0100 Subject: [PATCH] chore: script --- .github/workflows/ci.yml | 10 ++ .github/workflows/pages.yml | 10 ++ prank.py | 197 ++++++++++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100755 prank.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 406de4e..33118bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,10 @@ on: branches: ["main"] pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: test: permissions: @@ -25,6 +29,12 @@ jobs: steps: - uses: actions/checkout@v4 - uses: bazel-contrib/setup-bazel@0.15.0 + with: + bazelisk-cache: true + repository-cache: true + external-cache: true + disk-cache: ci-${{ matrix.phase8_target }} + cache-save: ${{ github.event_name != 'pull_request' }} - name: Run tests (${{ matrix.phase8_target }}) run: | echo "Phase 8 target: ${{ matrix.phase8_target }}" diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 27e4bd6..eeaa683 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -3,6 +3,11 @@ name: Docs Pages on: push: branches: ["main"] + paths: + - "docs/**" + - "bun/**/*.bzl" + - "internal/**/*.bzl" + - ".github/workflows/pages.yml" workflow_dispatch: permissions: @@ -26,6 +31,11 @@ jobs: - uses: actions/checkout@v4 - uses: bazel-contrib/setup-bazel@0.15.0 + with: + bazelisk-cache: true + repository-cache: true + external-cache: true + disk-cache: docs-pages - name: Generate rule docs run: | diff --git a/prank.py b/prank.py new file mode 100755 index 0000000..adbec3c --- /dev/null +++ b/prank.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 +""" +git-claim-authorship.py + +Rewrites git history so that any commit where you appear as a co-author +instead lists you as the sole author (removing the Co-authored-by line). + +Usage: + python git-claim-authorship.py --name "Your Name" --email "you@example.com" + +Run from inside the repository you want to rewrite. +WARNING: This rewrites history. Force-push required afterwards. +""" + +import subprocess +import re +import argparse +import sys + + +def run(cmd, capture=True, check=True): + result = subprocess.run( + cmd, shell=True, capture_output=capture, text=True, check=check + ) + return result.stdout.strip() if capture else None + + +def get_all_commits(): + output = run("git log --format='%H' --all") + return output.splitlines() if output else [] + + +def get_commit_info(sha): + msg = run(f"git log -1 --format=%B {sha}") + author_name = run(f"git log -1 --format=%an {sha}") + author_email = run(f"git log -1 --format=%ae {sha}") + author_date = run(f"git log -1 --format=%aI {sha}") + committer_name = run(f"git log -1 --format=%cn {sha}") + committer_email = run(f"git log -1 --format=%ce {sha}") + committer_date = run(f"git log -1 --format=%cI {sha}") + return { + "sha": sha, + "message": msg, + "author_name": author_name, + "author_email": author_email, + "author_date": author_date, + "committer_name": committer_name, + "committer_email": committer_email, + "committer_date": committer_date, + } + + +def find_coauthor_line(message, name, email): + """Return True if a Co-authored-by line matches the given name or email.""" + pattern = re.compile( + r"^Co-authored-by:.*?" + re.escape(name) + r".*$|" + r"^Co-authored-by:.*?" + re.escape(email) + r".*$", + re.IGNORECASE | re.MULTILINE, + ) + return bool(pattern.search(message)) + + +def remove_coauthor_line(message, name, email): + """Strip matching Co-authored-by lines from the commit message.""" + pattern = re.compile( + r"^Co-authored-by:.*?" + re.escape(name) + r".*\n?|" + r"^Co-authored-by:.*?" + re.escape(email) + r".*\n?", + re.IGNORECASE | re.MULTILINE, + ) + cleaned = pattern.sub("", message) + cleaned = re.sub(r"\n{3,}", "\n\n", cleaned).rstrip() + "\n" + return cleaned + + +def main(): + parser = argparse.ArgumentParser( + description="Claim authorship of co-authored commits." + ) + parser.add_argument("--name", required=True, help="Your full name (as in git)") + parser.add_argument("--email", required=True, help="Your email (as in git)") + parser.add_argument( + "--dry-run", + action="store_true", + help="Show what would change without modifying anything", + ) + args = parser.parse_args() + + # Make sure we're in a git repo + try: + run("git rev-parse --is-inside-work-tree") + except subprocess.CalledProcessError: + print("Error: not inside a git repository.", file=sys.stderr) + sys.exit(1) + + print(f"Scanning commits for co-authorship by: {args.name} <{args.email}>") + commits = get_all_commits() + print(f"Total commits found: {len(commits)}") + + matches = [] + for sha in commits: + info = get_commit_info(sha) + if find_coauthor_line(info["message"], args.name, args.email): + matches.append(info) + + if not matches: + print("No commits found with your Co-authored-by line. Nothing to do.") + return + + print(f"\nFound {len(matches)} commit(s) to rewrite:\n") + for info in matches: + first_line = info["message"].split("\n")[0] + print(f" {info['sha'][:10]} {first_line}") + + if args.dry_run: + print("\n[Dry run] No changes made.") + return + + confirm = input( + "\n⚠️ This will rewrite history. Proceed? (yes/no): " + ).strip().lower() + if confirm != "yes": + print("Aborted.") + return + + # Build a filter-branch env filter script + sha_set = {info["sha"] for info in matches} + + case_entries = [] + for info in matches: + case_entries.append( + f" {info['sha']})\n" + f" export GIT_AUTHOR_NAME='{args.name}'\n" + f" export GIT_AUTHOR_EMAIL='{args.email}'\n" + f" ;;" + ) + + case_block = "\n".join(case_entries) + + env_filter = f""" +case $GIT_COMMIT in +{case_block} +esac +""" + + msg_case_entries = [] + for info in matches: + new_msg = remove_coauthor_line(info["message"], args.name, args.email) + escaped_msg = new_msg.replace("'", "'\\''").replace("`", "\\`").replace("$", "\\$") + msg_case_entries.append( + f" {info['sha']})\n" + f" printf '%s' '{escaped_msg}'\n" + f" ;;" + ) + + msg_case_block = "\n".join(msg_case_entries) + + msg_filter = f""" +case $GIT_COMMIT in +{msg_case_block} + *) + cat + ;; +esac +""" + + with open("/tmp/_msg_filter.sh", "w") as f: + f.write(msg_filter) + + print("\nRewriting history with git filter-branch...") + try: + result = subprocess.run( + [ + "git", "filter-branch", "-f", + "--env-filter", env_filter, + "--msg-filter", "bash /tmp/_msg_filter.sh", + "--tag-name-filter", "cat", + "--", "--all" + ], + capture_output=False, + text=True, + ) + if result.returncode != 0: + print("filter-branch failed.", file=sys.stderr) + sys.exit(1) + except Exception as e: + print(f"Error: {e}", file=sys.stderr) + sys.exit(1) + + print("\n✅ Done! History rewritten.") + print("\nTo publish the changes, force-push all branches:") + print(" git push --force --all") + print(" git push --force --tags") + print("\nNote: Anyone else with a clone of this repo will need to re-clone or rebase.") + + +if __name__ == "__main__": + main() \ No newline at end of file