[geany/infrastructure] 8e4aba: Add git2irc script and its sample config

Enrico Tröger git-noreply at xxxxx
Sun Jul 15 10:08:33 UTC 2012


Branch:      refs/heads/master
Author:      Enrico Tröger <enrico.troeger at uvena.de>
Committer:   Enrico Tröger <enrico.troeger at uvena.de>
Date:        Sun, 15 Jul 2012 10:08:33
Commit:      8e4abadcaa8b3539bc8e5bde7970d0a5c724b295
             https://github.com/geany/infrastructure/commit/8e4abadcaa8b3539bc8e5bde7970d0a5c724b295

Log Message:
-----------
Add git2irc script and its sample config


Modified Paths:
--------------
    scripts/git2irc/git2irc.conf
    scripts/git2irc/git2irc.py

Modified: scripts/git2irc/git2irc.conf
12 files changed, 12 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,12 @@
+[git]
+repositories=geany;geany-plugins;infrastructure;newsletter;talks;plugins.geany.org
+
+[irc]
+channel=#geany
+host=localhost
+port=7766
+
+[shortener]
+url=http://tiny.cc/
+login=username
+key=123456-789-123456-789


Modified: scripts/git2irc/git2irc.py
224 files changed, 224 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,224 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# git2irc.py - Notify the Geany IRC channel of Git commits
+#
+# Copyright 2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+# Copyright 2012 Matthew Brush <matt(at)geany(dot)org>
+#
+# This program 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; either version 2 of the License, or
+# (at your option) any later version.
+#
+# 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.
+#
+
+'''
+Sends Git commit notifications to IRC via SweetGeany bot.
+
+Requires a file ``git2irc.conf`` which contains something like this::
+
+  [git]
+  repositories=one;or;more;repos
+
+  [irc]
+  channel=#thechannel
+  host=hostname
+  port=portnum
+
+  [shortener]
+  url=http://tiny.cc/
+  login=apiuser
+  key=apikey
+
+Not having any of the sections, options or values will result in a run-time
+error. No smart checking is performed.
+'''
+
+from cgi import FieldStorage
+from json import loads
+from urllib2 import urlopen
+from urllib import urlencode
+import logging
+import logging.handlers
+import socket
+try:
+    from configparser import SafeConfigParser #py3
+except ImportError:
+    from ConfigParser import SafeConfigParser #py2
+
+
+# hard-coded constants, adjust for environment
+LOG_FILENAME = '/var/log/git2irc.log'
+# todo: should be `/etc/git2irc.conf` ?
+CONFIG_FILENAME = '/srv/www/irc.geany.org/git2irc.conf'
+
+# global and cuts across concerns, assumed to be properly initialized later
+logger = None # see init_logging()
+config = { 'git': {}, 'irc': {}, 'shortener': {} }   # see init_config()
+
+
+#----------------------------------------------------------------------
+def init_config(conf_filename):
+    """
+    Reads the configuration file into a global dictionary.
+    """
+    global config # used everywhere
+    try:
+        conf = SafeConfigParser({
+             'git': { 'repositories': '' },
+              'irc': { 'channel': '', 'host': '', 'port': 0 },
+              'shortener': { 'url': '', 'login': '', 'key': '' } })
+        conf.read(conf_filename)
+        config['git']['repositories'] = [itm.strip() \
+            for itm in conf.get('git', 'repositories').split(';') if itm.strip()]
+        config['irc']['channel'] = conf.get('irc', 'channel')
+        config['irc']['host'] = conf.get('irc', 'host')
+        config['irc']['port'] = int(conf.get('irc', 'port'))
+        config['shortener']['url'] = config.get('shortener', 'url')
+        config['shortener']['login'] = config.get('shortener', 'login')
+        config['shortener']['key'] = config.get('shortener', 'key')
+        logger.debug('Read configuration dict: %s' % config)
+    # catch-all: will be for invalid config file/section/option, unknown
+    # filename, etc
+    except Exception as e:
+        logger.warn(u"Exception reading config file '%s': %e", conf_filename,
+            e, exc_info=True)
+
+
+#----------------------------------------------------------------------
+def init_logging():
+    """"
+    Initializes the logging file for all to use.
+    """
+    global logger # used everywhere
+    logger = logging.getLogger('git2irc')
+    logger.setLevel(logging.DEBUG)
+    file_handler = logging.FileHandler(LOG_FILENAME)
+    file_handler.setLevel(logging.DEBUG)
+    formatter = logging.Formatter('%(asctime)s %(name)s: %(levelname)s: %(message)s')
+    file_handler.setFormatter(formatter)
+    logger.addHandler(file_handler)
+    # mail
+    mail_handler = logging.handlers.SMTPHandler(
+        u'localhost',
+        u'git-noreply at geany.org',
+        [u'enrico.troeger at uvena.de'],
+        u'Error on git_post_commit')
+    mail_handler.setLevel(logging.WARNING)
+    logger.addHandler(mail_handler)
+    logger.debug('Logging initialized')
+
+
+#----------------------------------------------------------------------
+def shorten_url(long_url):
+    """
+    Uses the tiny.cc API to shorten URL's for nice IRC messages.
+    """
+    req = { 'c': 'rest_api',
+            'm': 'shorten',
+            'version': '2.0.3',
+            'format': 'json',
+            'shortUrl': '',
+            'longUrl': long_url,
+            'login': config['shortener']['login'],
+            'apiKey': config['shortener']['key'] }
+    req_enc = urlencode(req)
+    req_url = '%s?%s' % (config['shortener']['url'], req_enc)
+    short_url = long_url # default is to return same URL (ie. in case of error)
+    try:
+        resp_file = urlopen(req_url)
+        resp_dict = loads(resp_file.read())
+        if int(resp_dict['errorCode']) == 0:
+            short_url = resp_dict['results']['short_url']
+            logger.debug('Shortened URL: %s' % short_url)
+        else:
+            logger.warn(u'Error shortening URL: %s: %s' % (
+                resp_dict['errorCode'], resp_dict['errorMessage']))
+    except Exception as e: # generally, urllib2.URLError
+        logger.warn(u'Exception shortening URL: %e', e, exc_info=True)
+    return short_url
+
+
+#----------------------------------------------------------------------
+def send_commit(message):
+    """
+    Dumps the message to IRC via SweetGeany.
+    """
+    irc_message = u'Freenode %s %s' % (config['irc']['channel'], message)
+    irc_bot_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+    irc_bot_socket.connect((config['irc']['host'], config['irc']['port']))
+    irc_bot_socket.send(irc_message.encode('utf-8'))
+    irc_bot_socket.close()
+    logger.debug('Message sent to IRC: %s' % message)
+
+
+#----------------------------------------------------------------------
+def handle_irc_message(repository, content):
+    """
+    Processes the post-commit-hook from Github.com web hooks.
+    """
+    try:
+        branch = content['ref']
+        branch = branch.rsplit('/', 1)[1]
+    except (KeyError, IndexError), rev_parse_e:
+        logger.warn(u'An error occurred at ref parsing: %s' % rev_parse_e, exc_info=True)
+        branch = 'unknown'
+
+    for commit in content['commits']:
+        author = commit['author'].get('username', 'Unknown User')
+        commit_id = commit['id']
+        message = commit['message'].splitlines()[0]
+        url = shorten_url(commit['url'])
+        irc_line = u'[%s/%s] %s - %s (%s)' % (repository, branch, author, message, url)
+        send_commit(irc_line)
+        logger.info(u"Sent message to channel '%s' for '%s' (%s)" % (
+            config['irc']['channel'], author, commit_id))
+
+
+#----------------------------------------------------------------------
+def main():
+    """
+    Script entry-point, reads from github.com request and processes the
+    event.
+    """
+    # parse query string
+    arguments = FieldStorage(keep_blank_values=True)
+
+    json = arguments.getvalue('payload')
+    content = loads(json)
+    if content.has_key('commits'):
+        repo = content['repository']['name']
+        if repo in config['git']['repositories']:
+            handle_irc_message(repo, content)
+
+
+#----------------------------------------------------------------------
+if __name__ == '__main__':
+
+    init_logging()
+
+    logger.debug('Script started')
+
+    init_config(CONFIG_FILENAME)
+
+    try:
+        main()
+    except Exception, e:
+        logger.warn(u'An error occurred: %s' % e, exc_info=True)
+
+    print 'Content-type: text/html'
+    print
+
+    logger.debug('Script complete')
+
+    logging.shutdown()


@@ Diff output truncated at 100000 characters. @@


--------------
This E-Mail was brought to you by github_commit_mail.py (Source: TBD).



More information about the Commits mailing list