目錄
一、什么是持續(xù)集成?
二、我們?yōu)槭裁匆贸掷m(xù)集成?
三、安裝環(huán)境配置
四、iOS 項(xiàng)目配置
五、Android 項(xiàng)目配置
六、寫在最后
一、什么是持續(xù)集成?
持續(xù)集成指的是頻繁主動(dòng)的將代碼集合并到代碼倉庫當(dāng)中,方便產(chǎn)品保持高質(zhì)量的快速迭代。持續(xù)集成的好處主要有:
1)快速發(fā)現(xiàn)錯(cuò)誤。每完成一點(diǎn)更新,就集成到主干,可以快速發(fā)現(xiàn)錯(cuò)誤,定位錯(cuò)誤也比較容易。
2)防止分支大幅偏離主干。如果不是經(jīng)常集成,主干又在不斷更新,會(huì)導(dǎo)致以后集成的難度變大,甚至難以集成。
在一次的集成都必須通過自動(dòng)化的構(gòu)建(包括編譯、打包、發(fā)布、自動(dòng)化測試等)來驗(yàn)證,從而盡早的發(fā)現(xiàn)集成當(dāng)中的錯(cuò)誤。
與持續(xù)集成相關(guān)的,還有兩個(gè)概念,分別是持續(xù)交付和持續(xù)部署:
持續(xù)交付(Continuous delivery)指的是,頻繁地將軟件的新版本,交付給質(zhì)量團(tuán)隊(duì)或者用戶,以供測試。如果測試通過,代碼就進(jìn)入生產(chǎn)階段。
持續(xù)部署(continuous deployment)是持續(xù)交付的下一步,指的是代碼通過評(píng)審以后,自動(dòng)部署到生產(chǎn)環(huán)境。
二、我們?yōu)槭裁匆贸掷m(xù)集成?
團(tuán)隊(duì)中目前最大的痛點(diǎn)就是開發(fā)的時(shí)間被碎片化。隨著產(chǎn)品種類越來越多,也冒出來了各種各樣的測試Case,特定的環(huán)境、特定的跳轉(zhuǎn)、特定的需求,開發(fā)同學(xué)在打包上花費(fèi)的時(shí)間也是越來越多。任務(wù)經(jīng)常性的被打斷,還有可能分心導(dǎo)致代碼質(zhì)量的下降等等。為了解決這種問題,我們打算為內(nèi)部同學(xué)提供一套簡單自動(dòng)的開發(fā)者環(huán)境,引入了Jenkins 持續(xù)集成。前期主要的目的就是提供一套可以動(dòng)態(tài)配置常用參數(shù)、自動(dòng)構(gòu)建安裝包、自動(dòng)分發(fā)下載的平臺(tái)。后期會(huì)接入QA 相關(guān)的自動(dòng)化測試、靜態(tài)代碼檢測,安裝包內(nèi)也會(huì)加大對(duì)開發(fā)者功能的支持。
三、安裝環(huán)境配置
由于要支持iOS 與Android 兩種不同系統(tǒng),最終選擇Mac 系統(tǒng)當(dāng)做服務(wù)器系統(tǒng),版本10.12.4。Jenkins 版本2.46.2,這里就不贅述Jenkins 的安裝方法與登錄方法了。
以下列舉了目前使用到的Jenkins 插件和版本號(hào),吐槽一下,配置過程中發(fā)現(xiàn)有些以前教程里的插件現(xiàn)在根本搜不到,無奈只能用其他方式解決:
Android Emulator Plugin ? ? ? ? ? ? ? ? ? ?2.15
Android Lint Plugin ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.4
build-name-setter ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 1.6.5
description setter plugin ? ? ? ? ? ? ? ? ? ? 1.10
GitHub Organization Folder Plugin ? ? 1.6
Gitlab Hook Plugin ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?1.4.2
GitLab Plugin ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?1.4.5
Global Post Script Plugin ? ? ? ? ? ? ? ? ? ?1.1.3
Gradle Plugin ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?1.26
Keychains and Provisioning Profiles Management ? ? ? ? ?1.0.0
Publish Over FTP ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?1.12
Xcode integration ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 1.4.11
四、iOS 項(xiàng)目配置
這里最主要使用的兩個(gè)Jenkins 插件是Xcode integration和Keychains and Provisioning Profiles Management。
1. 配置Keychains and Provisioning Profiles Management
安裝好本插件后,進(jìn)入Jenkins--系統(tǒng)管理會(huì)多出來一個(gè)“Keychains and Provisioning Profiles Management” 選項(xiàng)。
首先進(jìn)行上傳login.keychain 文件,查找地址是
/Users/用戶名/Library/keychains/login.keychain
接下來指定Code Signing Identity,可以從Xcode 里的Signing 選項(xiàng)中或者通過命令行查看login.keychain 內(nèi)包含的:
security find-identity -p codesigning 地址/login.keychain
比如這里我選擇了正式打包時(shí)使用的,
iPhone Distribution: XXXXX (Beijing) Network Technology Co., Ltd (3GEKQMXXXX)
配置Provisioning Profiles 目錄,這里最好將整個(gè)開發(fā)機(jī)上的鑰匙串和配置文件目錄都拷貝到Jenkins/Library 目錄下,
/User/用戶/Library/Keychains
/User/用戶/Library/MobileDevice/Provisioning Profiles
所以配置Jenkins 的Provisioning Profiles Directory Path為:
/Users/Shared/Jenkins/Library/MobileDevice/Provisioning Profiles
3. 配置iOS Jobs
1)新建--構(gòu)建一個(gè)自由風(fēng)格的軟件項(xiàng)目
2)選中“丟棄舊的構(gòu)建”,普遍選擇保留3天,30個(gè)構(gòu)建個(gè)數(shù)。
3)選擇“參數(shù)化構(gòu)建過程”,可根據(jù)業(yè)務(wù)配置動(dòng)態(tài)參數(shù),使用${NAME} 可得到選擇的值。
4)源碼管理選擇Git,填寫Repository URL 代碼倉庫地址,Credentials 新建這里我選擇了username 和password 的方式進(jìn)行訪問。
這里需要注意下系統(tǒng)Git 的版本號(hào),如果Git 版本低于1.8 可能會(huì)一直出現(xiàn)401 權(quán)限問題,需要升級(jí)Git 版本到1.8 以上。
5)構(gòu)建觸發(fā)器
可以配置定時(shí)任務(wù)、觸發(fā)式任務(wù)等,觸發(fā)式任務(wù)可定期檢測代碼倉庫是否有更新,并自動(dòng)執(zhí)行構(gòu)建操作。配置規(guī)則Jenkins 的幫助寫的很詳細(xì),這里就簡單列一下:
第一個(gè)參數(shù)代表的是分鐘 minute,取值 0~59;
第二個(gè)參數(shù)代表的是小時(shí) hour,取值 0~23;
第三個(gè)參數(shù)代表的是天 day,取值 1~31;
第四個(gè)參數(shù)代表的是月 month,取值 1~12;
最后一個(gè)參數(shù)代表的是星期 week,取值 0~7,0 和 7 都是表示星期天。
如H/15 * * * * 表示的就是每15分鐘檢查一次源碼變化。
6)構(gòu)建環(huán)境,選中Keychains and Code Signing Identities,Keychain 行選擇之前配置的login.keychain 即可。
彈出的選擇框中可能無法選擇Keychain,這個(gè)時(shí)候先選中Keychain and Code Singing Identities 選項(xiàng),先保存一下當(dāng)前配置,重新進(jìn)入Jobs 配置頁面就可以正常選擇了。
7)構(gòu)建
由于要執(zhí)行pod 和動(dòng)態(tài)參數(shù)改變,構(gòu)建前先執(zhí)行我們自己的腳本文件。增加構(gòu)建步驟,選擇Execute shell,注意位置要放在“構(gòu)建”模塊的第一位。
#bin/bsah - l
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8
cd $WORKSPACE/你的項(xiàng)目文件
/usr/local/bin/pod update --verbose --no-repo-update
#這里可以做一些動(dòng)態(tài)參數(shù)的替換,例如:
oldParm="www.baidu.com"
newParm="www.sina.com"
parmSed="sed -i \"\" \"s/$oldParm/$newParm/g\" main.pch"
eval $parmSed
再次增加構(gòu)建步驟,選擇Xcode 插件。General build settings:
如果當(dāng)前有Target ,就填寫;我們項(xiàng)目因?yàn)橛玫搅薚oday 插件,不止一個(gè)Target,就不填寫。
選中Clean before build?,每次編譯前Clean 一下。
選中Generate Archive?
通過Configuration 可以選擇當(dāng)前是Release 版本還是Debug 版本。
選中Pack application and build .ipa?,指定生成ipa 包,.ipa filename pattern 包名規(guī)則自定義,這里為app_${VERSION}_${BUILD_DATE}。
Output directory 目錄為${WORKSPACE}/build/ ,指定打包后的ipa 文件輸出目錄。
Code signing & OS X keychain options:
選中sign IPA at build time,選中unlock keychain,Keychain Path 填寫${KEYCHAIN_PATH},鑰匙串密碼這里為系統(tǒng)用戶登錄密碼。
Advanced Xcode build options:
配置Xcode Schema File,可以通過Xcode 的Manage Schemas... 查看現(xiàn)有的Schema。
Custom xcodebuild arguments 配置為PROVISIONING_PROFILE=${項(xiàng)目Target_PROVISIONING_PROFILE}。
Xcode Workspace File 配置為${HOME}/Home/workspace/AppForiOS/xxxx,這里指向的是項(xiàng)目的xcworkspace文件,但是在構(gòu)建過程中Jenkins 會(huì)自動(dòng)追加.xcworkspace 后綴名,填寫時(shí)需要注意。注意:這個(gè)參數(shù)配置了,下面的Xcode Project File 參數(shù)配置就無效了。
Xcode Project Directory 配置為包含了xcodeproj 文件的目錄,只需要單獨(dú)一個(gè)目錄名就可以,這里是相對(duì)路徑從$workspace 開始。
Xcode Project File 如果要配置的話指向xcodeproj 文件即可。
Build output directory 輸出指向${WORKSPACE}/build/,這里的輸出不止包括.ipa 安裝包。
8)構(gòu)建后操作
構(gòu)建后的流程是上傳至蒲公英后在Jenkins 的構(gòu)建歷史中顯示下載地址、二維碼等,或者可以FTP 上傳到內(nèi)部服務(wù)器、發(fā)送郵件等,根據(jù)需求選擇。
增加構(gòu)建后操作步驟選擇Post build task,勾選Run script only if all previous steps were successful,腳本執(zhí)行蒲公英上傳功能:
#蒲公英上的User Key
uKey="3f9526ca10b8d43f3fa881b98xxxxx"
#蒲公英上的API Key
apiKey="95f337f90fe42dad8bb84xxxxxxx"
cd build
name="$(find . -maxdepth 1 -name '*.ipa')"
#要上傳的ipa文件路徑
IPA_PATH="${WORKSPACE}/build/$name"
#執(zhí)行上傳至蒲公英的命令
curl -F "file=@$IPA_PATH" -F "uKey=$uKey" -F "_api_key=$apiKey" https://qiniu-storage.pgyer.com/apiv1/app/upload
再次增加構(gòu)建后操作步驟,選擇Set build description(注意上下順序),
Regular expression 配置"appQRCodeURL":"(.*)",這里可以根據(jù)正則從日志中匹配到想獲得的值,在Description 里使用\1、\2等展示正則匹配的值,這里就自由發(fā)揮了。如果要以HTML 的方式(顯示圖片等)展示描述信息,需要將Jenkins--系統(tǒng)管理--Configure Global Security--Markup Formatter 選項(xiàng)改為“Safe HTML”。
4. 配置中的問題
由于Jenkins 是以“Jenkins”用戶的身份進(jìn)行操作,構(gòu)建過程中會(huì)出現(xiàn)各種的權(quán)限問題,我都是比較暴力的直接修改文件的權(quán)限進(jìn)行解決。
構(gòu)建出現(xiàn)錯(cuò)誤:xcrun: error: unable to find utility "PackageApplication", not a developer tool or in PATH。
解決方法:發(fā)現(xiàn)Xcode 8.3 以后已經(jīng)廢棄了PackageApplication,所以解決方式就是從舊版上復(fù)制一份來使用。
https://pan.baidu.com/s/1kVqP8xx 下載PackageApplication
拷貝至/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/ 目錄下
執(zhí)行命令 sudo xcode-select -switch/Applications/Xcode.app/Contents/Developer/
chmod +x/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/PackageApplication
執(zhí)行pod 命令時(shí)出現(xiàn)ERROR: SSL verification error at depth 1: unable to get local issuer certificate (20)
解決方法:出現(xiàn)這個(gè)問題的原因主要是Ruby環(huán)境需要2.2版本以上,所以要更新Ruby環(huán)境。
1.安裝rvm:$ curl -L get.rvm.io | bash -s stable
2.裝載rvm:$ source ~/.rvm/scripts/rvm
3.安裝2.3.0版本ruby:$ rvm install 2.3.0
4.將2.3.0設(shè)為默認(rèn):$ rvm use 2.3.0 --default
執(zhí)行pod 時(shí)出現(xiàn)env: ruby_executable_hooks: No such file or directory
解決方法:嘗試升級(jí)ruby、嘗試安裝executable_hooks、嘗試修改命令腳本引用、嘗試修改Jenkins 環(huán)境變量PATH。
這個(gè)卡的時(shí)間比較長,也是各種資料查。因?yàn)樵诜?wù)器機(jī)器上執(zhí)行pod,或者配置Path 后終端都可以正常使用,但是在執(zhí)行Jenkins 構(gòu)建的時(shí)候卻一直失敗。一開始以為是環(huán)境版本太低,能升級(jí)的都升了。后來還嘗試安裝了executable_hooks(命令sudo gem install --user-install executable-hooks)。嘗試過去修改pod 命令里的引用,直接指到安裝后的ruby 目錄(引用!#/Users/Shared/Jenkins/.rvm/rubies/ruby-2.3.0/bin ruby_executable_hooks)或者修改GEM_PATH(/Users/Shared/Jenkins/.rvm/gems/ruby-2.3.0/environment)等等。最后看到有可能是Jenkins 執(zhí)行Shell 腳本時(shí)的環(huán)境與服務(wù)器的系統(tǒng)環(huán)境不相同,嘗試在Shell 腳本中輸出一些變量值進(jìn)行觀察,因?yàn)閷?duì)Shell 腳本不是很熟悉,最后去Jenkins--系統(tǒng)管理--系統(tǒng)設(shè)置--全局屬性中,新增鍵值對(duì)PATH,值指向新版本ruby(/Users/Shared/Jenkins/.rvm/rubies/ruby-2.3.0/bin:$PATH)
五、Android 項(xiàng)目配置
配置好iOS 項(xiàng)目后,再進(jìn)行Android 的配置就簡單很多,這里主要是對(duì)Android 的開發(fā)環(huán)境進(jìn)行配置,主要使用的Jenkins 插件是Gradle Plugin。
1. 環(huán)境配置
Jenkins--系統(tǒng)管理--系統(tǒng)設(shè)置
選中Environment variables,新增鍵值對(duì)ANDROID_HOME,指向Android 的SDK目錄。
Jenkins--系統(tǒng)管理--Global Tool Configuration
Gradle 安裝,隨便起一個(gè)Gradle 配置名稱,GRADLE_HOME 配置/Applications/Android Studio.app/Contents/gradle/gradle-x.x。
2. Jobs 配置
其他部分與iOS 配置類似,只需要增加構(gòu)建步驟從Xcode 切換成Invoke Gradle script 插件,
選中Invoke Gradle,Gradle Version 選擇剛才已經(jīng)配置好的Gradle 名稱。
Task 任務(wù)內(nèi)填入clean build,表示執(zhí)行clean 和build 兩個(gè)操作。這里需要注意build 操作會(huì)將項(xiàng)目中build.gralde 配置文件中buildTypes 下所有的配置都執(zhí)行一遍,第一次時(shí)沒有注意就執(zhí)行了build,結(jié)果10+個(gè)配置一共執(zhí)行了45分鐘。如果想打單獨(dú)配置的包,填入assemblerelease 包,根據(jù)buildTypes 內(nèi)的定義即可。
Root Build script,配置${workspace}/app/,這里指向的是項(xiàng)目使用的build.gradle 文件目錄。如果build.gradle 文件就在項(xiàng)目根目錄,則不用填寫。
Post build task,增加APK 簽名命令,jarsigner -verbose -keystore keystore地址 -signedjar 簽名后的文件名 -digestalg SHA1 -sigalg MD5withRSA 未簽名的安裝包地址 keystore的alias -storepass keystore的密碼
3. 配置中的問題
Jenkins構(gòu)建Android 出現(xiàn)/Users/Shared/Jenkins/.android/analytics.settings(No such file or directory)
解決:創(chuàng)建.android 目錄
SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable
解決:項(xiàng)目中缺少local.properties文件,主動(dòng)創(chuàng)建,填寫內(nèi)容sdk.dir=“sdk目錄”
Jenkins A problem occurred configuring project‘:app’. > The SDK directory‘/User/用戶/Library/Android/sdk' does not exist
解決:將改目錄的權(quán)限全部設(shè)置成了777
六、寫在最后
目前只是實(shí)現(xiàn)了簡單的基礎(chǔ)功能,發(fā)現(xiàn)坑確實(shí)不少,但不得不說Jenkins 的日志真的很詳細(xì),定位問題很方便。以上就是Jenkins 的一些經(jīng)驗(yàn),特此記錄總結(jié)一下。
參考鏈接
阮一峰 http://www.ruanyifeng.com/blog/2015/09/continuous-integration.html
七、補(bǔ)充匯總
在新復(fù)制一個(gè)帶有“Git Parameter”插件的項(xiàng)目后,點(diǎn)擊“Build with Parameters” 時(shí),選擇分支的選擇框內(nèi)提示“null Please look at the log”。
解決:由于在Jenkins workspace 目錄下沒有任何相關(guān)的代碼,只需要直接進(jìn)行構(gòu)建,拉取一次遠(yuǎn)程代碼到本地,再次點(diǎn)擊就會(huì)正常顯示分支信息了。?
在配置iOS 靜態(tài)代碼掃描時(shí),使用sonar-objective-c-plugin-0.5.0-SNAPSHOT.jar 插件進(jìn)行掃描,該插件版本與sonarQube 系統(tǒng)版本相關(guān),需要注意。目前遺留問題是OC 的掃描規(guī)則太少,掃描結(jié)果只能掃出壞味道,Bug 和漏洞都無法掃到。配置文件增加了如下配置也沒有效果:
sonar.objectivec.oclint.report=oclint.xml
sonar.objectivec.oclint.reportPath=sonar-reports/oclint.xml