git/list[1] front-page[2] threads[3] people[4] search[5] about
 

CIA hook for contrib/

From
Eric Raymond <esr@thyrsus.com>
Date
Mar 27, 2010, 10:26 UTC
Message-ID
<20100327102632.GA5043@thyrsus.com>
Summary:
* The CIA hooks for git are presently dusty and somewhat broken.
* I am requesting that they be given a home in git contrib/.
* I am supplying working, updated versions.
* I will accept maintainance responsibility if required.

Many listmembers will be aware of CIA.vc, a useful service that echoes commits from open-source projects to IRC channels and maintains various interesting statistics on commit activity. Under git, it is supported by one of two hook scripts: ciabot.pl and ciabot.pl.

In the course of migrating the GPSD project from Subversion to git, I discovered that the 2006 version of ciabot.sh available from CIA.vc is broken. It requires, but does not have, a PATH adjustment to cope with the fact that various git tools it uses now go in a commands directory private to git. The 2008 version of ciabot.sh made available on the git wiki also has no PATH adjustment.

Upon investigating further, I find that ciabot.sh seems to be a derivative of ciabot.pl, which is a dangling bit of the moribund Cogito project. I have been unable to get responses from the authors of either ciabot.sh or ciabot.pl.

A fixed and working version in shell is enclosed. It has some advantages over the 2006 and 2008 versions:

* It uses only POSIX features.  Thus, it will work with Debian/Ubuntu
  dash and BSD's non-bash shells.
* It's faster, because it uses a lighter-weight shell.
* It's much closer to being autoconfiguring.  In the normal case, all
  the person installing an instance need supply is the project name.
* It is considerably better documented.
* It can support cgit as well as gitweb installations.

I am also enclosing a rewrite in Python. This has a serious functional advantage over either Perl or sh; the batteries-included effect of the Python libraries means it's not dependent on things like the path location of sendmail or whether the hosting site will allow it to run wget.

I think the broad usage of CIA.vc justifies adding one of these as an official ciabot hook to git contrib/, and am so proposing. Should it be required, I will accept maintainance responsibility; I expect the amount of effort involved to be minimal.

Both versions have been live-tested on the GPSD project repo. The Python version is now in production use there.

Code is enclosed.
-- 
		<a href="http://www.catb.org/~esr/">Eric S. Raymond</a>


#!/usr/bin/env python
# Distributed under the terms of the GNU General Public License v2
# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
#
# This script contains porcelain and porcelain byproducts.
# It's Python because the Python standard libraries avoid portability/security
# issues raised by callouts in the ancestral Perl and sh scripts.  It should
# be compatible back to Python 2.1.5.
#
# It is meant to be run either on a post-commit hook or in an update
# hook:
#
# post-commit: It queries for current HEAD and latest commit ID to get the
# information it needs.
#
# update: You have to call it once per merged commit:
#
#       refname=$1
#       oldhead=$2
#       newhead=$3
#       for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do
#               /path/to/ciabot.py ${refname} ${merged}
#       done
#
# Note: this script uses mail, not XML-RPC, in order to avoid stalling
# until timeout when the XML-RPC server is down. 
#
# Call with -n to see the notification mail dumped to stdout rather
# than shipped to CIA.
#
import os, sys, commands, socket, urllib
#
# The project as known to CIA. You will want to change this:
#
project="GPSD"

#
# You may not need to change these:
#

# Name of the repository.
# You can hardwire this to make the script faster.
repo = os.path.basename(os.getcwd())

# Fully-qualified domain name of this host.
# You can hardwire this to make the script faster.
host = socket.getfqdn()

# Changeset URL prefix for your repo: when the commit ID is appended
# to this, it should point at a CGI that will display the commit
# through gitweb or something similar. The default will probably
# work if you have a typical gitweb/cgit setup.
#
#urlprefix="http://%(host)s/cgi-bin/gitweb.cgi?p=%(repo)s;a=commit;h="%locals()
urlprefix="http://%(host)s/cgi-bin/cgit.cgi/%(repo)s/commit/?id="%locals()

#
# No user-serviceable parts below this line:
#

def do(command):
    return commands.getstatusoutput(command)[1]

# Addresses for the e-mail. The from address is a dummy, since CIA
# will never reply to this mail.
fromaddr = "CIABOT-NOREPLY@" + host
toaddr = "cia@cia.vc"

# Identify the generator script.
# Should only change when the script itself has a new home
generator="http://www.catb.org/~esr/ciabot.sh"

# Should add to the command path both places sendmail is likely to lurk, 
# and the git private command directory.
os.environ["PATH"] += ":/usr/sbin/:" + do("git --exec-path")

# Call this script with -n tp dump the notification mail to stdout
mailit = True 
if sys.argv[1] == '-n':
    mailit = False
    sys.argv.pop(1)

# Script wants a reference to head followed by the commit ID to notify about. 
if len(sys.argv) == 1:
    refname = do("git symbolic-ref HEAD 2>/dev/null")
    merged = do("git rev-parse HEAD")
else:
    refname = sys.argv[1]
    merged = sys.argv[2]

# This tries to turn your gitwebbish URL into a tinyurl so it will take up
# less space on the IRC notification line. You can tweak the tinyfier
# service if you need to.
tinyifier = "http://tinyurl.com/api-create.php?url="
try:
    url = open(urllib.urlretrieve(tinyifier + urlprefix + merged)[0]).read()
except:
    url = urlprefix + merged

refname = os.path.basename(refname)
gitver = do("git --version").split()[0]	# Git version number

rev = do("git describe ${merged} 2>/dev/null") or merged[:12]
rawcommit = do("git cat-file commit " + merged)
files=do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-<file>&</file>-'")

inheader = True
headers = {}
logmessage = ""
for line in rawcommit.split("\n"):
    if inheader:
        if line:
            fields = line.split()
            headers[fields[0]] = " ".join(fields[1:])
        else:
            inheader = False
    else:
        logmessage = line
        break
(author, ts) = headers["author"].split(">")
author = author.replace("<", "").split("@")[0].split()[-1]
ts = ts.strip()

out = '''\
<message>
  <generator>
    <name>CIA Shell client for Git</name>
    <version>%(gitver)s</version>
    <url>%(generator)s</url>
  </generator>
  <source>
    <project>%(project)s</project>
    <branch>%(repo)s:%(refname)s</branch>
  </source>
  <timestamp>%(ts)s</timestamp>
  <body>
    <commit>
      <author>%(author)s</author>
      <revision>%(rev)s</revision>
      <files>
        %(files)s
      </files>
      <log>%(logmessage)s %(url)s</log>
      <url>%(url)s</url>
    </commit>
  </body>
</message>
''' % locals()

message = '''\
Message-ID: <%(merged)s.%(author)s@%(project)s>
From: %(fromaddr)s
To: %(toaddr)s
Content-type: text/xml
Subject: DeliverXML

%(out)s''' % locals()

if mailit:
    import smtplib
    server = smtplib.SMTP('localhost')
    server.sendmail(fromaddr, [toaddr], message)
    server.quit()
else:
    print message

#End
Next: Junio C Hamano
Message 1 of 8 in “CIA hook for contrib/”
  1. Eric RaymondMar 27, 2010
  2. Junio C HamanoMar 29, 2010
  3. Eric RaymondMar 29, 2010
  4. Petr BaudisApr 21, 2010
  5. Eric RaymondApr 21, 2010
  6. Petr BaudisApr 21, 2010
  7. Eric RaymondApr 21, 2010
  8. Eric RaymondApr 21, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.