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 | 6 | import json |
|
2 | from datetime import datetime, timedelta | |
|
3 | 7 | import sys |
|
8 | ||
|
9 | from datetime import datetime, timedelta | |
|
4 | 10 | from urllib import urlopen |
|
5 | 11 | |
|
12 | ||
|
6 | 13 | def get_issues(project="ipython/ipython/", state="open"): |
|
7 | 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 | 17 | return json.load(f)['issues'] |
|
10 | 18 | |
|
19 | ||
|
11 | 20 | def _parse_datetime(s): |
|
12 | 21 | """Parse dates in the format returned by the Github API.""" |
|
13 | 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 | 38 | def issues_closed_since(period=timedelta(days=365), project="ipython/ipython/"): |
|
16 | 39 | """Get all issues closed since a particular point in time. period |
|
17 | 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 | 44 | period = datetime.now() - period |
|
22 | 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 | 67 | if __name__ == "__main__": |
|
25 | # Demo | |
|
68 | # Demo, search one year back | |
|
69 | show_urls = True | |
|
26 | 70 | if len(sys.argv) > 1: |
|
27 | 71 | days = int(sys.argv[1]) |
|
28 | 72 | else: |
|
29 | 73 | days = 365 |
|
30 | n = len(issues_closed_since(timedelta(days=days))) | |
|
31 | print "%d issues closed in the last %d days." % (n, days) | |
|
74 | ||
|
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