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

# 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 

 

# code inspired/copied from contrib/github_buildbot 

#  and inspired from code from the Chromium project 

# otherwise, Andrew Melo <andrew.melo@gmail.com> wrote the rest 

# but "the rest" is pretty minimal 

 

import re 

from twisted.web import resource, server 

from twisted.python.reflect import namedModule 

from twisted.python import log 

from twisted.internet import defer 

 

class ChangeHookResource(resource.Resource): 

     # this is a cheap sort of template thingy 

    contentType = "text/html; charset=utf-8" 

    children    = {} 

    def __init__(self, dialects={}): 

        """ 

        The keys of 'dialects' select a modules to load under 

        master/buildbot/status/web/hooks/ 

        The value is passed to the module's getChanges function, providing 

        configuration options to the dialect. 

        """ 

        self.dialects = dialects 

        self.request_dialect = None 

 

    def getChild(self, name, request): 

        return self 

 

    def render_GET(self, request): 

        """ 

        Reponds to events and starts the build process 

          different implementations can decide on what methods they will accept 

        """ 

        return self.render_POST(request) 

 

    def render_POST(self, request): 

        """ 

        Reponds to events and starts the build process 

          different implementations can decide on what methods they will accept 

         

        :arguments: 

            request 

                the http request object 

        """ 

 

        try: 

            changes, src = self.getChanges( request ) 

        except ValueError, err: 

            request.setResponseCode(400, err.args[0]) 

            return err.args[0] 

        except Exception: 

            log.err(None, "Exception processing web hook.") 

            msg = "Error processing changes." 

            request.setResponseCode(500, msg) 

            return msg 

 

        log.msg("Payload: " + str(request.args)) 

 

        if not changes: 

            log.msg("No changes found") 

            return "no changes found" 

        d = self.submitChanges( changes, request, src ) 

        def ok(_): 

            request.setResponseCode(202) 

            request.finish() 

        def err(_): 

            request.setResponseCode(500) 

            request.finish() 

        d.addCallbacks(ok, err) 

        return server.NOT_DONE_YET 

 

 

    def getChanges(self, request): 

        """ 

        Take the logic from the change hook, and then delegate it 

        to the proper handler 

        http://localhost/change_hook/DIALECT will load up 

        buildmaster/status/web/hooks/DIALECT.py 

         

        and call getChanges() 

         

        the return value is a list of changes 

         

        if DIALECT is unspecified, a sample implementation is provided 

        """ 

        uriRE = re.search(r'^/change_hook/?([a-zA-Z0-9_]*)', request.uri) 

 

        if not uriRE: 

            log.msg("URI doesn't match change_hook regex: %s" % request.uri) 

            raise ValueError("URI doesn't match change_hook regex: %s" % request.uri) 

 

        changes = [] 

        src = None 

 

        # Was there a dialect provided? 

        if uriRE.group(1): 

            dialect = uriRE.group(1) 

        else: 

            dialect = 'base' 

 

        if dialect in self.dialects.keys(): 

            log.msg("Attempting to load module buildbot.status.web.hooks." + dialect) 

            tempModule = namedModule('buildbot.status.web.hooks.' + dialect) 

            changes, src = tempModule.getChanges(request,self.dialects[dialect]) 

            log.msg("Got the following changes %s" % changes) 

            self.request_dialect = dialect 

        else: 

            m = "The dialect specified, '%s', wasn't whitelisted in change_hook" % dialect 

            log.msg(m) 

            log.msg("Note: if dialect is 'base' then it's possible your URL is malformed and we didn't regex it properly") 

            raise ValueError(m) 

 

        return (changes, src) 

 

    @defer.inlineCallbacks 

    def submitChanges(self, changes, request, src): 

        master = request.site.buildbot_service.master 

        for chdict in changes: 

            change = yield master.addChange(src=src, **chdict) 

            log.msg("injected change %s" % change)