summaryrefslogtreecommitdiff
path: root/repo/hooks/ciabot.py
blob: b788b56acff69c0dad5eac324fbbd02442761fe3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/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