diff --git a/manifests/site.pp b/manifests/site.pp
index 5d99d12a17..bc0cb6a788 100644
--- a/manifests/site.pp
+++ b/manifests/site.pp
@@ -43,8 +43,20 @@ class openstack_jenkins_slave {
#
# Long lived servers:
#
-node "gerrit.openstack.org", "gerrit-dev.openstack.org" {
+node "gerrit.openstack.org" {
include openstack_server
+ class { 'gerrit':
+ canonicalweburl => "https://review.openstack.org/",
+ email => "review@openstack.org",
+ }
+}
+
+node "gerrit-dev.openstack.org" {
+ include openstack_server
+ class { 'gerrit':
+ canonicalweburl => "https://review-dev.openstack.org/",
+ email => "review-dev@openstack.org",
+ }
}
node "docs.openstack.org" {
diff --git a/modules/gerrit/files/change-merged b/modules/gerrit/files/change-merged
new file mode 100755
index 0000000000..9c8c6c4438
--- /dev/null
+++ b/modules/gerrit/files/change-merged
@@ -0,0 +1,174 @@
+#!/usr/bin/env python
+#
+# Gerrit-Launchpad Hook, inspired by https://github.com/hobbs/jirret
+#
+# Copyright (C) 2011 Catalyst IT (http://www.catalyst.net.nz)
+# Copyright (C) 2011 Rackspace US, Inc.
+#
+# 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 3 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, see .
+
+# Changed by James E. Blair to add
+# config file parsing, and signed email with commands.
+
+# Some parts:
+# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+from email.mime.text import MIMEText
+from getopt import getopt
+import re
+import smtplib
+import subprocess
+import sys, os
+import pyme, pyme.core
+import StringIO
+import ConfigParser
+
+TO_ADDRESS_SUFFIX = '@bugs.launchpad.net'
+BASE_DIR = '/home/gerrit2/review_site'
+GERRIT_CONFIG = os.environ.get('GERRIT_CONFIG','/home/gerrit2/review_site/etc/gerrit.config')
+
+def get_broken_config(filename):
+ """ gerrit config ini files are broken and have leading tabs """
+ text = ""
+ with open(filename,"r") as conf:
+ for line in conf.readlines():
+ text = "%s%s" % (text, line.lstrip())
+
+ fp = StringIO.StringIO(text)
+ c=ConfigParser.ConfigParser()
+ c.readfp(fp)
+ return c
+
+gerrit_config = get_broken_config(GERRIT_CONFIG)
+FROM_ADDRESS = gerrit_config.get('user', 'email')
+
+
+# From Launchpad: lib/lp/services/mail/incoming.py
+# Match '\n' and '\r' line endings. That is, all '\r' that are not
+# followed by a '\n', and all '\n' that are not preceded by a '\r'.
+non_canonicalised_line_endings = re.compile('((?>> canonicalise_line_endings('\n\nfoo\nbar\rbaz\r\n')
+ '\r\n\r\nfoo\r\nbar\r\nbaz\r\n'
+
+ >>> canonicalise_line_endings('\r\rfoo\r\nbar\rbaz\n')
+ '\r\n\r\nfoo\r\nbar\r\nbaz\r\n'
+
+ >>> canonicalise_line_endings('\r\nfoo\r\nbar\nbaz\r')
+ '\r\nfoo\r\nbar\r\nbaz\r\n'
+ """
+ if non_canonicalised_line_endings.search(text):
+ text = non_canonicalised_line_endings.sub('\r\n', text)
+ if trailing_whitespace.search(text):
+ text = trailing_whitespace.sub('', text)
+ return text
+# End code from Launchpad: lib/lp/services/mail/incoming.py
+
+def email_tracker(change_url, project, branch, submitter, commit):
+ # Extract git log of all merged commits
+ git_log = subprocess.Popen(['git', '--git-dir=' + BASE_DIR + '/git/' + project + '.git', 'log', '--no-merges', commit + '^1..' + commit], stdout=subprocess.PIPE).communicate()[0]
+
+ # Find bug numbers referenced in the git log
+ bug_regexp = r'([Bb]ug|[Ll][Pp])\s*[#:]?\s*(\d+)'
+ tokens = re.split(bug_regexp, git_log)
+
+ # Extract unique bug numbers
+ bugs = []
+ for token in tokens:
+ if re.match('^\d+$', token) and (token not in bugs):
+ bugs.append(token)
+ send_bug_mail(token, change_url, project, commit, submitter, branch, git_log)
+
+def send_bug_mail(bug_number, change_url, project, commit, submitter, branch, git_log):
+
+ to_address = bug_number + TO_ADDRESS_SUFFIX
+
+ gitorious_url = 'http://github.com/%s/commit/%s' % (project, commit)
+ body = '''Reviewed: %s
+Committed: %s
+Submitter: %s
+Branch: %s
+
+ status fixcommitted
+ done\n''' % (change_url, gitorious_url, submitter, branch)
+
+ body = body + '\n' + git_log
+
+ bodypart = MIMEText(body)
+ bodystring = bodypart.as_string()
+ bodystring = canonicalise_line_endings(bodystring)
+
+ plain = pyme.core.Data(bodystring)
+ cipher = pyme.core.Data()
+ gpg = pyme.core.Context()
+ gpg.set_armor(1)
+
+ gpg.op_keylist_start(FROM_ADDRESS, 0)
+ gpg.op_sign(plain, cipher, pyme.pygpgme.GPGME_SIG_MODE_DETACH)
+ cipher.seek(0,0)
+ signature = cipher.read()
+
+ from email.mime.multipart import MIMEMultipart
+ from email.mime.base import MIMEBase
+ msg = MIMEMultipart(_subtype='signed',protocol='application/pgp-signature')
+ msg['Subject'] = 'A change has been merged to %s' % project
+ msg['From'] = FROM_ADDRESS
+ msg['To'] = to_address
+
+ msg.attach(bodypart)
+ signpart = MIMEBase('application','pgp-signature')
+ signpart.set_payload(signature)
+ msg.attach(signpart)
+
+ #print msg.as_string()
+ s = smtplib.SMTP()
+ s.connect()
+ s.sendmail(FROM_ADDRESS, [to_address], msg.as_string())
+ s.quit()
+
+def main():
+ # https://gerrit.googlecode.com/svn/documentation/2.1.6/config-hooks.html#change-merged
+ gerrit_args = ['change=', 'change-url=', 'project=', 'branch=', 'submitter=', 'commit=']
+ args, unused = getopt(sys.argv[1:], '', gerrit_args)
+
+ change_url = project = branch = submitter = commit = None
+ for argname, argv in args:
+ if argname == '--change-url':
+ change_url = argv
+ elif argname == '--project':
+ project = argv
+ elif argname == '--branch':
+ branch = argv
+ elif argname == '--submitter':
+ submitter = argv
+ elif argname == '--commit':
+ commit = argv
+
+ if change_url and project and branch and submitter and commit:
+ email_tracker(change_url, project, branch, submitter, commit)
+ else:
+ print 'Missing arguments'
+ return 1
+
+ return 0;
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/modules/gerrit/files/replication.config b/modules/gerrit/files/replication.config
new file mode 100644
index 0000000000..ebb5978f2f
--- /dev/null
+++ b/modules/gerrit/files/replication.config
@@ -0,0 +1,5 @@
+# This file is managed by puppet.
+# https://github.com/openstack/openstack-ci-puppet
+
+[remote "github"]
+url = git@github.com:${name}.git
diff --git a/modules/gerrit/lib/facter/gerrit_installed.rb b/modules/gerrit/lib/facter/gerrit_installed.rb
new file mode 100644
index 0000000000..b3ec1019bc
--- /dev/null
+++ b/modules/gerrit/lib/facter/gerrit_installed.rb
@@ -0,0 +1,5 @@
+Facter.add("gerrit_installed") do
+ setcode do
+ FileTest.directory?("/home/gerrit2/review_site/")
+ end
+end
diff --git a/modules/gerrit/manifests/init.pp b/modules/gerrit/manifests/init.pp
new file mode 100644
index 0000000000..90b32694d3
--- /dev/null
+++ b/modules/gerrit/manifests/init.pp
@@ -0,0 +1,43 @@
+class gerrit($canonicalweburl='',
+ $openidssourl="https://login.launchpad.net/+openid",
+ $email='',
+ $commentlinks = [ { name => 'launchpad',
+ match => '([Bb]ug|[Ll][Pp])\\s*[#:]?\\s*(\\d+)',
+ link => 'https://code.launchpad.net/bugs/$2' } ]
+ ) {
+
+ if $gerrit_installed {
+ #notice('Gerrit is installed')
+
+ file { '/home/gerrit2/review_site/etc/replication.config':
+ owner => 'root',
+ group => 'root',
+ mode => 444,
+ ensure => 'present',
+ source => 'puppet:///modules/gerrit/replication.config',
+ replace => 'true',
+ }
+
+ file { '/home/gerrit2/review_site/etc/gerrit.config':
+ owner => 'root',
+ group => 'root',
+ mode => 444,
+ ensure => 'present',
+ content => template('gerrit/gerrit.config.erb'),
+ replace => 'true',
+ }
+
+ file { '/home/gerrit2/review_site/hooks/change-merged':
+ owner => 'root',
+ group => 'root',
+ mode => 555,
+ ensure => 'present',
+ source => 'puppet:///modules/gerrit/change-merged',
+ replace => 'true',
+ }
+
+ } else {
+ notice('Gerrit is not installed')
+ }
+
+}
diff --git a/modules/gerrit/templates/gerrit.config.erb b/modules/gerrit/templates/gerrit.config.erb
new file mode 100644
index 0000000000..afcca23c21
--- /dev/null
+++ b/modules/gerrit/templates/gerrit.config.erb
@@ -0,0 +1,32 @@
+# This file is managed by puppet.
+# https://github.com/openstack/openstack-ci-puppet
+
+[gerrit]
+ basePath = git
+ canonicalWebUrl = <%= canonicalweburl %>
+[database]
+ type = MYSQL
+ hostname = localhost
+ database = reviewdb
+ username = gerrit2
+[auth]
+ type = OPENID_SSO
+ openIdSsoUrl = <%= openidssourl %>
+[sendemail]
+ smtpServer = localhost
+[container]
+ user = gerrit2
+ javaHome = /usr/lib/jvm/java-6-openjdk/jre
+[sshd]
+ listenAddress = *:29418
+[httpd]
+ listenUrl = proxy-https://*:8081/
+[cache]
+ directory = cache
+[user]
+ email = <%= email %>
+<% commentlinks.each do |commentlink| -%>
+[commentlink "<%= commentlink['name'] %>"]
+ match = "<%= commentlink['match'] %>"
+ link = "<%= commentlink['link'] %>"
+<% end -%>
\ No newline at end of file