#!/usr/bin/env python import json import os import sys from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from subprocess import call class GitAutoDeploy(BaseHTTPRequestHandler): CONFIG_FILEPATH = './GitAutoDeploy.conf.json' config = None quiet = False daemon = False @classmethod def getConfig(myClass): if myClass.config is None: try: configString = open(myClass.CONFIG_FILEPATH).read() except: sys.exit('Could not load ' + myClass.CONFIG_FILEPATH + ' file') try: myClass.config = json.loads(configString) except: sys.exit(myClass.CONFIG_FILEPATH + ' file is not valid json') for repository in myClass.config['repositories']: if not os.path.isdir(repository['path']): try: os.mkdir(repository['path']) except: sys.exit('Can NOT make a repository directory' + repository['path']) # sys.exit('Directory ' + repository['path'] + ' not found') # Check for a repository with a local or a remote GIT_WORK_DIR if not os.path.isdir(os.path.join(repository['path'], '.git')) \ and not os.path.isdir(os.path.join(repository['path'], 'objects')): try: call(['git clone' + " " + repository['url'] + " " + repository['path']], shell=True) except: sys.exit('Can NOT clone repository directory into ' + os.path.isdir(repository['path'])) # sys.exit('Directory ' + repository['path'] + ' is not a Git repository') return myClass.config def do_POST(self): event = self.headers.getheader('X-Github-Event') if event == 'ping': if not self.quiet: print 'Ping event received' self.respond(204) return if event != 'push': if not self.quiet: print 'We only handle ping and push events' self.respond(304) return self.respond(204) urls = self.parseRequest() for url in urls: paths = self.getMatchingPaths(url) for path in paths: self.fetch(path) self.deploy(path) def parseRequest(self): length = int(self.headers.getheader('content-length')) body = self.rfile.read(length) payload = json.loads(body) self.branch = payload['ref'] return [payload['repository']['url']] def getMatchingPaths(self, repoUrl): res = [] config = self.getConfig() for repository in config['repositories']: if repository['url'] == repoUrl: res.append(repository['path']) return res def respond(self, code): self.send_response(code) self.send_header('Content-type', 'text/plain') self.end_headers() def fetch(self, path): if not self.quiet: print "\nPost push request received" print 'Updating ' + path call(['cd "' + path + '" && git fetch'], shell=True) def deploy(self, path): config = self.getConfig() for repository in config['repositories']: if repository['path'] == path: if 'deploy' in repository: branch = None if 'branch' in repository: branch = repository['branch'] if branch is None or branch == self.branch: if not self.quiet: print 'Executing deploy command' call(['cd "' + path + '" && ' + repository['deploy']], shell=True) elif not self.quiet: print 'Push to different branch (%s != %s), not deploying' % (branch, self.branch) break def main(): server = None try: for arg in sys.argv: if arg == '-d' or arg == '--daemon-mode': GitAutoDeploy.daemon = True GitAutoDeploy.quiet = True if arg == '-q' or arg == '--quiet': GitAutoDeploy.quiet = True if GitAutoDeploy.daemon: pid = os.fork() if pid != 0: sys.exit() os.setsid() if not GitAutoDeploy.quiet: print 'Github Autodeploy Service v0.2 started' else: print 'Github Autodeploy Service v 0.2 started in daemon mode' server = HTTPServer(('', GitAutoDeploy.getConfig()['port']), GitAutoDeploy) server.serve_forever() except (KeyboardInterrupt, SystemExit) as e: if e: # wtf, why is this creating a new line? print >> sys.stderr, e if server is not None: server.socket.close() if not GitAutoDeploy.quiet: print 'Goodbye' if __name__ == '__main__': main()