gerrit安装部署文档

摘要

gerrit安装过程还是很简单的,虽然个人感觉web界面以及操作体验非常不爽,而且国内也欠缺靠谱的使用文档,但是gerrit的review、代码审核功能还是有很多团队需要的,因此安装配置、以及后续的管理还是需要的。

由于本人的工作接触到了gerrit,所以才有了这篇文章。

官方文档
cicd持续集成文档

本文部分内容取自网络,由本人整理并通过真实安装过程记录撰写而成

简介

gerrit的工作模式是所有真正的merge由gerrit负责,我们的提交只是提交给了gerrit,gerrit会通知项目的负责人来审核 代码,同时也会调用一些自动化测试构建工具来检查代码是否符合要求,只有都通过后才会的合并进主干代码。所以可以把gerrit看成是代码和提交者之间的一道门。

环境搭建

Jdk安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 卸载yum安装的java
yum remove java* -y
wget http://download.oracle.com/otn-pub/java/jdk/8u92-b14/jdk-8u92-linux-x64.tar.gz
mkdir /usr/local/product
tar xvf jdk-8u92-linux-x64.tar.gz
mv jdk1.8.0_92 /usr/local/product
ln -s /usr/local/product/jdk1.8.0_92 /usr/local/jdk
echo -e """
export JAVA_HOME="/usr/local/jdk"
export JRE_HOME="\$JAVA_HOME/jre"
export PATH="\$PATH:\$JAVA_HOME/bin"
export CLASSPATH=./:\$JAVA_HOME/lib:\$JRE_HOME/lib
""" >> /etc/profile
source /etc/profile
java -version
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

mysql安装

生产环境尽量还是使用源码安装的新版本mysql,本文为了方便采取yum安装的方式

1
2
3
4
5
6
7
8
9
10
yum install -y mysql mysql-devel mysql-server
/etc/init.d/mysqld start
chkconfig mysqld on
mysql
> CREATE DATABASE reviewdb;
> ALTER DATABASE reviewdb charset=latin1;
> CREATE USER 'gerrit2'@'localhost' IDENTIFIED BY 'gerrit2';
> GRANT ALL ON reviewdb.* TO 'gerrit2'@'localhost';
> FLUSH PRIVILEGES;

mysql我使用编译安装的5.5版本gerrit会报错,使用yum安装的5.1没问题,没有深究原因

gerrit安装

添加gerrit用户

1
adduser gerrit2

我使用gerrit用户安装一直不成功,使用gerrit2用户没问题

安装git

1
yum install -y git

安装gerrit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 需要用到的包
gerrit-2.13.1.war
mysql-connector-java-5.1.21.jar
bcpkix-jdk15on-152.jar
bcprov-jdk15on-152.jar
# 下面三个是用到的插件包,安装过程会自动下载,如果网络不好的话失败几率很大,所以可以事先下好,安装的时候直接放到lib目录里面可跳过自动下载的过程,以下为下载地址
https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.21/mysql-connector-java-5.1.21.jar
https://repo1.maven.org/maven2/org/bouncycastle/bcpkix-jdk15on/1.52/bcpkix-jdk15on-1.52.jar
https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.52/bcprov-jdk15on-1.52.jar
su - gerrit2
java -jar gerrit-2.13.1.war init -d /home/gerrit2/review_site/

安装过程

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
Using secure store: com.google.gerrit.server.securestore.DefaultSecureStore
[2017-06-15 15:22:17,223] [main] INFO com.google.gerrit.server.config.GerritServerConfigProvider : No /home/gerrit2/review_site/etc/gerrit.config; assuming defaults
*** Gerrit Code Review 2.13.1
***
Create '/home/gerrit2/review_site' [Y/n]?
##### 可以另起一个终端 cp *.jar review_site/lib/
*** Git Repositories
***
Location of Git repositories [git]:
##### 配置数据库
*** SQL Database
***
Database server type [h2]: mysql
Gerrit Code Review is not shipped with MySQL Connector/J 5.1.21
** This library is required for your configuration. **
Download and install it now [Y/n]?
Downloading https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.21/mysql-connector-java-5.1.21.jar ... OK
Checksum mysql-connector-java-5.1.21.jar OK
Server hostname [localhost]:
Server port [(mysql default)]:
Database name [reviewdb]:
Database username [gerrit2]:
gerrit2's password : gerrit2
confirm password : gerrit2
*** User Authentication
***
Authentication method [OPENID/?]: HTTP
Get username from custom HTTP header [y/N]?
SSO logout URL :
Enable signed push support [y/N]?
*** Review Labels
***
Install Verified label [y/N]?
##### 配置发件邮箱
*** Email Delivery
***
SMTP server hostname [localhost]: smtp.163.com
SMTP server port [(default)]: 25
SMTP encryption [NONE/?]:
SMTP username [gerrit2]: emo_ooppwwqq0@163.com
emo_ooppwwqq0@163.com's password :
confirm password :
*** Container Process
***
Run as [gerrit2]:
Java runtime [/usr/local/product/jdk1.8.0_92/jre]:
Copy gerrit-2.13.1.war to /home/gerrit2/review_site/bin/gerrit.war [Y/n]?
Copying gerrit-2.13.1.war to /home/gerrit2/review_site/bin/gerrit.war
*** SSH Daemon
***
Listen on address [*]:
Listen on port [29418]:
Gerrit Code Review is not shipped with Bouncy Castle Crypto SSL v152
If available, Gerrit can take advantage of features
in the library, but will also function without it.
Download and install it now [Y/n]?
Downloading https://repo1.maven.org/maven2/org/bouncycastle/bcpkix-jdk15on/1.52/bcpkix-jdk15on-1.52.jar ... OK
Checksum bcpkix-jdk15on-1.52.jar OK
Gerrit Code Review is not shipped with Bouncy Castle Crypto Provider v152
** This library is required by Bouncy Castle Crypto SSL v152. **
Download and install it now [Y/n]?
Downloading https://repo1.maven.org/maven2/org/bouncycastle/bcprov-jdk15on/1.52/bcprov-jdk15on-1.52.jar ... OK
Checksum bcprov-jdk15on-1.52.jar OK
Generating SSH host key ... rsa... dsa... done
*** HTTP Daemon
***
Behind reverse proxy [y/N]? y
Proxy uses SSL (https://) [y/N]?
Subdirectory on proxy server [/]: /gerrit
Listen on address [*]:
Listen on port [8081]:
Canonical URL [http://localhost/gerrit]: http://10.0.0.136:8003/gerrit
*** Plugins
***
Installing plugins.
Install plugin commit-message-length-validator version v2.13.1 [y/N]?
Install plugin download-commands version v2.13.1 [y/N]?
Install plugin hooks version v2.13.1 [y/N]? y
Installed hooks v2.13.1
Install plugin replication version v2.13.1 [y/N]?
Install plugin reviewnotes version v2.13.1 [y/N]?
Install plugin singleusergroup version v2.13.1 [y/N]?
Initializing plugins.
No plugins found with init steps.
Initialized /home/gerrit2/review_site
Executing /home/gerrit2/review_site/bin/gerrit.sh start
Starting Gerrit Code Review: OK
Waiting for server on 127.0.0.1:8081 ... OK
Opening http://127.0.0.1:8081/gerrit/#/admin/projects/ ...FAILED
Open Gerrit with a JavaScript capable browser:
http://127.0.0.1:8081/gerrit/#/admin/projects/

最后能看到gerrit启动了才算正常,如果没有启动就是失败了

配置gerrit

gerrit配置文件

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
cat review_site/etc/gerrit.config
#####
[gerrit]
basePath = git
serverId = b71016d0-9411-42e0-8082-ab1decc9f5fa
canonicalWebUrl = http://10.0.0.136:8003/gerrit
[database]
type = mysql
hostname = localhost
database = reviewdb
username = gerrit2
[auth]
type = HTTP
[receive]
enableSignedPush = false
[sendemail]
smtpServer = smtp.163.com
smtpServerPort = 25
smtpUser = emo_ooppwwqq0@163.com
# 需要加一个from配置 否则无法发送邮件,会报500
from = CodeReview<emo_ooppwwqq0@163.com>
[container]
user = gerrit2
javaHome = /usr/local/product/jdk1.8.0_92/jre
[sshd]
listenAddress = *:29418
[httpd]
listenUrl = proxy-http://*:8081/gerrit
[cache]
directory = cache

安装配置nginx

这里nginx也是为了方便直接yum安装,生产环境建议编译安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
yum install nginx -y
useradd www
cat nginx.conf
user www;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
include vhosts/*.conf;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cat vhost/gerrit.conf
server {
listen 8003;
server_name www.a.com;
auth_basic "Gerrit Code Review";
auth_basic_user_file /etc/nginx/gerrit2.passwd;
access_log off;
error_log off;
location /gerrit/ {
proxy_pass http://127.0.0.1:8081;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $host;
}
}
/etc/init.d/nginx restart

创建密码验证文件

1
2
3
4
yum install httpd -y
htpasswd -c /etc/nginx/gerrit2.passwd gerrit2
htpasswd -b 文件 用户名 密码 ---添加
htpasswd -D 文件 用户名 --删除

访问测试

1
http://127.0.0.1:8003/gerrit

后续配置

gitweb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
yum install gitweb -y
[gitweb]
type = gitweb
cgi = /var/www/git/gitweb.cgi
```
## 权限设置
### 新增两个用户
``` bash
htpasswd -b /etc/nginx/gerrit2.passwd test3 123456
htpasswd -b /etc/nginx/gerrit2.passwd test2 123456
# 创建用户之后用新用户登录gerrit做激活用户配置

创建用户组

用户组添加用户

创建项目

创建项目分支

配置项目权限

开发者配置

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
git clone ssh://test2@10.0.0.136:29418/test && scp -p -P 29418 test2@10.0.0.136:hooks/commit-msg test/.git/hooks/
git config --global user.email "xxx@qq.com"
git config --global user.name "test2"
# 配置推送分支以及配置默认审核人
# .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = ssh://test2@10.0.0.136:29418/mypro
[branch "master"]
remote = origin
merge = refs/heads/master
[branch "develop"]
remote = origin
merge = refs/heads/develop
[remote "dev"]
url = ssh://test2@10.0.0.136:29418/mypro
push = HEAD:refs/for/develop%r=test3
[branch "hotfix_v4.6"]
remote = origin
merge = refs/heads/hotfix_v4.6
[remote "hot"]
url = ssh://test2@10.0.0.136:29418/mypro
push = HEAD:refs/for/hotfix_v4.6%r=test3

gerrit-hooks配置

gerrit在git的hooks基础上做了一些个性化的修改,并且新增了一些属于自己的hooks文件,想要使用hooks需要在安装gerrit的时候选则安装hooks;

并且hooks需要放到$site_dir/hooks目录下,针对本文就是(/home/gerrit2/review_site/hooks);

如果成功安装了hooks登录管理员账号是可以看到的,如果没安装,建议重装gerrit,因为我也不知道怎么单独安装hooks,建议自行尝试;

本节内容暂时只讲解gerrit众多hooks中的一种,因为我暂时只用了这一种;

其他和git相同的hooks请看另一篇文章git-hooks(钩子):自定义你的工作流

change-merged

这个hooks的功能是开发者push代码之后,需要审核人进行审核,当审核人审核通过之后,也就是submit之后,就会触发的一个hooks,一般用来做一些发邮件的通知工作,而本文是为了用来将指定分支的代码合并到另一个分支(后续可能会更新一个纯python的版本)。

1
2
3
4
5
6
7
8
9
# pwd
/home/gerrit2/review_site/hooks
# tree
├── change-merged > hooks脚本
├── change-merged.d > 相关配置文件
│   ├── config.env > 主配置文件,用来定义一些共有变量
│   └── mypro > 需要执行hooks的项目的配置文件目录
│   └── config.env > 项目配置文件,定义一些个性化的配置
└── smail.py > 发送邮件的python脚本

change-merged

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
# change-merged
#!/bin/bash
# Gerrit post-merge hook
## LOG OUTPUT
unset GIT_DIR
DATETIME=$(date +%F)
TIME=$(date "+%Y-%m-%d %H:%M:%S")
LOGNAME="cherry"
LOGDIR="/data/cherry"
LOGFILE="${LOGDIR}/${LOGNAME}_${DATETIME}.log"
exec 1>>${LOGFILE}
exec 2>&1
## LOG OUTPUT
function myecho() {
echo "$TIME" "####################"
echo "$TIME" "$*"
}
function maincfg() {
CFG=${BASH_SOURCE[0]%/*}/change-merged.d/config.env
if [ ! -f "${CFG}" ] ; then
myecho "Cannot find ${CFG} !."
exit 1
fi
. ${CFG}
if [ $? -ne 0 ]; then
myecho "load ${CFG} fail!"
fi
}
function msecho() {
echo ">>>>>>>>>>>>>>>>>>>>>>" >> ${tCache}
echo """Project : ${PROJECT} (${BRANCH} --> ${Master})
Author : ${OWMAIL}
Reviewer : ${SUBMITTER}
CHANGE : ${CHANGEID}
Commit_id : ${COMMIT}
Fatal : $@""" >> ${tCache}
echo ">>>>>>>>>>>>>>>>>>>>>>" >> ${tCache}
}
function cmd_line() {
myecho $@
while [ $# -gt 0 ]
do
case "$1" in
(--change) CHANGEID="$2"; shift ;;
(--change-url) CHANGEURL="$2"; shift ;;
(--change-owner) OWNER="$3";OWMAIL="$(echo $3|sed 's/[()]//g')"; shift;shift ;;
(--project) PROJECT="$2"; shift ;;
(--branch) BRANCH="$2"; shift ;;
(--topic) myecho "topic skip" ;;
(--submitter) SUBMITTER="$(echo $3|sed 's/[()]//g')"; shift;shift ;;
(--commit) COMMIT="$2"; shift ;;
(--newrev) NEWREV="$2"; shift ;;
(*) myecho $@;myecho "I don't understand the option '$1'."; ;;
esac
shift
done
}
function project_cfg() {
PCFG=${BASH_SOURCE[0]%/*}/change-merged.d/${PROJECT}/config.env
if [ ! -f "${PCFG}" ] ; then
myecho "Cannot find ${PCFG} !."
exit 1
fi
myecho "load ${PCFG}"
. ${PCFG}
}
function check_clone() {
GIT_URL="ssh://${GIT_ADMIN}@${GIT_SERVER}:${GIT_PORT}/${PROJECT}"
MSG_URL="${GIT_ADMIN}@${GIT_SERVER}:hooks/commit-msg"
if [ ! -d ${Check_dir}/${PROJECT} ]; then
cd ${Check_dir}
git clone ${GIT_URL} && scp -p -P ${GIT_PORT} ${MSG_URL} ${PROJECT}/.git/hooks/
check_clone
else
cd ${Check_dir}/${PROJECT}
fi
}
function fail_clear() {
[ ! -d ${TRASH} ] && mkdir -p ${TRASH}
if [ -d ${Check_dir}/${PROJECT} ]; then
mv ${Check_dir}/${PROJECT} ${TRASH}/${PROJECT}_${STIME}
fi
}
function cherry() {
if [ -z ${To} ]; then
To="${OWMAIL},${SUBMITTER}"
else
tolist=$(echo ${To}|awk -F',' '{for(i=1;i<=NF;i++){print $i}}')
if [[ "${tolist[@]/${OWMAIL}/}" == "${tolist[@]//}" ]]; then
To="${To},${OWMAIL}"
fi
if [[ "${tolist[@]/${SUBMITTER}/}" == "${tolist[@]//}" ]]; then
To="${To},${SUBMITTER}"
fi
fi
check_clone
git checkout ${Master}
git pull
git cherry-pick ${COMMIT} >> ${tCache} 2>&1
if [ $? -eq 0 ]; then
msecho "cherry-pick success!"
#git config remote.origin.push refs/heads/${Master}:refs/for/${Master}
git show >> ${tCache} 2>&1
echo ">>>>>>>>>>>>>>>>>>>>>>" >> ${tCache}
git push >> ${tCache} 2>&1
if [ $? -eq 0 ]; then
msecho "push success!"
else
msecho "push faild!"
fail_clear
fi
python ${Message} ${Smtpserver} ${From} ${Password} ${Head} ${To} "cherry-pick<"${PROJECT}">success" ${tCache}
else
git status
msecho "cherry-pick failed!"
git status >> ${tCache} 2>&1
fail_clear
python ${Message} ${Smtpserver} ${From} ${Password} ${Head} ${To} "cherry-pick<"${PROJECT}">failed" ${tCache}
fi
}
function get_choose() {
myecho ${PROJECT} ${BRANCH} ${COMMIT} ${OWMAIL} ${SUBMITTER}
if [ ${Choose} == true ]; then
if [ ! -z ${BRANCH} ] && [ ${BRANCH} == ${Merge_branch} ]; then
cherry
else
myecho "not branch" ${BRANCH}
exit 1
fi
else
ch=$(awk "BEGIN {print index(${BRANCH},${Merge_head})}")
if [ ! -z ${BRANCH} ] && [ ${ch} -eq 1 ]; then
cherry
else
myecho "not branch" ${BRANCH}
exit 1
fi
fi
}
main() {
myecho "load cfg"
maincfg
myecho "get args"
cmd_line $@
myecho "load project_cfg"
project_cfg
myecho "begin to cherry-pick"
get_choose
}
main $@

change-merged.d/config.env

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# change-merged.d/config.env
#!/bin/bash
# FOR cache var
STIME=$(date "+%Y%m%d%H%M%S")
TRASH="/data/cherry/trash"
tCache="${TRASH}/text_${STIME}"
# For git var
GIT_SERVER="10.0.0.136"
GIT_PORT="29418"
GIT_ADMIN="gerrit2"
# For mail var
Smtpserver="smtp.163.com"
From="emo_ooppwwqq0@163.com"
Password="xxx"
Head="codemerge"
Message=$(dirname ${BASH_SOURCE[0]%/*})/smail.py

smail.py

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
# smail.py
#!/usr/bin/env python
## -*- coding: utf-8 -*-
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.header import Header
from sys import argv
print argv
if len(argv) > 3:
sc, Smtpserver, From, Password, Head, To, Subject, text = argv
def sendMail(sub, msg):
smtp = smtplib.SMTP()
msgRoot = MIMEMultipart('related')
msgRoot['Subject'] = Header(sub,'utf-8')
msgRoot['From'] = r"%s <%s>" % (Header(Head,"utf-8"),From)
tolist=To.split(",")
msgRoot['To'] = ";".join(tolist)
msgText = MIMEText('%s'%msg,'html','utf-8')
msgRoot.attach(msgText)
fullText = msgRoot.as_string()
while 1:
try:
smtp.sendmail(From, tolist, fullText)
break
except:
try:
smtp.connect(Smtpserver,"25")
smtp.login(From, Password)
except:
print "failed to login to smtp server"
def main():
Text = ""
with open(text) as msg:
for line in msg:
lines = "<pre><p>%s</p></pre>" % line.strip()
Text += lines
sendMail(Subject, Text)
if __name__ == "__main__":
main()

change-merged.d/mypro/config.env

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# change-merged.d/mypro/config.env
#!/bin/bash
Master="develop"
Merge_branch="hotfix_v4.6"
Merge_head="hotfix_"
# true to exact match
# false to fuzzy matching
# eg. true : hotfix_v4.6
# eg. flase : hotfix_
Choose=true
Check_dir="/data/cherry"
To="xxx@xxx.com"