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

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

# 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" 

    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]) 

        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'] 

        refname = payload['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.group(1) 

        if re.match(r"^0*$", newrev): 

            log.msg("Branch `%s' deleted, ignoring" % branch) 

            return [] 

        else: 

            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