这可能是目前关于Gerrit最全的中文手册(Gerrit+Ldap+Gitlab)

前言:

公司原有面向开发的git仓库为Gitlab,也能满足开发人员的日常需求,然而gitlab是审核是基于代码合并时候的审核,即一个人可以在自己的分支push了几百次后,才合到上线发布分支。此时审核的leader需要审核相当多的代码,leader就此提出了能否有基于每一次push的审核,因此引入了gerrit。gerrit也是一套代码仓库,但是他在权限上更加细分,且拥有replication插件,即代码提交审核后自动同步到gitlab,理论上,gitlab只开pull不开push权限,杜绝开发直接上传到gitlab后,gerrit的代码与gitlab的代码是一致的。gerrit的精髓在于不允许直接将本地修改同步到远程仓库。开发必须先push到远程仓库的refs/for/*分支上,等待审核。 gerrit上也可以对比代码审核提交前后的内容状态。

安装:

安装java1.8 :

yum -y install java-1.8.0-openjdk

自己下载Gerrit war包(插件部分选择全部安装),然后初始化:

cd /opt/
mkdir gerrit
java -jar gerrit-3.1.4.war init -d review_site可以随便填,因为后续会改配置文件

编辑Gerrit配置文件

vi /opt/gerrit/review_site/etc/gerrit.config

[gerrit]
        basePath = GerritRepo
        canonicalWebUrl = http://192.168.1.1/
        serverId = b7bea659-70ed-44d6-a72d-85972f81b12a
[container]
        javaOptions = "-Dflogger.backend_factory=com.google.common.flogger.backend.log4j.Log4jBackendFactory#getInstance"
        javaOptions = "-Dflogger.logging_context=com.google.gerrit.server.logging.LoggingContext#getInstance"
        user = root
        javaHome = /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-0.el7_7.x86_64/jre
[index]
        type = lucene
[auth]
  type = ldap
  gitBasicAuth = true
        gitBasicAuthPolicy = HTTP

[ldap]
  server = ldap://192.168.1.1
  username = cn=readonly,dc=abc,dc=com
  accountBase = ou=tech,dc=abc,dc=com
  accountPattern = (&(objectClass=person)(uid=${username}))
  accountFullName = displayName
  accountEmailAddress = mail
        groupBase = ou=tech,dc=abc,dc=com

[receive]
        enableSignedPush = false
[sendemail]
        smtpServer = localhost
[sshd]
        listenAddress = *:29418
[httpd]
        listenUrl = http://127.0.0.1:8080/
[cache]
        directory = cache

重启gerrit

review_site/bin/gerrit.sh restart

安装nginx

yum -y install nginx

配置nginx

vi /etc/nginx/conf.d/gerrit.conf
server {
      listen 80;
      server_name 192.168.1.1;

      location ^~ / {
     #       auth_basic "Restricted";
     #       auth_basic_user_file /home/gerrit/review_site/etc/passwd;
        proxy_pass        http://127.0.0.1:8080;
        proxy_set_header  X-Forwarded-For $remote_addr;
        proxy_set_header  Host $host;
      }
    }

重启nginx

systemctl restart nginx

此时打开网页,正常情况下gerrit已经可以打开了,用刚刚ldap里的账户登陆(默认第一个登陆的用户即为管理员)

Gerrit与Gitlab Replication

所谓的 replication,是 Gerrit 的一个插件,它可以自动地将 Gerrit Code Review 对它所管理的 Git 仓库创建的任何 changes push 到另外一个系统里。Gerrit 本身提供了两大功能:一是 Code Review;二是 Git 仓库。

配置 replication 将代码同步到 GitLab 的方法如下。

在gerrit服务器上root用户生成ssh公司钥
ssh-keygen -t rsa

然后将 SSK Key 的公钥,即 ~/.ssh/id_rsa.pub 文件的内容,添加到 GitLab 中具有权限的用户的 SSH key 列表里。

 

接下来,创建 $site_path/etc/replication.config 文件(修改后,重启有效)。这是一个 Git风格的配置文件,它用来控制 replication 插件的设置。这个文件由一个或多个 remote 段组成,每个 remote 段都为一个或多个目标 URIs 提供公共配置设置。如:

[remote "git.abc.com/cuixiangbin"]
    projects = GitStatics
    url = [email protected]:cuixiangbin/${name}.git
    push = +refs/heads/*:refs/heads/*
    push = +refs/tags/*:refs/tags/*
    push = +refs/changes/*:refs/changes/*
    timtout = 30
    threads = 3

[remote "git.abc.com/yunwei"]
    projects = test234
    projects = test345
    url = [email protected]:yunwei/${name}.git
    push = +refs/heads/*:refs/heads/*
    push = +refs/tags/*:refs/tags/*
    push = +refs/changes/*:refs/changes/*
    timtout = 30
    threads = 3

如果 ~/.ssh/config 文件存在的话,Gerrit 将在启动的时读取并缓存它,并支持大部分 SSH 配置序啊想,比如:

Host git.abc.com
    User git
    Port 22
    IdentityFile ~/.ssh/id_rsa
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null
    PreferredAuthentications publickey

然后重新启动 Gerrit Server:

review_site/bin/gerrit.sh restart
replication 插件在执行过程中,产生的日志文件位于 ~/review_site/logs/replication_log。当 replication 失败时,可以从这个文件中找到一点线索。如果 这个日志中提供的信息不足,还可以修改 replication 的代码,让它输出更多日志,编译它的代码,然后将生成的 jar 文件,替换 ~/review_site/plugins/replication.jar,并重启 Gerrit Server。
这里以上述配置文件中的GitStaic为例,来给大家做一个同步示范。
首先在Gerrit上创建相同名字的项目GitStatic,并且到服务器上删除该仓库目录
rm -rf GitStatic.git
然后在该目录克隆下Gitlab上的GitStatic项目(不是代码,是bare,不知道的自行百度。。。)
git clone --bare [email protected]:cuixiangbin/GitStatics.git

重启gerrit之后,可以在gerrit系统的projects中看到该项目

至此,已实现gitlab与gerrit的集成,代码需要从gerrit上拉取,按照格式提交、审核通过后会同步到gitlab中(之间有几十秒时延,官方说是如果有多个项目改变,可以一次同步掉)

手动同步

ssh -p 29418 [email protected] gerrit --help
ssh -p 29418 [email protected] replication start --help
ssh -p 29418 [email protected] replication start --all

 

Gerrit审批

首先要用到Gerrit的审批功能,必须使用2版本以上的git,不然会报git的有些命令不支持。

Gerrit权限细分

System Groups

Gerrit系统自带下面的群组

  • Anonymous Users
  • Change Owner
  • Project Owners
  • Registered Users

Anonymous Users
所有用户都是匿名用户成员, 所有用户都能继承Anonymous Users所有访问权限.
当前只有Read access权限值得赋予给Anonymous Users群组, 因为其他权限都需要认证.


Project Owners
Project Owners的访问权限在Project范围内有效


Change Owner
Change Owner的访问权限在Change范围内有效

Registered Users
所有在页面上登录成功的用户都会自动注册为gerrit用户,属于Registered Users群组
Registered Users群组通常被赋予Code-Review -1..+1权限, 允许给需要审查代码投票, 但不会引起审查被批准和拒绝

Gerrit自带两个predefined groups:

  • Administrators
  • Non-Interactive Users

Administrators
Administrators是Gerrit root角色, 在Gerrit初始化时Administrate Server权限被赋予给这个Predefined Groups群组.
在Administrators组的成员可以管理所有项目, 但是不意味着任何其他权限. Administrators组不会自动获得代码审查批准和提交权限.

Non-Interactive Users
Interactive Users比如在web页面上审查代码, 在提交/获取代码的用户
Non-Interactive Users是可以通过Gerrit接口进行操作的组, 在Gerrit初始化时Priority BATCH和Stream Events权限被赋予给这个Predefined Groups组.
Non-Interactive Users和Interactive Users使用不同的线程池, 防止交互式用户抢占线程. 当系统资源紧张时确保了交互式的用户可以继续工作.

Project Access Control Lists

All Projects

All Projects项目中的访问权限会自动被其他项目继承, 只有Administrate Server capability能够编辑All-Projects权限.

Per-Project

先计算子项目的访问权限, 再计算All Projects的访问权限, 允许一些权限可以被覆盖.
对一个群组赋予DENY限制时, 通常只对READ权限有效.

Special and magic references

refs/heads/*refs/tags/*是Git常用的引用命名空间, 一个用来存储分支一个用来标签
refs/*命名空间下的引用都是有效的,Gerrit在refs/*有一些特殊用处的命名空间和引用

Special references

这些特殊的引用的内容由Gerrit生成或者包含重要的项目配置信息

refs/changes/*          #用于存储审查的补丁
#获取某个补丁集需要审查序号和补丁集序号
#'refs/changes/'<last two digits of change number>/ <change number>/ <patch set number>
refs/meta/config        #项目配置的分支
refs/meta/dashboards/*  #
refs/notes/review       #保存代码审查信息的分支

Magic references

refs/for/<branch ref>  #进行代码审查时需要提交代码到这个命名空间
refs/publish/*         #和refs/for/*命名空间作用一样
refs/drafts/*          #用于草案代码审查,和refs/for/*的区别在于只有部分人可见

添加新的补丁

#审查者对代码进行修改, 审查的代码是修改后的补丁
git fetch ssh://[email protected]:29418/gerrit_ci refs/changes/03/3/1
git branch fix_xxx FETCH_HEAD && git checkout fix_xxx
vi README
git add README
git commit --amend
git push origin HEAD:refs/for/master

查看远程引用

git ls-remote ssh://[email protected]:29418/gerrit_ci
61fd289472707d79f73289216a4c5f0ca4cee4e1    HEAD
eeaef9da4ea27d7c23bfb5f9a2ed1b5357ebbba8    refs/changes/01/1/1
5f8ed98b0f88787c22e705595e2818db62874f56    refs/changes/02/2/1
bfdb700f4aab3afc32ec79a29b0e25f8be758f8f    refs/changes/03/3/1
effa7b004eec0b85e722fe10be6468e4ed9b78d3    refs/changes/03/3/2
61fd289472707d79f73289216a4c5f0ca4cee4e1    refs/heads/master
9f282c08d5108c6817dd1504e8bec0e94ba59d47    refs/meta/config
405030285eed7406b1ac7cfa6a5211331165b8e2    refs/notes/review

修改项目配置文件

git clone ssh://[email protected]:29418/All-Projects && scp -p -P 29418 [email protected]:hooks/commit-msg All-Projects/.git/hooks/

#refs/meta/config 是All-Projects的引用
git fetch origin refs/meta/config:refs/remotes/origin/meta/config
git checkout meta/config
#现在目录下有groups  project.config两个文件
#提交修改
git add .
git commit -m "modify config"
git push origin meta/config:meta/config

Access Categories

Abandon

代码审查时允许用户丢弃这个审查。如果对changepush权限,同时具有push,abandon,restore权限

Create Reference
用户可以创建新的references, branches or tags, 创建时引用必须不存在,不能删除已经创建的引用
如果仅仅推送标签,给refs/tags/*赋予Create Reference权限
这个权限通常用在创建某个命名空间下的分支, 如:某个部门自由创建分支权限refs/heads/hello/*
给某用户自由创建分支权限, 给refs/heads/sandbox/${username}/*赋予Create Reference权限
如果你这样赋予Create Reference权限,记得同时赋予push force权限, 这样拥有清理

Forge Author && Forge Committer && Forge Server

查看提交中AuthorCommitter

git log --format=full
commit 2dfae738781a3ba641ee06c913fd51162335a941
Author: admin <[email protected]>
Commit: gerrit_test <[email protected]>

    admin gerrit_test

    Change-Id: I0830cf061306101e977f9adf55270c9b3a3f59c4

Author一般表示谁创建了这个提交,也可以用git commit –amend –reset-author等命令修改
Committer一般表示谁修改了这个提交,在使用git commit –amend等命令时修改
通常Gerrit需要在Author和提交的Committer认证信息中至少一个,与uploading user注册过的邮箱地址匹配,Forge Author和Forge Committer允许用户绕过提交时的身份验证
Forge Author允许提交中Author信息不经过验证, 这个权限在下面场景非常有效,通过邮件接收第三方补丁,cherry-pick其他人的分支提交,审查合并前修改其他人的一些次要问题.
默认在All-Projects赋予Registered Users组Forge Author权限.
Forge Committer允许提交中Committer信息不经过验证和不验证匿名标签对象,通常在需要其他服务器自动提交时有用
Forge Server允许在提交中Committer信息使用Server的用户名和邮箱. 这个权限在强制推送git filter-branch修改过信息的提交和由这个Gerrit Code Review server创建的合并提交时有用.
在etc/gerrit.config可以配置Server的用户名和邮箱,user.name默认值Gerrit Code Review, user.email默认值在启动时生成[email protected]

Owner
允许修改项目以下配置:

改变项目描述
通过SSH创建新的分支
通过Web界面创建和删除分支
赋予和撤销任何访问权限,包括Owner权限
子命名空间的所有权可以通过命名空间格式来委派. 要委派以qa/开始的所有分支权限给QA群组,给refs/heads/qa/*添加Owner权限。 QA小组的成员可以进一步细分访问权限,但只能对refs/heads/qa/开始的分支有效.

Push

这类分支控制用户如何上传提交到Gerrit. 根据命名空间赋予的Push权限, 可以允许绕过代码审查直接推送到分支, 也可以允许创建新的change进行代码审查.

Direct Push

Direct Push权限下,任何已经存在的分支都接收fast-forward提交,创建新的分支需要Create Reference权限. 删除已经存在的分支会被拒绝,因为在这个最安全的模式下, 提交不会被丢弃.

Force选项
允许分支被删除. 由于force push实际上删除分支后会创建这个分支,但是这是个原子操作并且会被记录,也允许force push更新分支. 带有force选项会导致项目历史中的提交被丢弃.
force选项对只想使用Gerrit访问权限功能而不需要代码审查的项目有效, 对于需要进行代码审查的项目不应该分配这个权限.

Upload To Code Review

Upload To Code Review权限授权在refs/for/refs/heads/BRANCH命名空间上,允许用户上传non-merge提交到refs/for/BRANCH命名空间,创建新的change进行代码审查.
用户在自己环境下提交代码需要clone/fetch项目代码,所以必须赋予Read权限
对于开源公开的Gerrit安装方式,All-Projects中refs/for/refs/heads/*通常给Registered Users赋予Read和Push权限. 很多私有安装, 通常refs/for/refs/heads/*通常给all users简单的赋予Read和Push权限.
force选项赋予refs/for/refs/heads/*命名空间没有作用.

Push Merge Commits

Push Merge Commits权限允许用户上传merge commits.这是Push附加的访问权限,所以只赋予Push Merge Commits权限是不够的. 一些项目希望只能由Gerrit自动合并提交, 可以通过只赋予Push权限而不赋予Push Merge Commit权限.
赋予Push Merge Commit权限通常必须以refs/for/为前缀,例如refs/for/refs/heads/BRANCH. refs/heads/BRANCH作为补充, 赋予Read权限后允许直接推送non-merge提交,赋予Push Merge Commit权限后也允许直接提交一个merge提交.

Push Annotated Tag

允许推送带注释的标签到远程仓库, 标签必须带有注释.

#创建带注释的标签
git tag -a <tagname> -m <comment>
#提交标签到远程仓库
git push origin --tags
#获取标签
git fetch --tags

标签的email一定会与提交者的邮箱进行验证,如果推送其他人的标签需要同时赋予Push Annotated TagForge Committer Identity权限.

git show v1.0
tag v1.0
Tagger: username <email>

如果需要推送轻量级标签(不带注释), 给refs/tags/*命名空间赋予Create Reference权限, 轻量级标签就像Git中的分支一样.
如果需要删除或者重写标签, 给refs/tags/*命名空间赋予带force选项的Push权限,删除标签需要和删除分支一样的权限.

Push Signed Tag

允许推送PGP签证的标签到远程仓库

git tag -u "gpg-key-id" -m "tag comment" <tagname>

Read

Read权限控制查看项目的change,comment,code diff和通过SSH或者HTTP协议访问仓库的权限
这个权限非常特殊, 先计算项目中的Read权限, 再计算all-projects的Read权限.
如果项目中赋予DENY Read权限,all-projects项目不管是否赋予ALLOW READ都将无效.这个权限对于隐藏一些项目非常有用.

Rebase

允许用户在web页面上进行rebase changeschange作者和提交者可以通过页面进行rebase changes(尽管没有赋予Rebase权限)

Remove Reviewer

允许用户从审查者列表中移除其他用户.
Change owners能够移除那些审查分数为0或者负数的审查者.(尽管没有赋予Remove Reviewer权限)
Project owners和site administrators能够移除任何审查者(尽管没有赋予Remove Reviewer权限)
其他用户只能将他们自己从审查者列表中移除.

Review Labels

在项目中配置label My-Name,label My-Name和定义好的范围分数相关联. 同时也关联labelAs-My-Name权限, 可以允许编辑用户定义的label.
Gerrit带有配置好的Code-Review标签

[access "refs/heads/*"]
    label-Code-Review = -2..+2 group Administrators
    label-Code-Review = -2..+2 group Project Owners
    label-Code-Review = -1..+1 group Registered Users
[label "Code-Review"]
    function = MaxWithBlock
    defaultValue = 0
    copyMinScore = true
    copyAllScoresOnTrivialRebase = true
    value = -2 This shall not be merged
    value = -1 I would prefer this is not merged as is
    value =  0 No score
    value = +1 Looks good to me, but someone else must approve
    value = +2 Looks good to me, approved

Submit

允许用户提交审查通过的提交. 提交审查代码后会合并到对应的分支上.

Code-Review标签+2是通过,-2是否定, -1~+1只是代表意见并不会影响投票, 审查被通过至少需要一个+2投票并且没有-2投票. 两个+1并不会等于+2

[access "refs/heads/*"]
    submit = group Administrators
    submit = group Project Owners

View Drafts

允许用户查看其他人提交的draft changes.
draft changes作者和添加为审查者都能看见draft changes(尽管没有赋予View Drafts权限)

Publish Drafts
允许用户公开其他人提交的draft changes.
draft changes作者可以公开draft changes(尽管没有赋予Publish Drafts权限)

Delete Drafts
允许用户删除其他人提交的draft changes.
draft changes作者可以删除draft changes(尽管没有赋予Delete Drafts权限)

Edit Topic Name
允许修改change的主题topic
change owner, branch owners, project owners, and site administrators可以修改主题(尽管没有赋予Edit Topic Name权限)

Enforcing site wide access policies
通过赋予一个群组Owner访问权限在refs/*命名空间, Gerrit管理员可以委派这个项目的访问控制权限给这个群组.
如果需要没有一个人能更新或者删除标签, 连项目owners都没有权限. ALLOW和DENY规则并不能达到这样的目的, 因为项目owners可以赋予任何他们自己想要的访问权限. 覆盖任何从All-Projects或者其他父项目继承的权限是非常有效的方法.
在父项目中BLOCK权限, 使得就算是子项目owners也不能设置block权限为ALLOW. 尽管这样, 也应该保留owners所有non-blocked权限.

Gerrit管理员能够集中精力管理site wide策略并且提供有意义的默认访问权限.
在不违反site wide策略的情况下, 项目owners可以管理他们自己项目的访问权限.
‘BLOCK’ access rule
BLOCK规则是全局范围的权限. 子项目不能重载继承的BLOCK规则. 从父项目链表中搜索BLOCK规则, 忽略在访问区域中的独占(Exclusive)标志.
push权限赋予BLOCK规则, push和force push等推送都将被阻塞. force push权限赋予BLOCK规则只有force push被阻塞, 但是如果push权限具有ALLOW规则的话可以进行non-forced提交.
BLOCK也可以赋予label投票范围. 下面的配置可以阻塞group X投+2和-2票,仍然可以投-1 ~ +1的票.

[access "refs/heads/*"]
  label-Code-Review = block -2..+2 group X

在这个阻塞规则min..max范围的目的是: 阻塞-INFINITE..min和max..INFINITE投票,也意味着-1..+1投票范围不受阻塞影响.

BLOCK’ and ‘ALLOW’ rules in the same access section
当相同访问区域同时包含BLOCK和ALLOW规则, ALLOW规则会重载BLOCK规则.

[access "refs/heads/*"]
  push = block group X
  push = group Y

如果群组X和群组Y都包含了同一个用户, 这个用户依然能够push到refs/heads/*命名空间.
在同一个项目的同一个访问区域,ALLOW规则才会重载BLOCK规则.在同一个项目不同访问区域和子项目的同一个访问区域, ALLOW规则不会重载BLOCK规则.

BLOCK规则示例
确保没有人能够更新或者删除tag
在All-Projects中阻塞Anonymous Users组的push权限

[access "refs/tags/*"]
  push = block group Anonymous Users

由于所有人都是Anonymous Users组成员, 所以可以阻塞所有人.
可能项目owner需要创建tag权限

[access "refs/tags/*"]
    push = block group Anonymous Users
    pushTag = group Project Owners
    pushSignedTag = group Project Owners

某个命名空间只让一个特殊的群组投票

假设提交到发布分支Release-Process需要更为严格的过程, 假设我们需要确信只有Release Engineers群组可以投票,就算是项目owner权限也不可以投票. 在All-Projects我们定义下面的规则.

[access "refs/heads/stable*"]
    label-Release-Process = block -1..+1 group Anonymous Users
    label-Release-Process = -1..+1 group Release Engineers

Global Capabilities

Access Database
允许用户通过gsql命令访问数据库, 以及包含代码审查信息的分支refs/notes/review

Administrate Server
影响Gerrit中owner和administrator角色. 赋予administrateServer能力能够赋予任何群组访问权限.

Priority
Gerrit中有两类线程池用来给INTERACTIVE Users和Non-Interactive Users使用,防止抢占线程.
允许其他用户使用Non-Interactive Users的保留线程池.

默认配置, 用户默认使用INTERACTIVE线程池
BATCH, 赋予这个群组的用户使用独立的Non-Interactive线程池
INTERACTIVE, 除非用户赋予了BATCH选项,否则使用INTERACTIVE线程池
Stream Events 允许执行Gerrit触发的事件流.
获取All-Projects中refs/meta/config分支并修改权限配置

git clone ssh://[email protected]:29418/All-Projects && scp -p -P 29418 [email protected]:hooks/commit-msg All-Projects/.git/hooks/

#refs/meta/config 是All-Projects的引用
git fetch origin refs/meta/config:refs/remotes/origin/meta/config
git checkout meta/config
#现在目录下有groups  project.config两个文件
#groups文件包含project.config中需要的用户组和对应的UUID

#提交修改
git add .
git commit -m "modify config"
git push origin meta/config:meta/config

在公司文档看到大神写的很不错的一小段话

code review的目的是团队成员在一起共同学习,而不是相互”挑错”.将code review称为代码回顾好一些, 如果大家放弃”挑错”来共同学习,那么代码回顾中学习什么呢?
代码回顾的学习重点是团队成员共同识别模式,这里的模式是指程序员编写代码的习惯,包括”好模式”和”反模式”. 像富有表达力的命名, 单一职责的方法, 良好的格式缩进等,都是”好模式”. 团队成员通过阅读最近编写的测试代码和生产代码来识别”好模式”和”反模式”.既是团队成员之间相互学习的过程, 也是团队整体达成整洁代码共识的过程.

 

 

补充:

一般情况下在Gerrit权限设置里有三种类型的分支:

refs/* : 这是管理员才有的权限, 表示当前项目下的所有分支, 拥有此权限可以随意push到任何远端分支

refs/heads/* : 这是不需要经过code review的分支, 与 refs/* 同样权限

refs/for/* : 这是需要经过code review的分支, 提交到此分支上的代码需要经过code review, 通过后才能合并到正式分支上.

我们在提交代码审核的时候需要将代码提交到gerrit为我们提供的引用分支上, 比如说: 我在dev分支上操作, 本来要push的命令需要由 git push origin dev 改为 git push origin HEAD:/refs/for/dev.

如果嫌每次写这么长不方便的话, 可以在项目下做如下配置, git config remote.origin.push ‘refs/heads/*:refs/for/*’, 这样每次提交的时候就会自动提交到引用分支上了.

Gerrit删除Repo

ssh -p 29418 [email protected] delete-project delete --yes-really-delete ops --force

不重启Gerrit重新加载replication

ssh -p 29418 [email protected] gerrit plugin reload replication

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This blog is kept spam free by WP-SpamFree.