本篇內(nèi)容介紹了“基于Gitee + Jenkins的開源項(xiàng)目自動(dòng)化協(xié)作的方法教程”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
創(chuàng)新互聯(lián)建站是一家企業(yè)級云計(jì)算解決方案提供商,超15年IDC數(shù)據(jù)中心運(yùn)營經(jīng)驗(yàn)。主營GPU顯卡服務(wù)器,站群服務(wù)器,成都二樞服務(wù)器租用托管,海外高防服務(wù)器,機(jī)柜大帶寬,動(dòng)態(tài)撥號VPS,海外云手機(jī),海外云服務(wù)器,海外服務(wù)器租用托管等。
摘要:在開源理念日漸活躍的今天,越來越多的人開始投身于開源,貢獻(xiàn)了越來越多的開源項(xiàng)目。而隨著時(shí)間的推移,更多的人開始為開源項(xiàng)目添磚加瓦,為某一領(lǐng)域的開源項(xiàng)目貢獻(xiàn)出自己的力量。貢獻(xiàn)者的增多又給開源作者帶來不少審核的壓力,實(shí)際上投身開源的這些開源作者基本都是業(yè)余時(shí)間來做,并沒有太多的時(shí)間投入在開源項(xiàng)目上。本文就為了解決這類場景,介紹下如何在 Gitee 上通過 Jenkins 來為自己的開源項(xiàng)目開啟自動(dòng)化協(xié)作,旨在將一些開源相關(guān)的工作自動(dòng)化,留出更多的時(shí)間投身開源事業(yè)。
碼云 Gitee 是開源中國(OSChina.net)于 2013 年推出的基于 Git 的代碼托管和協(xié)作開發(fā)平臺,提供代碼托管服務(wù),與開源中國社區(qū)資訊、博客、社區(qū)等版塊相互補(bǔ)充和促進(jìn),希望以此更好地為開發(fā)者服務(wù)、構(gòu)建更加完善的開源生態(tài)。經(jīng)過超過七年的砥礪發(fā)展,已成為國內(nèi)最大的代碼托管平臺。
Jenkins 是一款開源 CI&CD 軟件,用于自動(dòng)化各種任務(wù),包括構(gòu)建、測試和部署軟件,支持各種運(yùn)行方式,可通過系統(tǒng)包、Docker 或者通過一個(gè)獨(dú)立的 Java 程序運(yùn)行。
為開源項(xiàng)目貢獻(xiàn)代碼一般都是使用 PullRequest(MergeRequest)方式,這種方式一般要求用戶先將開源倉庫 Fork 到自己名下,然后基于自己名下的倉庫進(jìn)行修改提交,最終以 PullRequest 的形式提交到開源項(xiàng)目主倉庫,意思就是我請求合并我的這些代碼到你的主倉庫,來為這個(gè)開源項(xiàng)目修復(fù)/貢獻(xiàn)一些代碼,具體的使用可以參見 Gitee 官方文檔:https://gitee.com/help/articles/4128
除了常規(guī)的 PullRequest 方式,Gitee 還推出了輕量級 PullRequest(簡稱輕量級PR),這種方式可以摒除繁瑣的 Fork 流程,快速的向開源項(xiàng)目提交一個(gè) PullRequest。比如我】在閱讀 Readme 的時(shí)候發(fā)現(xiàn)有表述或者拼寫錯(cuò)誤,這時(shí)就可以直接修改 Readme 文件,提交的時(shí)候就會(huì)自動(dòng)生成一個(gè)輕量級PR,這種操作類似于知識共享平臺的糾錯(cuò)功能。詳細(xì)介紹可以參見:https://gitee.com/help/articles/4291
相比于常規(guī)的 PullRequest,Gitee 輕量級PR更加便捷。
開源項(xiàng)目作者在接收到用戶提交第一個(gè)的 PullRequest 的時(shí)候,心情想必是非常激動(dòng)的,畢竟這是對自己項(xiàng)目的一種認(rèn)可。而且根據(jù)我個(gè)人的觀察,一般情況下開源項(xiàng)目的 Star 數(shù)量超過100的時(shí)候,才有可能收獲自己的第一個(gè) PullRequest。
在 PullRequest 數(shù)量少的時(shí)候,人工完全能夠處理的過來,那么,如果是一個(gè)非?;鸨拈_源項(xiàng)目呢?答案是會(huì)有非常非常多的熱心用戶幫忙提交和貢獻(xiàn)代碼,而且這些 PullRequest 很有可能造成擠壓的情況。隨著項(xiàng)目的發(fā)展,合規(guī)性也要逐漸提上日程,對代碼提交的規(guī)范,甚至 Commit Message 的提交也有可能需要規(guī)范化。
目前開源協(xié)作中主要的痛點(diǎn)有如下幾個(gè):
提交信息不規(guī)范,比如中英文混用,重復(fù)的提交信息等
提交的代碼需要人工檢測是否能夠通過構(gòu)建
對于特定的文件需要進(jìn)行規(guī)范的格式化檢查
代碼質(zhì)量檢查需要反復(fù)溝通跟進(jìn)
貢獻(xiàn)者沒有詳細(xì)閱讀貢獻(xiàn)者協(xié)議或者規(guī)范
目前可以通過 Gitee + Jenkins 配置 PullRequest Flow,實(shí)現(xiàn)智能自動(dòng)化預(yù)處理一些場景,減少人力的維護(hù)。Gitee 提供了 Gitee Jenkins Plugin 插件,可以與 Jenkins 聯(lián)動(dòng),實(shí)現(xiàn)對每一個(gè) PullRequest 進(jìn)行一些自動(dòng)化的檢查,實(shí)現(xiàn)流程圖:
下面以一個(gè)小工具 GiteeAutoUpdate(地址:https://gitee.com/kesin/GiteeAutoUpdate,以下簡稱 GAU)為例,展開介紹下具體實(shí)現(xiàn)的方式
Note: 以下的示例代碼以及配置均為 Demo 為目的,并未做任何異常及錯(cuò)誤處理,如果需要投產(chǎn)使用,請做好異常及錯(cuò)誤處理,避免出現(xiàn)預(yù)期外的情況 :)
GAU 是一個(gè)推送到 Gitee 自動(dòng)更新到其它平臺的 Webhook 服務(wù)端,通過簡單的配置,可以實(shí)現(xiàn)推送到 Gitee 的提交自動(dòng)推送到其他平臺的目的。為了能夠自動(dòng)化的對用戶提交的 PullRequest 進(jìn)行一些前置檢查,假設(shè)我們需要做以下的一些事情:
配置 PullRequest 的與 Jenkins 聯(lián)動(dòng),當(dāng)有 PullRequest 提交或者更新的時(shí)候,觸發(fā) Jenkins 進(jìn)行前置檢查
提交 PullRequest 之后,自動(dòng)提示用戶閱讀貢獻(xiàn)者協(xié)議,然后評論Rebuild
即可進(jìn)行下一步的檢查(你也可以說評論了Rebuild
即視為同意貢獻(xiàn)者協(xié)議)
檢查 Commit Message 是否有重復(fù)的情況(我們要求每一個(gè) Commit Message 都有具體的意義)
驗(yàn)證構(gòu)建是否成功
檢查配置文件格式是否正確(對于一些關(guān)鍵的信息,需要做針對性的檢查)
集成 Sonar 質(zhì)量檢測工具,對代碼進(jìn)行檢測
Gitee 提供了 Gitee Jenkins Plugin 插件,可以在 Jenkins 的插件市場搜索進(jìn)行安裝,安裝完成后,我們新建一個(gè) Free Style 的工程,命名為 GAU
在 Source Code Management 配置 Git 源,作如下配置:
在 Build Triggers 內(nèi),選擇作如下配置:
并將 Gitee WebHook URL 添加到對應(yīng)倉庫的 WebHook 中
其中 Webhook Token 即在 Jenkins 的 Secret Token for Gitee WebHook 生成的,這里需要注意的是,如果你的 Jenkins 暴露在公網(wǎng),你可能將 Jenkins 設(shè)置了需要權(quán)限才可以訪問,那么 Gitee 將無法請求你的這個(gè) WebHook,你需要使用插件Role-Based Strategy
來配置匿名用戶對 Build 的權(quán)限。不過不用擔(dān)心,你可以結(jié)合剛剛生成的 Token 來保證安全觸發(fā)。
接著配置一個(gè)構(gòu)建階段 Build,我們選擇 Execute shell
,并先填寫一個(gè)簡單的Hello World
最后,在 Post-build Actions 配置一下失敗后的回傳信息,這里我們只需要配置失敗后的動(dòng)作即可,因?yàn)槠渌那闆r我們將會(huì)通過腳本自行回傳。
提交一個(gè) PullRequest,將會(huì)自動(dòng)觸發(fā)構(gòu)建并提示Triggered by ZokerBot Gitee Pull Request #1: kesin/GiteeAutoUpdate => master
,并且任務(wù)執(zhí)行也會(huì)打出剛剛我們寫的那句Hello World
具體的配置見插件說明:https://gitee.com/oschina/Gitee-Jenkins-Plugin#%E6%8F%92%E4%BB%B6%E9%85%8D%E7%BD%AE
有時(shí)候,我們需要在用戶提交 PullRequest 后,自動(dòng)添加一句提示或者要求提交者進(jìn)行一些其他的操作,這里我們假設(shè)需要用戶閱讀貢獻(xiàn)者須知:
### 貢獻(xiàn)代碼1. 提交信息請不要重復(fù),保證每一個(gè)提交信息均有意義2. 提交的代碼請?zhí)砑幼⑨?. 代碼合并后,所有權(quán)將遵循項(xiàng)目本身的 LICENSE### 請求添加同步1. 請確保已經(jīng)在對應(yīng)平臺將授權(quán)用戶加到對應(yīng)項(xiàng)目2. 請確保已經(jīng)添加 Webhook 到你的倉庫3. 請確保`syncWhitelist`內(nèi)容符合格式
為了確保評論信息整潔,我們將內(nèi)容添加到 Issue 中:https://gitee.com/kesin/GiteeAutoUpdate/issues/I28BNK
那么,我們需要的歡迎信息應(yīng)該是這個(gè)樣子的:
為了快速實(shí)現(xiàn),我們下面使用 Go 寫一個(gè)腳本giteeCheck
來實(shí)現(xiàn)這個(gè)功能:
func welcomeMsg(PRIID string) {params := make(map[string]interface{})params["access_token"] = TOKENif noteNotExist(PRIID) {// create first welcome noteparams["body"] = fmt.Sprintf(`歡迎提交 PR,您需要進(jìn)行如下兩步: 1. [點(diǎn)擊此處閱讀貢獻(xiàn)者協(xié)議及注意事項(xiàng)](https://gitee.com/%s/%s/issues/%s) 2. 在本 PR 評論「Rebuild」繼續(xù)執(zhí)行構(gòu)建集成測試狀態(tài),表示您閱讀并同意了「貢獻(xiàn)者協(xié)議」 `, OWNER, REPO, ISSUE) commentUrl := fmt.Sprintf("https://gitee.com/api/v5/repos/%s/%s/pulls/%s/comments", OWNER, REPO, PRIID) postForm(commentUrl, params) fmt.Printf("0")return} fmt.Printf("1") }
只需要傳入當(dāng)前的 PRIID 即可,為了識別是否是第一次提交,我們判定是否有過評論即可,所以在 Jenkins 的構(gòu)建過程我們可以添加這么一句命令
# add welcome msg when PR created status=`/home/zoker/app/jenkins/scripts/giteeCheck welcome ${giteePullRequestIid}`
其中,${giteePullRequestIid} 為 Gitee Jenkins Plugin 所傳入的環(huán)境變量,可以在 SHELL 中直接調(diào)用,將返回值保存到status
是為了判定是首次歡迎信息,還是之后的構(gòu)建。
提交信息是否重復(fù)可以根據(jù)源分支與目標(biāo)分支的差異提交來判定,Git 提供了一種方式,可以快速的拿到兩個(gè)版本之間的差異的提交信息
git log HEAD ^remotes/origin/master --pretty=format:'%B'
通過去重前后的數(shù)量對比,即可得出是否有重復(fù)的提交信息,這個(gè)過程的命令如下:
# check commit msg commitCountA=`git log HEAD ^remotes/origin/master --pretty=format:'%B'| sort -r |grep -v '^$'|wc -l` commitCountB=`git log HEAD ^remotes/origin/master --pretty=format:'%B'| sort -r |grep -v '^$'|uniq|wc -l` if [ $commitCountA == $commitCountB ]; then commitMsg="valid" else commitMsg="invalid" fi
執(zhí)行完后,我們將結(jié)果保存在commitMsg
變量,用以后續(xù)的信息回傳。
這一步檢測就比較簡單了,只需要執(zhí)行對應(yīng)的構(gòu)建命令,然后判定構(gòu)建物是否存在即可
# build and check validation go build main.go if [ -x gau ]; then buildStatus="valid" else buildStatus="invalid" fi
同樣,我們將結(jié)果保存在BuildStatus
,用以后續(xù)的信息回傳。
syncWhitelist
格式是否正確這里檢查syncWhitelist
是為了避免程序啟動(dòng)的時(shí)候無法讀取到正確的倉庫白名單信息而啟動(dòng)失敗,類似的行為也可以是團(tuán)隊(duì)自研的檢查工具或者商業(yè)檢查工具,用戶檢查代碼格式、注釋、是否存在意外上傳的 Token 等,這里以檢查文件的 Json 格式行為替代。同樣的我們寫了一個(gè)腳本用來解碼,保證解碼能夠正常進(jìn)行:
func checkFile(file string) { projects := make(map[string][]string) jsonFile, err := os.Open(file)if err != nil { fmt.Printf("invalid")return}defer jsonFile.Close() jsonParser := json.NewDecoder(jsonFile)if err := jsonParser.Decode(&projects); err != nil { fmt.Printf("invalid")return} fmt.Printf("valid") }
配置到構(gòu)建命令中:
# check syncWhitefile validation syncFormat=`/home/zoker/app/jenkins/scripts/giteeCheck checkfile config/syncWhitelist`
Sonar (SonarQube)是一個(gè)開源平臺,用于管理源代碼的質(zhì)量。Sonar 不只是一個(gè)質(zhì)量數(shù)據(jù)報(bào)告工具,更是代碼質(zhì)量管理平臺。它的安裝和使用都非常簡單,只要支持 Java 11 環(huán)境即可,這里不在贅述 Sonar 的安裝和使用,具體可以參見官方文檔:https://docs.sonarqube.org/latest/
我們所需要知道的就是,Sonar 由 SonarWeb 以及 SonarRunner 兩部分組成,SonarWeb 用以收集數(shù)據(jù)及展示,SonarRunner 用于分析倉庫代碼生成質(zhì)量數(shù)據(jù),只要在對應(yīng)的倉庫下執(zhí)行一條命令,就可以得到分析報(bào)告,我們可以根據(jù)這個(gè)報(bào)告重的數(shù)據(jù),來做一些門禁,比如多于5個(gè)警告或者有1個(gè)嚴(yán)重則直接拒絕掉 PullRequest,讓提交者完善后再行提交,可以在一定程度上解放人力。
為了快速實(shí)現(xiàn),我們接下來僅僅關(guān)注warningCount
,只要warningCount
大于零,就提示用戶可能有風(fēng)險(xiǎn),在執(zhí)行完分支命令后,我們可以從結(jié)果中拿到一個(gè) API 地址,這個(gè)地址包含了本次分析的一些基本數(shù)據(jù):
INFO: Analysis report generated in 50ms, dir size=134 KBINFO: Analysis report compressed in 15ms, zip size=31 KBINFO: Analysis report uploaded in 15msINFO: ANALYSIS SUCCESSFUL, you can browse http://127.0.0.1:8089/dashboard?id=taskoverINFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis reportINFO: More about the report processing at http://127.0.0.1:8089/api/ce/task?id=AXYoHjxxxxxxxxDlfFINFO: Analysis total time: 2.788 sINFO: ------------------------------------------------------------------------INFO: EXECUTION SUCCESS
我們要的就是拿到http://127.0.0.1:8089/api/ce/task?id=AXYoHjxxxxxxxxDlfF
這個(gè)地址,然后傳給我們的腳本進(jìn)行進(jìn)一步的處理:
# Sonar check /home/zoker/app/sonar/scanner/bin/sonar-scanner -Dsonar.projectKey=GAU -Dsonar.sources=. -Dsonar.host.url=http://127.0.0.1:8089 -Dsonar.login=410e439472a0626bde66aa7564fc3faa9430f7c6 > sonarRes sonarResUrl=`cat sonarRes | grep api/ce | cut -d' ' -f8` sleep 3 // 防止 SonarWeb 正在處理中就請求導(dǎo)致的 404
至此,幾個(gè)檢測項(xiàng)目均配置完成,并且我們所需要的status
syncFormat
commitMsg
buildStatus
sonarResUrl
等均已保存在變量中,接下來,我們就要把這些數(shù)據(jù)回傳到 PullRequest 的評論。
結(jié)果回傳無非就是把剛剛得到的一系列的結(jié)果,處理后以固定的格式通過 PullRequest 的評論 API 返回給對應(yīng)的 PullRequest,我們通過腳本對這些數(shù)據(jù)進(jìn)行處理,并且根據(jù)具體情況返回具體信息:
func resultBack(args []string) {var a, b, c, d = "success", "success", "success", "success"status := make(map[string]string) status["valid"] = ":white_check_mark:"status["invalid"] = ":x:"http:// sonar warningCountsonarRes, _ := http.Get(args[3]) sonarResBody, _ := ioutil.ReadAll(sonarRes.Body)var sonarJson map[string]map[string]interface{}var sonarStatus stringjson.Unmarshal(sonarResBody, &sonarJson)if sonarJson["task"]["warningCount"].(float64) == 0 { sonarStatus = ":white_check_mark:"d = "No Warings"} else { sonarStatus = ":x:"d = fmt.Sprintf("Warings: %f", sonarJson["task"]["warningCount"].(float64)) }// othersif args[4] == "invalid" { a = "請本地構(gòu)建成功后再行提交"}if args[5] == "invalid" { b = "有重復(fù)的提交"}if args[6] == "invalid" { c = "syncWhitelist 格式有誤,請確認(rèn)"}var botMsg stringif a == "success" && b == "success" && c == "success" { botMsg = "所有檢查通過,請 @Zoker 處理"} else { botMsg = "檢測到有 **未通過項(xiàng)** ,請檢查調(diào)整后重新提交,將會(huì)自動(dòng)重新觸發(fā)檢查。"} params := make(map[string]interface{}) params["access_token"] = TOKEN params["body"] = fmt.Sprintf(`自動(dòng)化檢測已完成,請根據(jù)結(jié)果進(jìn)行調(diào)整: | 步驟 | 結(jié)果 | 備注 | |-------------|---|-----------------| | 構(gòu)建 | %s | %s | | 提交信息檢查 | %s | %s | | syncWhitelist 格式檢查 | %s | %s | | Sonar 質(zhì)量檢測 | %s | %s | %s `, status[args[4]], a, status[args[5]], b, status[args[6]], c, sonarStatus, d, botMsg) commentUrl := fmt.Sprintf("https://gitee.com/api/v5/repos/%s/%s/pulls/%s/comments", OWNER, REPO, args[2]) postForm(commentUrl, params) }
最終,我們的構(gòu)建腳本看起來就是這樣的:
# add welcome msg when PR createdstatus=`/home/zoker/app/jenkins/scripts/giteeCheck welcome ${giteePullRequestIid}`if [ $status == "1" ]; then # check syncWhitefile validation syncFormat=`/home/zoker/app/jenkins/scripts/giteeCheck checkfile config/syncWhitelist` # check commit msg commitCountA=`git log HEAD ^remotes/origin/master --pretty=format:'%B'| sort -r |grep -v '^$'|wc -l` commitCountB=`git log HEAD ^remotes/origin/master --pretty=format:'%B'| sort -r |grep -v '^$'|uniq|wc -l` if [ $commitCountA == $commitCountB ]; then commitMsg="valid" else commitMsg="invalid" fi # build and check format go build if [ -x gau ]; then buildStatus="valid" else buildStatus="invalid" fi # Sonar check /home/zoker/app/sonar/scanner/bin/sonar-scanner -Dsonar.projectKey=GAU -Dsonar.sources=. -Dsonar.host.url=http://127.0.0.1:8089 -Dsonar.login=410exxxxxxxxxxxxxxxxxxx3faa9430f7c6 > sonarRes sonarResUrl=`cat sonarRes | grep api/ce | cut -d' ' -f8` sleep 3 # callback result /home/zoker/app/jenkins/scripts/giteeCheck result ${giteePullRequestIid} ${sonarResUrl} $buildStatus $commitMsg $syncFormatfi
我們來貢獻(xiàn)代碼為 GAU 修復(fù)一個(gè)強(qiáng)制推送的問題,我們新建一個(gè)fix-force-push
分支,在這個(gè)分支上修改代碼:
完善提交信息update utils.go fixed force push bug
并提交到分支,接著我們創(chuàng)建一個(gè) PullRequest
進(jìn)到 Jenkins 我們可以看到已經(jīng)觸發(fā)了構(gòu)建:
而且如我們所期望的,有了歡迎信息
我們評論Rebuild
接受貢獻(xiàn)者協(xié)議并開始檢查,等待片刻即可看到結(jié)果:
可以看到,構(gòu)建失敗了,原因是因?yàn)?Jenkins 構(gòu)建機(jī)器沒有配置代理,下載依賴包超時(shí)了,處理完后,我們重新執(zhí)行 Rebuild
可以看到,由于代碼量比較少,所以 Sonar 也沒什么質(zhì)量問題產(chǎn)生。這里需要說明的是,一般情況下更新代碼會(huì)自動(dòng)觸發(fā)構(gòu)建,不需要我們手動(dòng)評論Rebuild
。
“基于Gitee + Jenkins的開源項(xiàng)目自動(dòng)化協(xié)作的方法教程”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!