| 1 |
#!/usr/bin/python |
| 2 |
# |
| 3 |
# Gerrit Launchpad and CIA Hook, inspired by: |
| 4 |
# https://github.com/hobbs/jirret |
| 5 |
# http://cia.vc/clients/git/ciabot.bash |
| 6 |
# http://cia.vc/clients/bzr/cia_bzr.py |
| 7 |
# |
| 8 |
# Copyright (C) 2011, 2012 Catalyst IT (http://www.catalyst.net.nz) |
| 9 |
# |
| 10 |
# This program is free software: you can redistribute it and/or modify |
| 11 |
# it under the terms of the GNU General Public License as published by |
| 12 |
# the Free Software Foundation, either version 3 of the License, or |
| 13 |
# (at your option) any later version. |
| 14 |
# |
| 15 |
# This program is distributed in the hope that it will be useful, |
| 16 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 17 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 18 |
# GNU General Public License for more details. |
| 19 |
# |
| 20 |
# You should have received a copy of the GNU General Public License |
| 21 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 22 |
|
| 23 |
from email.mime.text import MIMEText |
| 24 |
from getopt import getopt |
| 25 |
import re |
| 26 |
import smtplib |
| 27 |
import subprocess |
| 28 |
import sys |
| 29 |
from xml.dom.minidom import Document |
| 30 |
import xmlrpclib |
| 31 |
|
| 32 |
FROM_ADDRESS = 'dev@mahara.org' |
| 33 |
TO_ADDRESS_SUFFIX = '@bugs.launchpad.net' |
| 34 |
CIA_PROJECT = 'Mahara' |
| 35 |
CIA_SERVER = 'http://cia.vc' |
| 36 |
BASE_DIR = '/home/gerrit/mahara_reviews' |
| 37 |
|
| 38 |
def send_notifications(change_url, project, branch, submitter, commit): |
| 39 |
# Extract git log of all merged commits |
| 40 |
git_log = subprocess.Popen(['git', '--git-dir=' + BASE_DIR + '/git/' + project + '.git', 'log', '--no-merges', commit + '^1..' + commit], stdout=subprocess.PIPE).communicate()[0] |
| 41 |
|
| 42 |
# Find bug numbers referenced in the git log |
| 43 |
bug_regexp = '[Bb]ug:? *#?([0-9]+)' |
| 44 |
tokens = re.split(bug_regexp, git_log) |
| 45 |
|
| 46 |
# Extract unique bug numbers |
| 47 |
bugs = [] |
| 48 |
for token in tokens: |
| 49 |
if re.match('^\d+$', token) and (token not in bugs): |
| 50 |
bugs.append(token) |
| 51 |
send_bug_mail(token, change_url, project, commit, submitter, branch, git_log) |
| 52 |
|
| 53 |
submit_to_cia(project, commit, branch, git_log) |
| 54 |
|
| 55 |
def send_bug_mail(bug_number, change_url, project, commit, submitter, branch, git_log): |
| 56 |
|
| 57 |
to_address = bug_number + TO_ADDRESS_SUFFIX |
| 58 |
|
| 59 |
gitorious_url = 'http://gitorious.org/mahara/%s/commit/%s' % (project, commit) |
| 60 |
body = '''Reviewed: %s |
| 61 |
Committed: %s |
| 62 |
Submitter: %s |
| 63 |
Branch: %s\n''' % (change_url, gitorious_url, submitter, branch) |
| 64 |
|
| 65 |
msg = MIMEText(body + '\n' + git_log) |
| 66 |
msg['Subject'] = 'A change has been merged' |
| 67 |
msg['From'] = FROM_ADDRESS |
| 68 |
msg['To'] = to_address |
| 69 |
|
| 70 |
s = smtplib.SMTP() |
| 71 |
s.connect() |
| 72 |
s.sendmail(FROM_ADDRESS, [to_address], msg.as_string()) |
| 73 |
s.quit() |
| 74 |
|
| 75 |
def append_commit(commits, document, project, full_commit_id, author, log): |
| 76 |
if not full_commit_id or not author: |
| 77 |
return |
| 78 |
|
| 79 |
revision = subprocess.Popen(['git', '--git-dir=' + BASE_DIR + '/git/' + project + '.git', 'rev-parse', '--short', full_commit_id], stdout=subprocess.PIPE).communicate()[0].strip() |
| 80 |
|
| 81 |
gitorious_url = 'http://gitorious.org/mahara/%s/commit/%s' % (project, full_commit_id) |
| 82 |
commit = document.createElement('commit') |
| 83 |
|
| 84 |
commit_author = document.createElement('author') |
| 85 |
commit_author.appendChild(document.createTextNode(author)) |
| 86 |
commit.appendChild(commit_author) |
| 87 |
|
| 88 |
commit_revision = document.createElement('revision') |
| 89 |
commit_revision.appendChild(document.createTextNode(revision)) |
| 90 |
commit.appendChild(commit_revision) |
| 91 |
|
| 92 |
commit_log = document.createElement('log') |
| 93 |
commit_log.appendChild(document.createTextNode(log)) |
| 94 |
commit.appendChild(commit_log) |
| 95 |
|
| 96 |
commit_url = document.createElement('url') |
| 97 |
commit_url.appendChild(document.createTextNode(gitorious_url)) |
| 98 |
commit.appendChild(commit_url) |
| 99 |
|
| 100 |
commits.append(commit) |
| 101 |
|
| 102 |
def generate_commits(document, project, git_log): |
| 103 |
commits = [] |
| 104 |
commit_id = author = log = None |
| 105 |
for line in git_log.splitlines(): |
| 106 |
if line.startswith('commit'): |
| 107 |
append_commit(commits, document, project, commit_id, author, log) |
| 108 |
commit_id = line[7:] |
| 109 |
author = log = None |
| 110 |
elif line.startswith('Author:'): |
| 111 |
full_author = line[8:] |
| 112 |
author = re.search('^(.+) <[^>]+>$', full_author).group(1) |
| 113 |
elif line.startswith(' ') and not log: |
| 114 |
log = line[4:] |
| 115 |
|
| 116 |
append_commit(commits, document, project, commit_id, author, log) |
| 117 |
return commits |
| 118 |
|
| 119 |
def submit_to_cia(project, commit, branch, git_log): |
| 120 |
doc = Document() |
| 121 |
message = doc.createElement('message') |
| 122 |
generator = doc.createElement('generator') |
| 123 |
generator_name = doc.createElement('name') |
| 124 |
generator_name.appendChild(doc.createTextNode('Mahara custom CIA script')) |
| 125 |
generator_version = doc.createElement('version') |
| 126 |
generator_version.appendChild(doc.createTextNode('1.0')) |
| 127 |
generator_url = doc.createElement('url') |
| 128 |
generator_url.appendChild(doc.createTextNode('http://gitorious.org/mahara/mahara-scripts/blobs/master/change-merged')) |
| 129 |
generator.appendChild(generator_name) |
| 130 |
generator.appendChild(generator_version) |
| 131 |
generator.appendChild(generator_url) |
| 132 |
message.appendChild(generator) |
| 133 |
|
| 134 |
source = doc.createElement('source') |
| 135 |
source_project = doc.createElement('project') |
| 136 |
source_project.appendChild(doc.createTextNode(CIA_PROJECT)) |
| 137 |
source_branch = doc.createElement('branch') |
| 138 |
source_branch.appendChild(doc.createTextNode(branch)) |
| 139 |
source.appendChild(source_project) |
| 140 |
source.appendChild(source_branch) |
| 141 |
message.appendChild(source) |
| 142 |
|
| 143 |
body = doc.createElement('body') |
| 144 |
message.appendChild(body) |
| 145 |
doc.appendChild(message) |
| 146 |
|
| 147 |
for commit in generate_commits(doc, project, git_log): |
| 148 |
body.appendChild(commit) |
| 149 |
xmlrpclib.ServerProxy(CIA_SERVER).hub.deliver(doc.toxml()) |
| 150 |
body.removeChild(commit) |
| 151 |
|
| 152 |
def main(): |
| 153 |
# https://gerrit.googlecode.com/svn/documentation/2.1.6/config-hooks.html#change-merged |
| 154 |
gerrit_args = ['change=', 'change-url=', 'project=', 'branch=', 'submitter=', 'commit='] |
| 155 |
args, unused = getopt(sys.argv[1:], '', gerrit_args) |
| 156 |
|
| 157 |
change_url = project = branch = submitter = commit = None |
| 158 |
for argname, argv in args: |
| 159 |
if argname == '--change-url': |
| 160 |
change_url = argv |
| 161 |
elif argname == '--project': |
| 162 |
project = argv |
| 163 |
elif argname == '--branch': |
| 164 |
branch = argv |
| 165 |
elif argname == '--submitter': |
| 166 |
submitter = argv |
| 167 |
elif argname == '--commit': |
| 168 |
commit = argv |
| 169 |
|
| 170 |
if change_url and project and branch and submitter and commit: |
| 171 |
send_notifications(change_url, project, branch, submitter, commit) |
| 172 |
else: |
| 173 |
print 'Missing arguments' |
| 174 |
return 1 |
| 175 |
|
| 176 |
return 0; |
| 177 |
|
| 178 |
if __name__ == '__main__': |
| 179 |
sys.exit(main()) |