Show More
@@ -1,17 +1,40 b'' | |||||
|
1 | #!/usr/bin/env python | |||
|
2 | """Simple tools to query github.com and gather stats about issues. | |||
|
3 | """ | |||
|
4 | from __future__ import print_function | |||
|
5 | ||||
1 | import json |
|
6 | import json | |
2 | from datetime import datetime, timedelta |
|
|||
3 | import sys |
|
7 | import sys | |
|
8 | ||||
|
9 | from datetime import datetime, timedelta | |||
4 | from urllib import urlopen |
|
10 | from urllib import urlopen | |
5 |
|
11 | |||
|
12 | ||||
6 | def get_issues(project="ipython/ipython/", state="open"): |
|
13 | def get_issues(project="ipython/ipython/", state="open"): | |
7 | """Get a list of the issues from the Github API.""" |
|
14 | """Get a list of the issues from the Github API.""" | |
8 |
f = urlopen("http://github.com/api/v2/json/issues/list/%s%s" % (project, |
|
15 | f = urlopen("http://github.com/api/v2/json/issues/list/%s%s" % (project, | |
|
16 | state)) | |||
9 | return json.load(f)['issues'] |
|
17 | return json.load(f)['issues'] | |
10 |
|
18 | |||
|
19 | ||||
11 | def _parse_datetime(s): |
|
20 | def _parse_datetime(s): | |
12 | """Parse dates in the format returned by the Github API.""" |
|
21 | """Parse dates in the format returned by the Github API.""" | |
13 | return datetime.strptime(s.rpartition(" ")[0], "%Y/%m/%d %H:%M:%S") |
|
22 | return datetime.strptime(s.rpartition(" ")[0], "%Y/%m/%d %H:%M:%S") | |
14 |
|
23 | |||
|
24 | ||||
|
25 | def issues2dict(issues): | |||
|
26 | """Convert a list of issues to a dict, keyed by issue number.""" | |||
|
27 | idict = {} | |||
|
28 | for i in issues: | |||
|
29 | idict[i['number']] = i | |||
|
30 | return idict | |||
|
31 | ||||
|
32 | ||||
|
33 | def is_pull_request(issue): | |||
|
34 | """Return True if the given issue is a pull request.""" | |||
|
35 | return 'pull_request_url' in issue | |||
|
36 | ||||
|
37 | ||||
15 | def issues_closed_since(period=timedelta(days=365), project="ipython/ipython/"): |
|
38 | def issues_closed_since(period=timedelta(days=365), project="ipython/ipython/"): | |
16 | """Get all issues closed since a particular point in time. period |
|
39 | """Get all issues closed since a particular point in time. period | |
17 | can either be a datetime object, or a timedelta object. In the |
|
40 | can either be a datetime object, or a timedelta object. In the | |
@@ -21,11 +44,47 b' latter case, it is used as a time before the present."""' | |||||
21 | period = datetime.now() - period |
|
44 | period = datetime.now() - period | |
22 | return [i for i in allclosed if _parse_datetime(i['closed_at']) > period] |
|
45 | return [i for i in allclosed if _parse_datetime(i['closed_at']) > period] | |
23 |
|
46 | |||
|
47 | ||||
|
48 | def sorted_by_field(issues, field='closed_at', reverse=False): | |||
|
49 | """Return a list of issues sorted by closing date date.""" | |||
|
50 | return sorted(issues, key = lambda i:i[field], reverse=reverse) | |||
|
51 | ||||
|
52 | ||||
|
53 | def report(issues, show_urls=False): | |||
|
54 | """Summary report about a list of issues, printing number and title. | |||
|
55 | """ | |||
|
56 | # titles may have unicode in them, so we must encode everything below | |||
|
57 | if show_urls: | |||
|
58 | for i in issues: | |||
|
59 | print('* `%d <%s>`_: %s' % (i['number'], | |||
|
60 | i['html_url'].encode('utf-8'), | |||
|
61 | i['title'].encode('utf-8'))) | |||
|
62 | else: | |||
|
63 | for i in issues: | |||
|
64 | print('* %d: %s' % (i['number'], i['title'].encode('utf-8'))) | |||
|
65 | ||||
|
66 | ||||
24 | if __name__ == "__main__": |
|
67 | if __name__ == "__main__": | |
25 | # Demo |
|
68 | # Demo, search one year back | |
|
69 | show_urls = True | |||
26 | if len(sys.argv) > 1: |
|
70 | if len(sys.argv) > 1: | |
27 | days = int(sys.argv[1]) |
|
71 | days = int(sys.argv[1]) | |
28 | else: |
|
72 | else: | |
29 | days = 365 |
|
73 | days = 365 | |
30 | n = len(issues_closed_since(timedelta(days=days))) |
|
74 | ||
31 | print "%d issues closed in the last %d days." % (n, days) |
|
75 | if 1: | |
|
76 | issues = sorted_by_field(issues_closed_since(timedelta(days=days)), | |||
|
77 | reverse=True) | |||
|
78 | ||||
|
79 | pulls = filter(is_pull_request, issues) | |||
|
80 | regular = filter(lambda i: not is_pull_request(i), issues) | |||
|
81 | n = len(issues) | |||
|
82 | ||||
|
83 | print("%d total issues closed in the last %d days." % (n, days)) | |||
|
84 | print("%d pull requests and %d regular issues." % (len(pulls), len(regular))) | |||
|
85 | print() | |||
|
86 | print('Pull requests (%d):\n' % len(pulls)) | |||
|
87 | report(pulls, show_urls) | |||
|
88 | print() | |||
|
89 | print('Regular issues (%d):\n' % len(regular)) | |||
|
90 | report(regular, show_urls) |
General Comments 0
You need to be logged in to leave comments.
Login now