Repository navigation
Expand file tree
/
Copy pathgithub.py
More file actions
125 lines (96 loc) · 4.38 KB
/
Copy pathgithub.py
File metadata and controls
125 lines (96 loc) · 4.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# encoding: utf-8
"""
Specialized Git backend which uses Github.com for all of the heavy work
Among other things, this means that the codespeed server doesn't need to have
git installed, the ability to write files, etc.
"""
import logging
import urllib
import re
import isodate
from django.core.cache import cache
# Import from here on the off-chance someone is using a really old Python:
from django.utils import simplejson as json
logger = logging.getLogger(__name__)
GITHUB_URL_RE = re.compile(
r'^(?P<proto>\w+)://github.com/(?P<username>[^/]+)/(?P<project>[^/]+)[.]git$')
# We currently use a simple linear search of on a single parent to retrieve
# the history. This is often good enough, but might miss the actual starting
# point. Thus, we need to terminate the search after a resonable number of
# revisions.
GITHUB_REVISION_LIMIT = 10
def updaterepo(project, update=True):
return
def retrieve_revision(commit_id, username, project, revision=None):
commit_url = 'http://github.com/api/v2/json/commits/show/%s/%s/%s' % (
username, project, commit_id)
commit_json = cache.get(commit_url)
if commit_json is None:
try:
commit_json = json.load(urllib.urlopen(commit_url))
except IOError, e:
logger.exception("Unable to load %s: %s",
commit_url, e, exc_info=True)
raise e
if 'error' in commit_json:
# We'll still cache these for a brief period of time to avoid making too many requests:
cache.set(commit_url, commit_json, 300)
else:
# We'll cache successes for a very long period of time since
# SCM diffs shouldn't change:
cache.set(commit_url, commit_json, 86400 * 30)
if 'error' in commit_json:
raise RuntimeError("Unable to load %s: %s" % (commit_url, commit_json['error']))
commit = commit_json['commit']
date = isodate.parse_datetime(commit['committed_date'])
if revision:
# Overwrite any existing data we might have for this revision since
# we never want our records to be out of sync with the actual VCS:
# We need to convert the timezone-aware date to a naive (i.e.
# timezone-less) date in UTC to avoid killing MySQL:
revision.date = date.astimezone(isodate.tzinfo.Utc()).replace(tzinfo=None)
revision.author = commit['author']['name']
revision.message = commit['message']
revision.full_clean()
revision.save()
return {'date': date,
'message': commit['message'],
'body': "", # TODO: pretty-print diffs
'author': commit['author']['name'],
'author_email': commit['author']['email'],
'commitid': commit['id'],
'short_commit_id': commit['id'][0:7],
'parents': commit['parents']}
def getlogs(endrev, startrev):
if endrev != startrev:
revisions = endrev.branch.revisions.filter(
date__lte=endrev.date, date__gte=startrev.date)
else:
revisions = [i for i in (startrev, endrev) if i.commitid]
m = GITHUB_URL_RE.match(endrev.branch.project.repo_path)
if not m:
raise ValueError(
"Unable to parse Github URL %s" % endrev.branch.project.repo_path)
username = m.group("username")
project = m.group("project")
logs = []
last_rev_data = None
revision_count = 0
ancestor_found = False
#TODO: get all revisions between endrev and startrev,
# not only those present in the Codespeed DB
for revision in revisions:
last_rev_data = retrieve_revision(revision.commitid, username, project, revision)
logs.append(last_rev_data)
revision_count += 1
ancestor_found = (startrev.commitid in [rev['id'] for rev in last_rev_data['parents']])
# Simple approach to find the startrev, stop after found or after
# #GITHUB_REVISION_LIMIT revisions are fetched
while (revision_count < GITHUB_REVISION_LIMIT
and not ancestor_found
and len(last_rev_data['parents']) > 0):
last_rev_data = retrieve_revision(last_rev_data['parents'][0]['id'], username, project)
logs.append(last_rev_data)
revision_count += 1
ancestor_found = (startrev.commitid in [rev['id'] for rev in last_rev_data['parents']])
return sorted(logs, key=lambda i: i['date'], reverse=True)