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