Skip to content

Instantly share code, notes, and snippets.

@sxlijin
Created October 1, 2016 22:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sxlijin/b4ad4361fd78712d45dccd7da2d7b9d4 to your computer and use it in GitHub Desktop.
Save sxlijin/b4ad4361fd78712d45dccd7da2d7b9d4 to your computer and use it in GitHub Desktop.
Demo of how to access the protected branches API (currently in preview) with Python.
#!/usr/bin/env python
"""
Demo of how to access the protected branches API, currently in preview.
See https://developer.github.com/changes/2016-06-27-protected-branches-api-update/
Note that you get a 404 if you attempt to get the protection of a branch on a
repo that your token actually works for (it's not well-defined behavior, but
it's what happens).
Note that for this to work on non-unix systems, AUTH_TOKEN must be set.
"""
import argparse, json, requests, subprocess
AUTH_TOKEN=None
def get_auth_token():
"""
Returns AUTH_TOKEN if AUTH_TOKEN is not None; if AUTH_TOKEN is None, gets
OAuth token from git-credential.
"""
if AUTH_TOKEN is not None:
return AUTH_TOKEN
command = ' | '.join(('git credential fill <<< "host=github.com"',
'grep -o "password=\w\+"',
'cut -d= -f2'
))
return subprocess.check_output(command, shell=True).strip().decode('utf-8')
def make_api_url(*args):
"""
Concatenates *args to make a path to access the GitHub API.
"""
return '/'.join(('https://api.github.com', 'repos', *args))
def make_api_headers():
"""
Returns a dict representing the headers needed to access the GH API.
"""
APPLICATION_HEADER_VALUE='application/vnd.github.loki-preview+json'
return {
'Authorization': 'token {:s}'.format(get_auth_token()),
'Accept': APPLICATION_HEADER_VALUE,
}
def get_branches(target_repo):
"""
Returns the <response> corresponding to the response from the GH API
endpoint which lists the branches in a $target_repo.
"""
url = make_api_url(target_repo, 'branches')
return requests.get(url, headers=make_api_headers())
def get_protection(target_repo, branch):
"""
Returns the <response> corresponding to the response from the GH API
endpoint which lists the protection status of $branch in $target_repo.
"""
url = make_api_url(target_repo, 'branches', branch, 'protection')
return requests.get(url, headers=make_api_headers())
def set_protection(target_repo, branch, data=None):
"""
Sets protections on $branch in $target_repo, where $data is the JSON that
sent in a PUT request to the corresponding GH API endpoint.
If $data is not specified, it defaults to no required status checks, and
saying restricting permissions to no users/teams (note that admins can
still push to the branch even when restrictions are so set).
Returns the <response> corresponding to the response from the GH API
endpoint.
"""
url = make_api_url(target_repo, 'branches', branch, 'protection')
if data is None:
data = {
'required_status_checks': None,
'restrictions': {
'users': [],
'teams': [],
},
}
return requests.put(url, headers=make_api_headers(), json=data)
def delete_protection(target_repo, branch):
"""
Returns the <response> corresponding to the response from the GH API
endpoint which deletes the protection status of $branch in $target_repo.
"""
url = make_api_url(target_repo, 'branches', branch, 'protection')
return requests.delete(url, headers=make_api_headers())
def main():
parser = argparse.ArgumentParser(description = __doc__)
parser.add_argument(
'target_repo',
help='the target repository (specify as either org/repo or repo)'
)
parser.add_argument(
'target_branch',
help='the target branch'
)
parser.add_argument(
'action',
choices=['get', 'set', 'delete'],
help='action to perform on branch protections'
)
def do_and_print_json(fxn, *args):
print(
json.dumps(
fxn(*args).json(),
sort_keys=True,
indent=2
)
)
{
'get': lambda *args: do_and_print_json(get_protection, *args),
'set': lambda *args: do_and_print_json(set_protection, *args),
'delete': delete_protection,
}[parser.parse_args().action](
parser.parse_args().target_repo,
parser.parse_args().target_branch
)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment