blob: b0fe98a1355a4d7017b558a14bb2fc60306a3863 [file] [log] [blame]
# This file is part of Buildbot. Buildbot is free software: you can
# redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright Buildbot Team Members
#!/usr/bin/env python
"""
github_buildbot.py is based on git_buildbot.py
github_buildbot.py will determine the repository information from the JSON
HTTP POST it receives from github.com and build the appropriate repository.
If your github repository is private, you must add a ssh key to the github
repository for the user who initiated the build on the buildslave.
"""
import re
import datetime
from twisted.python import log
import calendar
try:
import json
assert json
except ImportError:
import simplejson as json
# python is silly about how it handles timezones
class fixedOffset(datetime.tzinfo):
"""
fixed offset timezone
"""
def __init__(self, minutes, hours, offsetSign = 1):
self.minutes = int(minutes) * offsetSign
self.hours = int(hours) * offsetSign
self.offset = datetime.timedelta(minutes = self.minutes,
hours = self.hours)
def utcoffset(self, dt):
return self.offset
def dst(self, dt):
return datetime.timedelta(0)
def convertTime(myTestTimestamp):
#"1970-01-01T00:00:00+00:00"
# Normalize myTestTimestamp
if myTestTimestamp[-1] == 'Z':
myTestTimestamp = myTestTimestamp[:-1] + '-00:00'
matcher = re.compile(r'(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)([-+])(\d\d):(\d\d)')
result = matcher.match(myTestTimestamp)
(year, month, day, hour, minute, second, offsetsign, houroffset, minoffset) = \
result.groups()
if offsetsign == '+':
offsetsign = 1
else:
offsetsign = -1
offsetTimezone = fixedOffset( minoffset, houroffset, offsetsign )
myDatetime = datetime.datetime( int(year),
int(month),
int(day),
int(hour),
int(minute),
int(second),
0,
offsetTimezone)
return calendar.timegm( myDatetime.utctimetuple() )
def getChanges(request, options = None):
"""
Reponds only to POST events and starts the build process
:arguments:
request
the http request object
"""
payload = json.loads(request.args['payload'][0])
if 'pull_request' in payload:
user = payload['repository']['owner']['login']
repo = payload['repository']['name']
repo_url = payload['repository']['html_url']
else:
user = payload['repository']['owner']['name']
repo = payload['repository']['name']
repo_url = payload['repository']['url']
project = request.args.get('project', None)
if project:
project = project[0]
elif project is None:
project = ''
# This field is unused:
#private = payload['repository']['private']
changes = process_change(payload, user, repo, repo_url, project)
log.msg("Received %s changes from github" % len(changes))
return (changes, 'git')
def process_change(payload, user, repo, repo_url, project):
"""
Consumes the JSON as a python object and actually starts the build.
:arguments:
payload
Python Object that represents the JSON sent by GitHub Service
Hook.
"""
changes = []
newrev = payload['after'] if 'after' in payload else payload['pull_request']['head']['sha']
refname = payload['ref'] if 'ref' in payload else payload['pull_request']['head']['ref']
# We only care about regular heads, i.e. branches
match = re.match(r"^(refs\/heads\/|)([^/]+)$", refname)
if not match:
log.msg("Ignoring refname `%s': Not a branch" % refname)
return []
branch = match.groups()[1]
if re.match(r"^0*$", newrev):
log.msg("Branch `%s' deleted, ignoring" % branch)
return []
else:
if 'pull_request' in payload:
changes = [{
'category' : 'github_pullrequest',
'who' : user,
'files' : [],
'comments' : payload['pull_request']['title'],
'revision' : newrev,
'when' : convertTime(payload['pull_request']['updated_at']),
'branch' : branch,
'revlink' : '{0}/commit/{1}'.format(repo_url,newrev),
'repository' : repo_url,
'project' : project }]
return changes
for commit in payload['commits']:
files = []
if 'added' in commit:
files.extend(commit['added'])
if 'modified' in commit:
files.extend(commit['modified'])
if 'removed' in commit:
files.extend(commit['removed'])
when = convertTime( commit['timestamp'])
log.msg("New revision: %s" % commit['id'][:8])
chdict = dict(
who = commit['author']['name']
+ " <" + commit['author']['email'] + ">",
files = files,
comments = commit['message'],
revision = commit['id'],
when = when,
branch = branch,
revlink = commit['url'],
repository = repo_url,
project = project)
changes.append(chdict)
return changes