The above needs to go into your executable path somewhere, then add
ppr = "!f() { pull_pull_request.py $@; }; f"
to the alias section of ~/.gitconfig.
| #!/usr/bin/env python3 | |
| """ | |
| pull from and pushing to other people's pull requests | |
| (might require an auth key for private repos) | |
| """ | |
| import os | |
| import re | |
| import sys | |
| import requests | |
| from requests.auth import HTTPBasicAuth | |
| from subprocess import run, PIPE, CalledProcessError | |
| def pull(origin, remote_branch_name, local_branch_name): | |
| p = run(['git', 'branch'], check=True, stdout=PIPE, universal_newlines=True) | |
| branches = {b.strip(' *') for b in p.stdout.split('\n')} | |
| if local_branch_name in branches: | |
| p = run(['git', 'symbolic-ref', 'refs/remotes/origin/HEAD'], check=True, stdout=PIPE, universal_newlines=True) | |
| default_branch = p.stdout.strip().rsplit('/', 1)[-1] | |
| run(['git', 'checkout', default_branch], check=True) | |
| run(['git', 'branch', '-D', local_branch_name], check=True) | |
| run(['git', 'fetch', origin, '{}:{}'.format(remote_branch_name, local_branch_name)], check=True) | |
| run(['git', 'checkout', local_branch_name], check=True) | |
| def push(origin, remote_branch_name, local_branch_name): | |
| run(['git', 'push', origin, '{}:{}'.format(local_branch_name, remote_branch_name)], check=True) | |
| def main(): | |
| if not 2 <= len(sys.argv) <= 3: | |
| print('usage: git ppr <pull request id> [pull/push]') | |
| return 1 | |
| pr_id = int(sys.argv[1]) | |
| p = run(['git', 'remote', '-v'], check=True, stdout=PIPE, universal_newlines=True) | |
| m = re.search(r'github.com:([\w\-]+/[\w\-]+)', p.stdout) | |
| assert m, 'repo and username not found in "git remote -v":' + repr(p.stdout) | |
| repo = m.group(1) | |
| auth = None | |
| username_token = os.getenv('GITHUB_USERNAME_TOKEN') | |
| if username_token: | |
| auth = HTTPBasicAuth(*username_token.split(':', 1)) | |
| r = requests.get('https://api.github.com/repos/{}/pulls/{}'.format(repo, pr_id), auth=auth) | |
| r.raise_for_status() | |
| data = r.json() | |
| print('Pull Request: \x1b[1;36m{title} #{number}\x1b[0m\n'.format(**data)) | |
| head = data['head'] | |
| remote_branch_name = head['ref'] | |
| local_branch_name = '{}-{}'.format(head['user']['login'], remote_branch_name) | |
| # could use head['repo']['git_url'] here | |
| origin = head['repo']['ssh_url'] | |
| try: | |
| if sys.argv[2].lower() == 'push' if len(sys.argv) == 3 else False: | |
| push(origin, remote_branch_name, local_branch_name) | |
| else: | |
| pull(origin, remote_branch_name, local_branch_name) | |
| except CalledProcessError as e: | |
| print('error executing command: "{}"'.format(' '.join(e.cmd))) | |
| return 1 | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(main()) |