]> andersk Git - zcommit.git/blob - zcommit.py
Now use abspath for calling zsend
[zcommit.git] / zcommit.py
1 #!/usr/bin/python
2
3 import cherrypy
4 from flup.server.fcgi import WSGIServer
5 import logging
6 import json
7 import os
8 import subprocess
9 import sys
10 import traceback
11
12 HERE = os.path.abspath(os.path.dirname(__file__))
13 ZWRITE = os.path.join(HERE, 'bin', 'zsend')
14 LOG_FILENAME = 'logs/zcommit.log'
15
16 # Set up a specific logger with our desired output level
17 logger = logging.getLogger(__name__)
18 logger.setLevel(logging.DEBUG)
19
20 # Add the log message handler to the logger
21 handler = logging.FileHandler(LOG_FILENAME)
22 logger.addHandler(handler)
23
24 def zephyr(sender, klass, instance, zsig, msg):
25     # TODO: spoof the sender
26     logger.info("""About to send zephyr:
27 sender: %(sender)s
28 class: %(klass)s
29 instance: %(instance)s
30 zsig: %(zsig)s
31 msg: %(msg)s""" % {'sender' : sender,
32                    'klass' : klass,
33                    'instance' : instance,
34                    'zsig' : zsig,
35                    'msg' : msg})
36     cmd = [ZWRITE, '-S', sender, '-c', klass, '-i', instance,
37            '-s', zsig, '-d', '-m', msg]
38     subprocess.check_call(cmd)
39
40 class Application(object):
41     @cherrypy.expose
42     def index(self):
43         logger.debug('Hello world app reached')
44         return """
45 <p> <i>Welcome to zcommit.</i> </p>
46
47 <p> zcommit allows you to send zephyr notifications by sending an HTTP
48 POST request to a URL.  Currently zcommit supports POST-backs from
49 github.  If you would like it to support another form of POST-back,
50 please let us know (zcommit@mit.edu). </p>
51
52 <h1> URL structure </h1>
53
54 The URL you post to is structured as follows:
55 <tt>http://zcommit.mit.edu/$type/$key1/$value1/$key2/$value2/...</tt>.
56 So for example, the URL
57 <tt>http://zcommit.mit.edu/github/class/zcommit/instance/commit</tt>
58 is parsed as having type <tt>github</tt>, class <tt>zcommit</tt>, and
59 instance <tt>commit</tt>.  Using this information, zcommit figures out
60 how to form a useful message which is then sends as a zephyr.
61
62 <h1> Github </h1>
63
64 Set your POST-back URL to
65 <tt>http://zcommit.mit.edu/github/class/$classname</tt>, followed by
66 any of the following optional key/value parameters:
67
68 <ul>
69 <li> <tt>/instance/$instance</tt> </li>
70 <li> <tt>/zsig/$zsig</tt> </li>
71 <li> <tt>/sender/$sender</tt> </li>
72 </ul>
73 """
74
75     class Github(object):
76         @cherrypy.expose
77         def default(self, *args, **query):
78             try:
79                 return self._default(*args, **query)
80             except Exception, e:
81                 logger.error('Caught exception %s:\n%s' % (e, traceback.format_exc()))
82                 raise
83
84         def _default(self, *args, **query):
85             logger.info('A %s request with args: %r and query: %r' %
86                         (cherrypy.request.method, args, query))
87             opts = {}
88             if len(args) % 2:
89                 raise cherrypy.HTTPError(400, 'Invalid submission URL')
90             logger.debug('Passed validation')
91             for i in xrange(0, len(args), 2):
92                 opts[args[i]] = args[i + 1]
93             logger.debug('Set opts')
94             if 'class' not in opts:
95                 raise cherrypy.HTTPError(400, 'Must specify a zephyr class name')
96             logger.debug('Specified a class')
97             if cherrypy.request.method == 'POST':
98                 logger.debug('About to load data')
99                 payload = json.loads(query['payload'])
100                 logger.debug('Loaded payload data')
101                 zsig = payload['ref']
102                 if 'zsig' in opts:
103                     zsig = '%s: %s' % (opts['zsig'], zsig)
104                 sender = opts.get('sender', 'daemon.zcommit')
105                 logger.debug('Set zsig')
106                 for c in reversed(payload['commits']):
107                     inst = opts.get('instance', c['id'][:8])
108                     actions = []
109                     if c.get('added'):
110                         actions.append('Added: %s\n' % '\n  '.join(c['added']))
111                     if c.get('removed'):
112                         actions.append('Removed: %s\n' % '\n  '.join(c['removed']))
113                     if c.get('modified'):
114                         actions.append('Modified: %s\n' % '\n  '.join(c['modified']))
115                     if not actions:
116                         actions.append('Something weird happened... could not figure out what action to take')
117                     info = {'name' : c['author']['name'],
118                             'email' : c['author']['email'],
119                             'message' : c['message'],
120                             'timestamp' : c['timestamp'],
121                             'actions' : '--\n'.join(actions)}
122                     
123                     msg = """%(name)s <%(email)s> (%(timestamp)s)
124 > %(message)s
125 --
126 %(actions)s""" % info
127                     zephyr(sender, opts['class'], inst, zsig, msg)
128                 msg = 'Thanks for posting!'
129             else:
130                 msg = ('If you had sent a POST request to this URL, would have sent'
131                        ' a zepyhr to -c %s' % opts['class'])
132             return msg
133
134     github = Github()
135
136 def main():
137     app = cherrypy.tree.mount(Application(), '/zcommit')
138     cherrypy.server.unsubscribe()
139     cherrypy.engine.start()
140     try:
141         WSGIServer(app, environ={'SCRIPT_NAME' : '/zcommit'}).run()
142     finally:
143         cherrypy.engine.stop()
144
145 if __name__ == '__main__':
146     sys.exit(main())
This page took 0.250976 seconds and 5 git commands to generate.