Created
January 9, 2020 18:15
-
-
Save non/01fdb04a34625bb94dc8fe3035521223 to your computer and use it in GitHub Desktop.
Script to delete all issues for a repo. This is different than just closing all of them. It uses the v4 GraphQL Github API.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# | |
# by Erik Osheim | |
# | |
# STEPS TO USE | |
# | |
# 0. install deps | |
# - pip install requests | |
# | |
# 1. generate personal access token | |
# - log into github | |
# - go to https://github.com/settings/tokens | |
# - the account used must have 'admin' permission to delete issues for the repo | |
# - include at least the 'public_repo' permission for the access token | |
# - save the token string (something like 'd33e2d1d3fb978eafded0c9817e8bce9cca04472') | |
# | |
# 2. update user, tok, owner, and repo variables in this script | |
# - user: the account that generated the token | |
# - tok: the generated token string | |
# - owner: the owner of the repo whose issues are to be deleted | |
# - repo: the name of the repo whose issues are to be deleted | |
# | |
# 3. python massdel.py | |
# | |
# The script will delete the issues 20 at a time. It will display the | |
# remaining API calls available and when the calls refresh. For repos | |
# with many thousands of issues the script may need to be run multiple | |
# times (e.g. delete the first 5K issues, wait until the API calls are | |
# refreshed, delete the next 5K, etc.). The script doesn't do this | |
# backoff itself, and contains no rate limiting of any kind. | |
# | |
# FUTURE WORK | |
# | |
# * delete only issues with a matching label | |
# * delete only issues opened by a particular account | |
# * delete a set of issues given by issue number | |
import datetime | |
import json | |
import requests | |
user = 'github-username' | |
tok = 'abcdef0123456789abcdef0123456789abcdef01' | |
owner = "repo-owner" | |
repo = "repo-name" | |
# get info about how many API requests remain | |
def info(r0): | |
remaining = int(r0.headers['X-RateLimit-Remaining']) | |
limit = int(r0.headers['X-RateLimit-Limit']) | |
return (remaining, limit) | |
# get into about when API requests are refreshed | |
def retryat(r0): | |
t = r0.headers['X-RateLimit-Reset'] | |
d = datetime.datetime.fromtimestamp(int(t)) | |
return (d, t) | |
# make a graphql request to github | |
def req(q): | |
dat = json.dumps({"query": q}) | |
return requests.post('https://api.github.com/graphql', auth=(user, tok), data=dat) | |
# request all the issues for the repo | |
def getissues(): | |
q = """ | |
query { | |
repository(owner:"%s", name:"%s") { | |
issues(last:20, states:[CLOSED,OPEN]) { | |
edges { | |
node { id number } | |
} | |
} | |
} | |
} | |
""" % (owner, repo) | |
return req(q) | |
# delete a particular issues by its internal issue ID (not issue number) | |
def delete(iid): | |
m = """ | |
mutation { | |
deleteIssue(input:{issueId:"%s"}) { | |
clientMutationId | |
} | |
} | |
""" % iid | |
return req(m) | |
# the actual script body | |
def main(): | |
while True: | |
r0 = getissues() | |
if r0.status_code != 200: | |
print('failed to get issues') | |
print(r0.json()) | |
return | |
rem, lim = info(r0) | |
dt, _ = retryat(r0) | |
print('%d of %d API calls remaining until %s' % (rem, lim, dt)) | |
lst = r0.json()['data']['repository']['issues']['edges'] | |
if not lst: | |
print('no issues to delete') | |
return | |
print('got next %d issues' % len(lst)) | |
for item in lst: | |
iid = item['node']['id'] | |
num = item['node']['number'] | |
r1 = delete(iid) | |
if r1.status_code != 200: | |
print('failed to delete #%s (%s)' % (num, iid)) | |
d, t = retryat(r1) | |
print('retry at %s (%s)' % (d, t)) | |
print(r1.json()) | |
return None | |
rem, lim = info(r1) | |
print(' %04d/%04d: deleted issue #%s (%s)' % (rem, lim, num, iid)) | |
if __name__ == "__main__": | |
# run the script! | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment