【Gerrit】Gerrit與Jenkins/Hudson CI服務器搭建

配置Git

不少系統(例如Linux)已經默認提供了Git,在Git主頁也能夠找到安裝程序。對於Windows用戶,最好的選擇是MsysGit。請注意,若是你安裝了Apple Developer Tools (for Xcode 4),那麼其中已經自帶Git二進制包了。若是遇到了問題,help.github.com中能夠找到不少很是出色的指南。html

由於全部的Git提交都帶有做者和電子郵件地址,若是你尚未設置過這些內容,請執行如下命令進行配置:java

$ git config --global user.name "Alex Blewitt"
$ git config --global user.email Alex.Blewitt@example.com

最好有一個Git代碼庫。Gerrit在初始化階段會自動掃描Git代碼庫,這樣作比在後期配置代碼庫容易一些,所以最好在初始化Gerrit前準備好Git代碼庫。git

若是尚未Git代碼庫,能夠建立一個:github

git init --bare /path/to/gits/example.git

Gerrit

能夠從http://code.google.com/p/gerrit/下載到Gerrit,那是一個WAR文件。Gerrit有很好的文檔(目前的最新文檔是2.2.1,但也可用於2.1.7)和安裝指南sql

Gerrit在運行時須要用到數據庫(用於存儲代碼審查的信息)。目前支持的數據庫包括H二、PostgreSQL和MySQL。在沒有進行額外配置的狀況下,它默認使用H2。shell

請注意,Gerrit 2.2.x正把項目配置、權限和其餘元數據移到Git存儲中,這樣就能夠經過Git進行訪問和版本控制。在2.2.x中,這個轉變會慢慢擴展到其餘類型的元數據上,包含代碼評審內容。詳見2.2.0版本的發佈說明數據庫

要初始化Gerrit,運行java -jar gerrit.war init -d /path/to/location會在指定路徑上安裝Gerrit運行時。xcode

若是是在交互終端中運行的,安裝程序會提幾個問題,例如:瀏覽器

  • Git代碼庫的位置 [git]
  • 導入現有代碼庫 [Y/n]
  • 數據庫服務器類型 [H2/?]
  • 身份驗證方法 [OPENID/?]
  • SMTP服務器主機名 [localhost]
  • SMTP服務器端口 [(default)]
  • SMTP加密 [NONE/?]
  • SMTP用戶名
  • 以何種身份運行 [you]
  • Java運行時 [/path/to/jvm]
  • 將gerrit.war複製到/path/to/location/bin/gerrit.war [Y/n]
  • 監聽地址 [*]
  • 監聽端口 [29418]
  • 下載並安裝Bouncy Castle [Y/n]
  • 位於HTTP反向代理以後 [y/N]
  • 使用SSL [y/N]
  • 監聽地址 [*]
  • 監聽端口 [8080]

其中大部分能夠保留默認值,可是有幾個須要重點關注。服務器

  • Git代碼庫的位置要指向正確的位置。默認值是位於安裝目錄中的'git'目錄,也能夠是其餘不一樣位置(例如/var/gits等等)。應該先配置好這個路徑,由於在Gerrit啓動時它會先掃描該目錄來添加新項目。
  • 監聽地址對有多個地址(例如IPv4和IPv6)的主機頗有用,它能夠限定使用哪一個地址。*表示本地主機上的任意地址。
  • 監聽端口是一個端口號。29418是默認的Gerrit SSH端口,而8080是默認的Gerrit Web端口。可是若是8080已經被別的應用程序佔用了,那麼你可能會想修改第二個端口。
  • 身份驗證方法肯定了如何登陸Gerrit。若是你想掛入某個現有的身份驗證提供方(例如Google Accounts),那麼可使用OpenID。但對測試而言(還有上面提到的範例),可使用development_become_any_account。鍵入?會顯示一個可用方法的列表。

Gerrit啓動後,會打開一個瀏覽器,顯示Gerrit主頁。登陸的第一個用戶將自動成爲管理員;全部後續登陸的用戶都是無權限用戶。若是你選擇了development_become_any_account,在頁面頂端會有一個Become連接,經過它能夠進入註冊/登陸頁面。

註冊用戶

爲了使用Gerrit,你須要一個帳號,生成一個SSH密鑰對。在命令行中運行 ssh-keygen -t rsa -b 2048能夠生成密鑰對,將其放到你的.ssh目錄中。若是你須要更多信息,能夠訪問這篇博文,這是我六年前寫的SSH密鑰相關文章。此外,GitHub 幫助頁面中也有更多相關信息。

默認文件名爲id_rsa(這是私鑰)和id_rsa.pub(這是公鑰)。你只能給別人公鑰,千萬別給別人私鑰。

有了密鑰,你就能夠在Gerrit中註冊新帳戶了。點擊頂部右端的「Become」連接,而後再點擊「New account」按鈕,輸入Git知道的名稱和電子郵件(即上面用git config配置的),這些內容要徹底匹配(包括大小寫)。保存變動,而後選擇一個惟一的用戶名(填入了名稱後點擊'select username',例如demo)。

在'add SSH public key'文本框中,添加.pub文件中的公鑰。若是你使用的是OS X,pbcopy < ~/.ssh/id_rsa.pub就可輕鬆搞定。記住要點擊「Add」保存公鑰。

點擊Continue後應該就能登陸到Gerrit的主窗口了。到目前爲止一切還不錯,如今能夠測試SSH的連通性了。

鍵入ssh -p 29418 demo@localhost會嘗試鏈接Gerrit服務器,會出現如下三者之一:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!

這並無看上去那麼糟。它只是說你的~/.ssh/known_hosts文件中有舊的密鑰。最懶的一種修復方法是刪除這個文件(這是GitHub推薦的作法)。更好的方法是找到提示出錯的那一行,把它刪了:

Offending key in /Users/demo/.ssh/known_hosts:123

你能夠用任何文本編輯器來刪除known_hosts文件中的第123行。在標準UNIX配置下,能夠用如下命令自動刪除:

sed -i '' '123d' ~/.ssh/known_hosts
The authenticity of host '[localhost]:29418 ([::1]:29418)' can't be established.
RSA key fingerprint is e8:e2:fe:19:6f:e2:db:c1:05:b5:bf:a6:ad:4b:04:33.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:29418' (RSA) to the list of known hosts.
Permission denied (publickey).

若是看到這個消息,說明Gerrit沒有識別出你提交的任何密鑰。ssh默認會發送id_rsa,要確認它的確發送了該值,能夠查看.ssh/config,文件頭上有一行IdentityFile ~/.ssh/id_rsa。能夠運行ssh -v查看發送的內容:

debug1: Next authentication method: publickey
debug1: Trying private key: /Users/demo/.ssh/id_dsa
debug1: Offering public key: /Users/demo/.ssh/id_rsa

假設已經發送了正確的密鑰,那麼在settings - ssh public keys菜單項中檢查該密鑰是否關聯了Gerrit中的用戶。若是沒有的話點擊'Add Key'並和以前同樣粘貼公鑰。

若是Gerrit仍是說你未經身份驗證,檢查用戶名和配置頁面裏的用戶名是否一致。若是用戶名不一樣,試試ssh -p 29418 username@localhost。

最後,要驗證具體的密鑰,能夠運行ssh -i ~/.ssh/id_rsa顯式地選擇要使用的密鑰,而不是讓它自動選擇密鑰。若是這樣能夠工做,但不帶-i參數卻不行的話,那麼問題出在你的~/.ssh/config文件裏――你須要保證選擇了合適的IdentityFile。

 ****    Welcome to Gerrit Code Review    ****

  Hi demo, you have successfully connected over SSH.

  Unfortunately, interactive shells are disabled.
  To clone a hosted Git repository, use:

  git clone ssh://demo@localhost:29418/REPOSITORY_NAME.git

Connection to localhost closed.

若是看到這個提示,說明Gerrit已經正常工做了。

修正電子郵件地址

若是以前你沒法在Gerrit中註冊電子郵件地址,那麼能夠手工進行註冊。咱們能夠中止Gerrit,運行GSQL工具更新特定數據字段。

$ bin/gerrit.sh stop
$ java -jar bin/gerrit.war gsql
Welcome to Gerrit Code Review 2.1.6.1
(H2 1.2.134 (2010-04-23))

Type '\h' for help.  Type '\r' to clear the buffer.

gerrit> select * from ACCOUNT_EXTERNAL_IDS;
 ACCOUNT_ID | EMAIL_ADDRESS          | PASSWORD | EXTERNAL_ID
 -----------+------------------------+----------+------------------------------------------
 1000000    | NULL                   | NULL     | uuid:ac1b8a08-2dd1-4aa1-8449-8b2994dffaed
 1000000    | NULL                   | NULL     | username:demo
(2 rows; 23 ms)
gerrit> update ACCOUNT_EXTERNAL_IDS set EMAIL_ADDRESS='alex.blewitt@example.com' where ACCOUNT_ID=1000000;
UPDATE 2; 5 ms
gerrit> select * from ACCOUNT_EXTERNAL_IDS;
 ACCOUNT_ID | EMAIL_ADDRESS          | PASSWORD | EXTERNAL_ID
 -----------+------------------------+----------+------------------------------------------
 1000000    | alex.blewitt@example.com | NULL     | uuid:ac1b8a08-2dd1-4aa1-8449-8b2994dffaed
 1000000    | alex.blewitt@example.com | NULL     | username:demo
(2 rows; 23 ms)
gerrit> \q
Bye
$ bin/gerrit.sh start

建立項目,克隆並推送代碼

開始前,咱們須要先在Gerrit中建立一個項目。若是Gerrit沒有在你的範例目錄中檢測到項目,在它運行時,咱們能夠建立一個項目。

$ ssh -p 29418 demo@localhost gerrit create-project --name example.git

上述命令會建立一個名爲example的項目,在以前指定的Git目錄裏初始化一個空的代碼庫。若是已經有一個代碼庫了,Gerrit不容許建立同名代碼庫——但你能夠先對它進行臨時重命名,隨後再把名字改回來。

隨後,能夠建立一個克隆:

$ git clone ssh://demo@localhost:29418/example.git
Cloning into example...
warning: You appear to have cloned an empty repository.

咱們能夠向代碼庫進行提交和推送,就和其餘Git系統同樣:

$ cd example
$ echo hello > world
$ git add world
$ git commit -m "The World"
[master (root-commit) 06bf85e] The World
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 world
$ git push
No refs in common and none specified; doing nothing.
Perhaps you should specify a branch such as 'master'.
$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 217 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://me@localhost:29418/example.git
 ! [remote rejected] master -> master (prohibited by Gerrit)
error: failed to push some refs to 'ssh://demo@localhost:29418/example.git'

這是什麼狀況?Gerrit不但願咱們直接覆寫Git代碼庫中的任何分支,而是將變動推送到另外一個refspec中,這讓Gerrit有機會在代碼審查中修改代碼。最簡單的方法是爲推送配置一個默認的refspec:

$ git config remote.origin.push refs/heads/*:refs/for/*
$ git push origin
Counting objects: 3, done.
Writing objects: 100% (3/3), 217 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://demo@localhost:29418/example.git
 * [new branch]      master -> refs/for/master

咱們推送了一個分支,在Gerrit的change,1裏能夠發現,儘管實際的分支名稱是refs/changes/01/1/1,但看到的倒是refs/for/master。你會發現當前分支的哈希值和此處顯示的同樣(在個人例子裏是06bf85e)。若是咱們要再次推送,會建立一個新的分支refs/changes/02/2/1,而不是覆蓋refs/for/master。第一個數字是變動號的最後兩位,第二個數字是變動號,第三個數字是補丁集號。因此變動123的補丁集17就是refs/changes/23/123/17。

若是想要修正(amend)提交,Gerrit會建立一個新的代碼審查引用,這麼作不太好。若是兩次變動之間有審查評語,你將丟失這些內容。

咱們能夠修改commit-msg,添加一個(Gerrit專門的)Change-Id。同一變動的全部後續提交都會關聯到一個補丁集上。Gerrit提供了一個實現,只要複製出來就好了。

$ cd .git/hooks
$ scp -P 29418 demo@localhost:hooks/commit-msg .
$ cd ../..

如今,當咱們要提交修正時便會自動生成一個Change-Id。能夠用這個值爲變動集生成多個補丁。經過修正提交,並提供Gerrit變動的Change-Id,咱們能夠修改當前的提交。

$ git commit --amend -m "Hello World
>
> Change-Id: I06bf85ed12f370212ec22dbd76c115861b653cf2
> "
[master 86a7a39] Hello World
 1 files changed, 1 insertions(+), 0 deletions(-)
$ git push
Counting objects: 3, done.
Writing objects: 100% (3/3), 260 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: (W) 86a7a39: no files changed, message updated
To ssh://me@localhost:29418/example.git
 * [new branch]      master -> refs/for/master

如今再去看Gerrit中的change 1,你會發現出現了第二個與該變動相關聯的補丁集。遠端分支refs/changes/01/1/2包含了新的提交消息(儘管全部文件仍是同樣的)。

一般狀況下,你並不須要添加Change-Id,由於提交消息Hook會自動幫你添加的。

代碼審查與結果提交

咱們要建立一個build.sh腳原本執行構建過程。Jenkins/Hudson會簽出並運行該腳本。通常而言,這是一個Maven的構建,也多是xcodebuild或make——爲了不針對某種語言,咱們就使用一個普通的腳本。

$ cat > build.sh
#!/bin/sh
echo Pretending to build ...
echo done
^D
$ chmod a+x build.sh
$ git add build.sh
$ git commit -m "Adding (dummy) build script"
$ git push

問題是這些變動還在Gerrit的評審隊列裏,咱們要先批准這些變動。進入變動頁面,會看到這些文件,還有一個Review按鈕。在變動頁面有一個讓你作代碼審查的Review按鈕,但卻沒有提交按鈕……

這是由於變動在提交前默認要評審+2,每一個人只能+1,也就是說只有一我的作代碼審查是沒法提交代碼的。

咱們能夠修改Gerrit的規則,容許一我的投票+2,也能夠准許+1提交。

最簡單的方法是進入項目管理頁面All Projects Access標籤頁(在Gerrit 2.2.1和2.1.7.2裏這個標籤從--All Projects--改爲了All-Projects)。點擊「Code review」規則旁邊的複選框,修改「Permitted Range」爲+2: Looks good to me, approved。Gerrit還須要一個+1校驗,隨後也會爲Jenkins/Hudson配置的。按照下面內容添加一條新規則:

Category  
Verified  
Group Name  
Non-Interactive Users  
Reference Name  
refs/*  
Permitted Range  
-1: Fails to +1: Verified 

點擊「Add Access Right」來配置該權限。

咱們須要爲Jenkins/Hudson建立一個新用戶並添加到這個分組裏,所以進到登陸頁面註冊一個新帳戶buildbot。還須要一個新的SSH密鑰(名字是id_rsa.buildbot),和以前同樣粘貼在公鑰一欄裏。

從新用管理員ID登陸(你早些時候建立的那個帳戶),進入Admin - Groups標籤。在Non-Interactive Users里加入buildbot和demo用戶(後者是臨時的)。

配置好了校驗規則,咱們應該回到變動頁面,將這個變動標記爲經過。

但咱們仍是缺乏一個Submit按鈕,須要用它來合併分支。提交權限獨立於校驗和代碼審查權限以外,所以須要回到All Projects Access標籤頁,添加一個權限:

Category  
Submit  
Group Name  
Registered Users  
Reference Name  
refs/*  
Permitted Range  
+1: Submit 

點擊「Add Access Right」來配置該權限。

如今,回到變動頁面,咱們就能看到Submit按鈕(若是變動已經經過了代碼審查)了,在評論/代碼審查頁面也有Publish and Submit按鈕。(請注意,若是代碼審查還沒到達提交所需的級別,在點擊Publish and Submit時會出現一個錯誤提示。)

最後,發佈並提交全部未完成的代碼審查(保證構建腳本已經就緒),執行git pull來確保你的代碼庫是最新的。它們應該出如今已合併標籤頁中。

管理員注意事項:通常來講,不會廣泛賦予'All Projects Access'權限,而是根據項目進行分配。這裏使用'All Projects'是爲了方便運行,也能夠根據項目進行配置。

配置Jenkins/Hudson

如今要作的就是配置Jenkins(若是你喜歡也能夠用Hudson)。它們和Gerrit同樣,默認運行在8080端口上,你須要爲它們換個端口。修改Gerrit的端口要從新執行以前的配置過程,修改Jenkins/Hudson的端口只需命令行便可。

$ #java -jar hudson-2.0.1.war --httpPort=1234
$ java -jar jenkins.war -httpPort=1234
...

Jenkins/Hudson能夠直接簽出Git項目,也能夠經過Gerrit簽出。可是簽出過程未必都能自定義SSH身份(不用.ssh/config中的默認身份集)。有時使用匿名Git協議來託管Git代碼庫會容易些,即無需身份驗證。能夠運行以下命令:

$ git daemon --export-all --base-path=/path/to/gits

咱們還須要安裝Git插件和Git/Gerrit觸發器。打開位於http://localhost:1234的Jenkins/Hudson,點擊左上方的Manage Jenkins/Hudson連接,再點擊Manage Plugins連接。切換到 Available標籤頁,安裝:

  • Gerrit Trigger

Install按鈕在右下方,Jenkins/Hudson稍後會重啓。Gerrit Trigger會安裝Git插件。請注意,有一個Gerrit Plugin,那個不是咱們要裝的。(若是你在使用Hudson,而且更新頁面裏沒有任何內容的話,進入'Advanced'點擊下方的'Check now'。)

如今,咱們能夠開始配置Jenkins/Hudson了。先按如下步驟新建一個CI任務檢查Git代碼庫的變動(合併):

  1. 點擊左上方的'New Job'。這會要求你輸入一個名稱(例如Example)和類型;本例中選擇free-style項目。
  2. SCM類型選擇Git(若是沒有這個選項,說明須要安裝上面提到的Git插件)。URL是git://localhost/example.git
  3. 至於構建觸發器,選中Poll SCM並輸入* * * * *。這裏的格式與crontab相似,這裏至關於每分鐘檢查一次代碼庫。
  4. 滾動到add a build step,選擇execute shell。輸入$WORKSPACE/build.sh(請注意:若是項目名中有空格,須要用引號把它括起來,例如"$WORKSPACE/build.sh")
  5. 最後,點擊Save,項目建立好了。

上面建立了一個項目,簽出master,若是有變化則執行build.sh。點擊build now連接會簽出代碼,運行腳本並報告執行成功與否。(若是失敗了,能夠檢查構建日誌瞭解詳細信息,在繼續後續任務前把問題解決掉。)

集成Gerrit

咱們如今已經能夠在master發生變動時經過Jenkins/Hudson自動構建了,可是咱們還應該在提交代碼審查時進行構建。

下面要建立另外一個任務:

Name  
Example-Gerrit  
Type  
Free-style  
SCM  
Git  
URL  
git://localhost/example.git  
Advanced (below URL of repository) Refspec  
$GERRIT_REFSPEC  
Advanced (above repository browser) Choosing strategy  
Gerrit-plugin  
Build Triggers  
Gerrit Event  
Gerrit Project  
Path - ** - Path - ** 

有新事件發生時,Gerrit會觸發項目。可是咱們還差一步,要告訴Jenkins/Hudson監聽哪一個Gerrit服務器。

在Manage Jenkins/Hudson標籤頁中,有一項Gerrit Trigger,添加以下信息:

Hostname  
localhost  
URL  
http://localhost:8080  
Port  
29418  
Username  
buildbot  
Keyfile  
/path/to/.ssh/id_rsa.buildbot  
SSH Keyfile password  
... 

首先,點擊下方的「Save」按鈕。而後,點擊Test Connection按鈕檢查配置是否成功。若是成功,點擊「Restart」,或者重啓Jenkins/Hudson。

若是一切順利,應該能夠回到主頁,左邊有一個Query and Trigger Gerrit Patches連接。點擊該連接,輸入is:open查看打開的變動,is:merged查看合併的變動。完成後,選中複選框,點擊Trigger Selected觸發該變動的構建。

若是你使用的是Hudson 2.0.0和Gerrit 2.2.0,在Hudson控制檯裏會看到java.lang.reflect.InvocationTargetException錯誤。這是新Gerrit Trigger的一個問題;升級到Hudson 2.0.1就行了。

整合到一塊兒

你如今能夠在代碼庫的本地克隆中建立一個變動,推送到Gerrit中,讓Jenkins/Hudson自動爲你執行構建。

要測試失敗的狀況,編輯build.sh腳本,在文件末尾輸入exit 1。提交文件並將其推送到Gerrit,你會看到Jenkins/Hudson的狀態會變爲失敗,由於如今的構建腳本返回了一個非零碼。修復提交,將剛纔那行改成exit 0,推送以後你會看到構建結果變回成功。

最後,若是要使用xcodebuild構建iOS應用程序,經過ocunit2junit.rb腳原本串聯整個構建,它會把SenTest的斷言轉爲Jenkins/Hudson能夠理解的形式,這樣失敗的斷言就能打印在輸出的構建日誌裏了。

相關文章
相關標籤/搜索