123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- # 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])
- import urllib,datetime
- fname = str(datetime.datetime.now()).replace(' ','_').replace(':','-')[:19]
- open('github_{0}.json'.format(fname),'w').write(json.dumps(json.loads(urllib.unquote(request.args['payload'][0])), sort_keys = True, indent = 2))
- if 'pull_request' in payload:
- user = payload['pull_request']['user']['login']
- repo = payload['pull_request']['head']['repo']['name']
- repo_url = payload['pull_request']['head']['repo']['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:
- if payload['action'] == 'closed':
- log.msg("PR#{} closed, ignoring".format(payload['number']))
- return []
- changes = [{
- 'category' : 'github_pullrequest',
- 'who' : '{0} - PR#{1}'.format(user,payload['number']),
- '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
|