1e7e9171eSGeorge Keishing#!/usr/bin/env python3 2a464a7ceSSivas SRR 3a464a7ceSSivas SRRr""" 4a464a7ceSSivas SRRExports issues from a list of repositories to individual CSV files. 5a464a7ceSSivas SRRUses basic authentication (GitHub username + password) to retrieve issues 6a464a7ceSSivas SRRfrom a repository that username has access to. Supports GitHub API v3. 7a464a7ceSSivas SRR""" 8*249fbcc0SSridevi Ramesh 9a464a7ceSSivas SRRimport argparse 10a464a7ceSSivas SRRimport csv 119fe1b12eSSivas SRRimport getpass 1220f38712SPatrick Williams 13a464a7ceSSivas SRRimport requests 14a464a7ceSSivas SRR 15a464a7ceSSivas SRRauth = None 1620f38712SPatrick Williamsstates = "all" 17a464a7ceSSivas SRR 18a464a7ceSSivas SRR 19a464a7ceSSivas SRRdef write_issues(response, csv_out): 20a464a7ceSSivas SRR r""" 21a464a7ceSSivas SRR Parses JSON response and writes to CSV. 22a464a7ceSSivas SRR """ 2365dbeaadSvinaybs6 print(response) 24a464a7ceSSivas SRR if response.status_code != 200: 25a464a7ceSSivas SRR raise Exception(response.status_code) 26a464a7ceSSivas SRR for issue in response.json(): 2720f38712SPatrick Williams if "pull_request" not in issue: 284ebb3281SGeorge Keishing labels = ", ".join([label["name"] for label in issue["labels"]]) 29b4eb9ac1SSivas SRR 309fe1b12eSSivas SRR # Below lines to overcome "TypeError: 'NoneType' object has 319fe1b12eSSivas SRR # no attribute '__getitem__'" 329fe1b12eSSivas SRR 3320f38712SPatrick Williams close_date = issue.get("closed_at") 34b4eb9ac1SSivas SRR if close_date: 3520f38712SPatrick Williams close_date = issue.get("closed_at").split("T")[0] 36b4eb9ac1SSivas SRR 3720f38712SPatrick Williams assignee_resp = issue.get("assignees", "Not Assigned") 389fe1b12eSSivas SRR if assignee_resp: 3920f38712SPatrick Williams owners = ",".join( 4020f38712SPatrick Williams [ 4120f38712SPatrick Williams assignee_login["login"] 4220f38712SPatrick Williams for assignee_login in assignee_resp 4320f38712SPatrick Williams ] 4420f38712SPatrick Williams ) 459fe1b12eSSivas SRR else: 46b4eb9ac1SSivas SRR owners = "Not Assigned" 47b4eb9ac1SSivas SRR 4820f38712SPatrick Williams milestone_resp = issue.get("milestone", "Not Assigned") 49b4eb9ac1SSivas SRR if milestone_resp: 5020f38712SPatrick Williams milestone_resp = milestone_resp["title"].encode("utf-8") 519fe1b12eSSivas SRR 52a464a7ceSSivas SRR # Change the following line to write out additional fields 5320f38712SPatrick Williams csv_out.writerow( 5420f38712SPatrick Williams [ 5520f38712SPatrick Williams labels.encode("utf-8"), 5620f38712SPatrick Williams issue.get("title").encode("utf-8"), 5720f38712SPatrick Williams issue.get("state").encode("utf-8"), 5820f38712SPatrick Williams issue.get("created_at").split("T")[0], 59b4eb9ac1SSivas SRR close_date, 6020f38712SPatrick Williams issue.get("html_url").encode("utf-8"), 6120f38712SPatrick Williams issue.get("user").get("login").encode("utf-8"), 6220f38712SPatrick Williams owners, 6320f38712SPatrick Williams milestone_resp, 6420f38712SPatrick Williams ] 6520f38712SPatrick Williams ) 66a464a7ceSSivas SRR 67a464a7ceSSivas SRR 680419fb0aSSivas SRRdef get_issues_from_github_to_csv(name, response): 69a464a7ceSSivas SRR r""" 70a464a7ceSSivas SRR Requests issues from GitHub API and writes to CSV file. 710419fb0aSSivas SRR Description of argument(s): 720419fb0aSSivas SRR name Name of the GitHub repository 730419fb0aSSivas SRR response GitHub repository response 74a464a7ceSSivas SRR """ 7565dbeaadSvinaybs6 print(name) 7665dbeaadSvinaybs6 print(states) 77a464a7ceSSivas SRR 78a464a7ceSSivas SRR # Multiple requests are required if response is paged 7920f38712SPatrick Williams if "link" in response.headers: 8020f38712SPatrick Williams pages = { 8120f38712SPatrick Williams rel[6:-1]: url[url.index("<") + 1 : -1] 8220f38712SPatrick Williams for url, rel in ( 8320f38712SPatrick Williams link.split(";") for link in response.headers["link"].split(",") 8420f38712SPatrick Williams ) 8520f38712SPatrick Williams } 8620f38712SPatrick Williams while "last" in pages and "next" in pages: 8720f38712SPatrick Williams pages = { 8820f38712SPatrick Williams rel[6:-1]: url[url.index("<") + 1 : -1] 8920f38712SPatrick Williams for url, rel in ( 9020f38712SPatrick Williams link.split(";") 9120f38712SPatrick Williams for link in response.headers["link"].split(",") 9220f38712SPatrick Williams ) 9320f38712SPatrick Williams } 9420f38712SPatrick Williams response = requests.get(pages["next"], auth=auth) 95a464a7ceSSivas SRR write_issues(response, csv_out) 9620f38712SPatrick Williams if pages["next"] == pages["last"]: 97a464a7ceSSivas SRR break 98a464a7ceSSivas SRR 99a464a7ceSSivas SRR 10020f38712SPatrick Williamsparser = argparse.ArgumentParser( 10120f38712SPatrick Williams description="Write GitHub repository issues to CSV file." 10220f38712SPatrick Williams) 103a464a7ceSSivas SRR 10420f38712SPatrick Williamsparser.add_argument( 10520f38712SPatrick Williams "username", nargs="?", help="GitHub user name, formatted as 'username'" 10620f38712SPatrick Williams) 107a464a7ceSSivas SRR 10820f38712SPatrick Williamsparser.add_argument( 10920f38712SPatrick Williams "repositories", 11020f38712SPatrick Williams nargs="+", 11120f38712SPatrick Williams help="Repository names, formatted as 'basereponame/repo'", 11220f38712SPatrick Williams) 113a464a7ceSSivas SRR 11420f38712SPatrick Williamsparser.add_argument( 11520f38712SPatrick Williams "--all", action="store_true", help="Returns both open and closed issues." 11620f38712SPatrick Williams) 1170419fb0aSSivas SRR 118a464a7ceSSivas SRRargs = parser.parse_args() 119a464a7ceSSivas SRR 120a464a7ceSSivas SRRif args.all: 12120f38712SPatrick Williams state = "all" 122a464a7ceSSivas SRR 1230419fb0aSSivas SRRusername = args.username 124a464a7ceSSivas SRR 1259fe1b12eSSivas SRRpassword = getpass.getpass("Enter your GitHub Password:") 126a464a7ceSSivas SRR 127a464a7ceSSivas SRRauth = (username, password) 128a464a7ceSSivas SRR 1290419fb0aSSivas SRR# To set the csv filename 1300419fb0aSSivas SRRcsvfilename = "" 131a464a7ceSSivas SRRfor repository in args.repositories: 13220f38712SPatrick Williams csvfilename_temp = "{}".format(repository.replace("/", "-")) 1330419fb0aSSivas SRR csvfilename = csvfilename + csvfilename_temp 13420f38712SPatrick Williamscsvfilename = csvfilename + "-issues.csv" 13520f38712SPatrick Williamswith open(csvfilename, "w") as csvfileout: 1360419fb0aSSivas SRR csv_out = csv.writer(csvfileout) 13720f38712SPatrick Williams csv_out.writerow( 13820f38712SPatrick Williams [ 13920f38712SPatrick Williams "Labels", 14020f38712SPatrick Williams "Title", 14120f38712SPatrick Williams "State", 14220f38712SPatrick Williams "Open Date", 14320f38712SPatrick Williams "Close Date", 14420f38712SPatrick Williams "URL", 14520f38712SPatrick Williams "Author", 14620f38712SPatrick Williams "Assignees", 14720f38712SPatrick Williams "Milestone", 14820f38712SPatrick Williams ] 14920f38712SPatrick Williams ) 1500419fb0aSSivas SRR for repository in args.repositories: 15120f38712SPatrick Williams l_url = "https://api.github.com/repos/{}/issues?state={}" 1520419fb0aSSivas SRR l_url = l_url.format(repository, states) 1530419fb0aSSivas SRR response = requests.get(l_url, auth=auth) 1540419fb0aSSivas SRR write_issues(response, csv_out) 1550419fb0aSSivas SRR get_issues_from_github_to_csv(repository, response) 1560419fb0aSSivas SRRcsvfileout.close() 157