scripts/backport.py (42 lines of code) (raw):

#!/usr/bin/env python3 """ Automatically backport a PR to a release branch ./scripts/backport.py PR_ID 2.x.x The `gh` CLI must be set up and already authenticated. """ import argparse import json import subprocess import sys parser = argparse.ArgumentParser(description="Backport a PR") parser.add_argument("pr", type=int, help="the # of the PR to backport") parser.add_argument("version", help="the release version to target with the backport") parser.add_argument("--remote", default="origin", help="the git remote to use (defaults to origin)") args = parser.parse_args() title = json.loads( subprocess.check_output(["gh", "pr", "view", str(args.pr), "--json", "title"], text=True) )["title"] commits = json.loads( subprocess.check_output( ["gh", "api", f"repos/{{owner}}/{{repo}}/pulls/{args.pr}/commits"], text=True ) ) print(f'Backporting {len(commits)} commits from "{title}"') branch = f"backport-{args.pr}" base = f"release/{args.version}" remote = args.remote subprocess.check_call(["git", "fetch", remote]) subprocess.check_call(["git", "checkout", "-b", branch, f"{remote}/{base}"]) subprocess.check_call(["git", "cherry-pick", "-x"] + [commit["sha"] for commit in commits]) if input("OK to push and create PR? [y/N]").lower() != "y": sys.exit() subprocess.check_call(["git", "push", "-u", remote, branch]) body = f"""\ ## Status Ready for review ## Description of Changes Backport of #{args.pr}. ## Testing * [ ] CI is passing * [ ] base is `{base}` * [ ] Only contains changes from #{args.pr}. """ print(body) subprocess.check_call( [ "gh", "pr", "create", "--base", base, "--body", body, "--title", f'[{args.version}] Backport "{title}"', ] )