Fastlane實戰(zhàn)(一):移動開發(fā)自動化之道

本人一直認為:在程序的世界里,一切重復性的,流程化的工作都可以交給自動化去完成。

在移動開發(fā)中也是如此:其實寫代碼只是我們開發(fā)過程中的一部分,除此之外我們還需要進行編譯,打包,上傳,部署,庫管理,版本控制等等Coding之外的雜事,而正是這些乏味而重復的工作占用了我們寶貴的時間。

所以在“懶人”遍布的工程師世界中,總會有人想盡辦法做出改變,于是這些“懶人”們樂此不疲的造出許多美妙的輪子,既方便了自己,又幫助了他人,讓這個世界變得更加美好。

今天就給大家介紹其中一個輪子:Fastlane,這個Github上的明星項目截止到目前共獲得1萬多個Star,并且還有1500多個Fork。

Fastlane在我們團隊中的推廣和應用

怎么樣,聽起來是不是很牛?不過先別急,在進入正題之前,我想跟大家簡單分享一下我們移動團隊在開展持續(xù)測試和持續(xù)交付工作中的一些心得體會。

大家都知道,最近幾年,隨著智能手機的普及,移動端不僅要承載更多業(yè)務場景的實現(xiàn),并且還要應對不斷變化業(yè)務需求。這就要求我們移動團隊能夠迅速響應變化,快速的迭代。那么隨之而來的問題就是如何保障在不犧牲質(zhì)量的前提下,盡可能的提升速度,我認為這一切需要建立在高質(zhì)量的持續(xù)測試和持續(xù)交付體系之上。

但是移動端本身興起的時間就比較短,各方面的成熟度也有所欠缺,能夠拿來用的工具更是少之又少,隨著業(yè)務深度廣度的增加,迭代速度的加快,諸如證書管理,打包,上傳,發(fā)布這類重復而毫無技術(shù)含量的工作逐漸占用了大家的時間,團隊內(nèi)部對此詬病不已。

所以我們的架構(gòu)團隊從去年初就一直在尋找這樣的一種工具,一種解決方案,旨在徹底解放工程師的“雙手”。

剛開始我們嘗試使用Jenkins+Fir搭建了一套持續(xù)測試的環(huán)境,流程如下圖:

Jenkins+Fir

說實話,效果還是可以的,至少在一定的時期內(nèi)滿足了我們的要求,但是Jenkins本身只是一個通用的CI流程管理系統(tǒng),本身并不提供諸如ITC提包和Meta內(nèi)容管理,簽名,證書管理等等和移動端業(yè)務緊密結(jié)合的場景,而且配置的過程相當繁瑣。

去年年底的時候,機緣巧合之下,我們在Github上發(fā)現(xiàn)了Fastlane,看了Readme后感覺有戲,于是決定嘗試一下。其實剛開始的時候,我們也只是用Fastlane來解決iOS團隊內(nèi)證書同步和上傳ITC的問題,但是隨著深入的研究,發(fā)現(xiàn)其實Fastlane能做的更多,于是我們將其逐步應用到iOS端的更多的場景,比如:私有Pod的發(fā)布,代碼的靜態(tài)檢查,UIAutomation測試等等,接著又推廣到Andriod平臺,完成諸如私有AAR的發(fā)布,Monkey測試等等一系列任務。現(xiàn)在可以說Fastlane已經(jīng)變成了我們工作中密不可分的一部分。

另外,F(xiàn)astlane本身也可以和Jenkins,Circle等主流CI系統(tǒng)做很好的集成,并且由于主要的CI流程都由Fastlane來管理和執(zhí)行,所以從根本上降低了這些系統(tǒng)配置的復雜度。

Fastlane簡介

說了這么多,我們回到今天的主角身上,首先先簡單介紹一下:Fastlane是用Ruby語言編寫的一套自動化工具集和框架,每一個工具實際都對應一個Ruby腳本,用來執(zhí)行某一個特定的任務,而Fastlane核心框架則允許使用者通過類似配置文件的形式,將不同的工具有機而靈活的結(jié)合在一起,從而形成一個個完整的自動化流程。

到目前為止,F(xiàn)astlane的工具集大約包含170多個小工具,基本上涵蓋了打包,簽名,測試,部署,發(fā)布,庫管理等等移動開發(fā)中涉及到的內(nèi)容。

關(guān)于這些工具的描述和使用可以看這里:https://docs.fastlane.tools/actions/Actions/

如果這些工具仍然沒有符合你需求的,沒有關(guān)系,得益于Fastlane本身強大的Action和Plugin機制,如果你恰好懂一些Ruby開發(fā)的話,可以很輕易的編寫出自己想要的工具。

其實真正官方出品的工具大約占一半左右,剩下的都是Github社區(qū)成員貢獻的,本人有幸也貢獻過其中一個。(這里建議移動開發(fā)工程師還是需要學習一門腳本語言的,比如Ruby)

Fastlane的安裝非常簡單,和Cocoapods一樣,F(xiàn)astlane也可以通過RubyGems來安裝,如果你的電腦上有Ruby環(huán)境的話,那么只需要執(zhí)行如下命令,即可完成:

gem install fastlane

移動客戶端持續(xù)測試和持續(xù)交付的常見場景及痛點

Fastlane本身能做的事情很多,但是其中一個最為重要的作用就是能夠無縫嵌入在持續(xù)測試和持續(xù)交付體系中。

下面,為了便于大家理解,我拿iOS為例,舉幾個我們在移動開發(fā)過程中常常會遇到的場景:

場景一
當一個迭代開發(fā)測試結(jié)束,服務器端上線之后,我們會使用Testflight進行線上跟測,一般會執(zhí)行如下流程:

  1. 執(zhí)行Git Pull命令,拉最新的代碼到本地
  2. Pod Install安裝最新的依賴庫
  3. 在Xcode中將Build Version增加
  4. 在Xcode點擊Archive編譯并打包
  5. 選擇輸出一個iOS AppStore模式的ipa文件
  6. 通過Application Loader將IPA上傳到ITC(TestFlight)
  7. 然后等待ITC Process完成后,登錄上去選擇剛才的Build進行TestFlight測試
  8. 由于修改了版本號,所以需要將代碼Commit和Push一下

如果線上跟測發(fā)現(xiàn)有問題,那么需要修復完畢后重復上面的8個步驟。
其實做過這件事的同學應該都有體會,順利的話差不多一次得30分鐘吧,如果某一次Build Version忘記增加了,那么前面的工作就白做了。
在我們團隊早期的時候,由于自動化體系尚未建立,我們有一個同事專門負責此事,在線上跟測的這兩天,他有半天時間幾乎干不了別的,基本上都在打包上傳,說出來都是淚。

場景二
隨著業(yè)務的發(fā)展,產(chǎn)品線的增加,我們需要將APP拆分為若干個基礎組件和業(yè)務組件,以便跨APP使用,并且方便管理維護(這又是另外一個大的議題,就不在此贅述了)。每個組件都由一個私有Pod來管理,Pod的發(fā)布和更新也成為了我們?nèi)粘9ぷ鞯囊徊糠郑瑢τ谶@些Pod,一般我們團隊內(nèi)部的原則是:誰制作,誰管理,誰發(fā)布,Pod的負責人我們內(nèi)部稱之為庫管,這件事也就分擔到了每個庫管身上,庫管發(fā)布一個Pod的流程大約如下:

  1. 增加Podspec中的版本號
  2. 執(zhí)行pod lib lint命令進行庫驗證
  3. Git Commit代碼
  4. Git Push代碼到遠端
  5. 打一個Git Tag
  6. 將Tag Push到遠端
  7. 執(zhí)行pod repo push命令發(fā)布庫到私有倉庫

如果只有兩三個庫的話,并且?guī)斓母骂l率較低的時候,每次手動來處理還好。但是當庫逐漸增多的時候這件事就變得相當麻煩,尤其是當頂層的庫依賴底層庫的時候,那么升級一個庫,影響面將遠遠超過其本身,通過人工的方式處理的話,整個過程會變得相當痛苦。

說到這里,我相信但凡是操作過的同學,應該都對此深有感觸。

所以我們來看看針對以上這兩個場景,如何使用Fastlane來解決。

其實說起來也不難,首先在項目下執(zhí)行:

fastlane init

然后跟隨配置引導,填寫App和ITC相關(guān)信息,然后Fastlane會在項目目錄下創(chuàng)建一個fastlane目錄,里面包含所有和此項目相關(guān)的配置,剩下要做的就是將以上的流程配置在fastlane目錄下的Fastfile中,

場景一的Fastfile(可以忽略HipChat部分):

desc 'Deploy a new version to the App Store'
lane :do_deliver_app do |options|
  ENV["FASTLANE_PASSWORD"] = options[:itc_password]
  project          = options[:project]
  scheme           = options[:scheme]
  version          = options[:version] 
  build            = options[:build] || Time.now.strftime('%Y%m%d%H%M')
  output_directory = options[:output_directory]
  output_name      = options[:output_name]
    
  hipchat(message: "Start deilver app #{project} at version #{version}")
    
  hipchat(message: "Git pull")
  git_pull

  hipchat(message: "Pod install")
  cocoapods
   
  hipchat(message: "Update build number to #{build} and building ipa")
  update_build_number(version: build, plist: "#{project}/Info.plist")
  gym(scheme: options[:scheme], clean: true, output_directory: output_directory, output_name: output_name)

  hipchat(message: 'deliver to itunesconnect')
  deliver(force: false, skip_screenshots: true, skip_metadata: true)

  hipchat(message: "Upload #{project} to itunesconnect successfully!")
    
  git_add(path: '.')
  git_commit(path: '.', message: "update build number to #{build} and upload to itunesconnect")
  git_pull
  git_push(branch: "test")
end

場景二的Fastfile(可以忽略HipChat部分):

desc "Release new private pod version"
lane :do_release_lib do |options|
  target_version = options[:version]
  project        = options[:project]
  path           = "#{project}.podspec"
    
  hipchat(message: "Start release pod #{project} at version #{target_version}")
    
  git_pull
  ensure_git_branch # 確認 master 分支
  pod_install
  pod_lib_lint(verbose: true, allow_warnings: true, sources: SOURCES, use_bundle_exec: true, fail_fast: true)
  version_bump_podspec(path: path, version_number: target_version) # 更新 podspec
  git_commit_all(message: "Bump version to #{target_version}") # 提交版本號修改
  add_git_tag(tag: target_version) # 設置 tag
  push_to_git_remote # 推送到 git 倉庫
  pod_push(path: path, repo: "GMSpecs", allow_warnings: true, sources: SOURCES) # 提交到 CocoaPods
    
  hipchat(message: "Release pod #{project} Successfully!")
end

對于Fastlane的配置,官方提供的文檔中會有更詳細的描述:

https://docs.fastlane.tools/getting-started/ios/setup/

配置完這個腳本后,剩下的事就很輕松寫意了。
針對場景一我們在項目目錄下,用終端執(zhí)行如下命令即可:

fastlane do_deliver_app 
project:Gengmei 
scheme:Gengmei-AppStore 
version:6.3.0 
build:201609011530 
...

同理,針對場景二我們在項目目錄下,用終端執(zhí)行如下命令即可:

fastlane do_release_lib project:GMUtil version:0.1.4

任何復雜的流程,基本上一個命令全部搞定,是不是很方便。

另外,為了能夠讓Fastlane的各種命令更加傻瓜話,可視化,我們基于Fastlane內(nèi)核,使用Ruby on Rails框架開發(fā)了一款適用于移動端持續(xù)測試和持續(xù)發(fā)布的系統(tǒng)Jaguar。Jaguar本身和Gitlab,Sentry,Jira,HipChat,Maven等等內(nèi)部系統(tǒng)進行打通,從而形成一個完整的自動化體系。

Jaguar

這樣對于大部分的自動化流程,Jaguar會通過各種定時任務或WebHook自動觸發(fā);少部分需要人工操作的,工程師們也只需要點一個按鈕就能完成了。

這里附上一個Jaguar的截圖:


jaguar-screenshot

使用Fastlane的感受,踩坑的簡單回顧

使用了Fastlane這么長的時間,我最深的感受就是:Fastlane真正的將工程師從各種無聊而又必須要做的重復性勞動和流程化工作中解放出來,專注于業(yè)務或架構(gòu)本身,使得整個開發(fā)效率,測試效率,運維效率大大提升。

在使用Fastlane的過程中,有一些小的注意事項,也和大家分享一下:

由于Fastlane本身更新頻率比較高,大約1-2周一次,那么如果最近的幾個版本都沒有升級的話,建議仔細閱讀一下這幾次更新的Release Notes,否則有可能會出現(xiàn)一些奇奇怪怪的Bug,比如:
在1.87版本升級到1.88的時候,如果不在Fastfile中加入如下兩行:

ENV['FASTLANE_EXPERIMENTAL_TRANSPORTER_AVOID_SHELL_SCRIPT'] = '1'
ENV['SPACESHIP_LOGIN_ENCODING_IDENTITY'] = '1'

那么,上傳ITC的時候,就會報錯,而且從報錯中并不能看到具體原因,最后經(jīng)過各種折騰終于在Github上的issue中找到了原因:Spaceship這個工具增加了一個小的特性而導致的Bug。

另外,大家在使用Fastlane的過程中,如果遇到了問題,建議直接在Github上提issue,F(xiàn)astlane的作者和社區(qū)工程師們會非常迅速的做出響應,而且會非常熱心的幫你解決問題,當然大家提問題的時候要盡量描述清楚,該貼代碼帖代碼,該截圖的截圖。

發(fā)散思維,F(xiàn)astlane不只專屬于移動端

雖然Fastlane本身是為移動而生的,但是如果我們發(fā)揮一下想象力的話,就會發(fā)現(xiàn),其實也可以把后端,前端的持續(xù)集成和持續(xù)交付流程整理出來,然后也統(tǒng)一交給Fastlane來管理(當然這個過程中肯定需要自定義一些Plugin或Action的)

比如:我們團隊目前正計劃先把PC站的UI自動化測試流程集成進來:

  1. 執(zhí)行Git Pull命令,拉最新的代碼
  2. 使用pip安裝Requirements
  3. 混淆壓縮前端Javascript和CSS
  4. 重啟Django服務
  5. 使用Selenium執(zhí)行UI自動化測試
  6. 收集測試結(jié)果,發(fā)郵件給QA團隊

對應的Fastfile如下(簡寫,還未真正使用):

desc "Do automation test for pc web"
lane :automation_test_pc do |options|
  git_pull
  pip_install
  gulp_build
  restart_django
  selenium_test
end

這樣以來,一個團隊內(nèi)的客戶端,前端,后端的持續(xù)集成和持續(xù)交付就能夠統(tǒng)一部署,統(tǒng)一管理,統(tǒng)一維護,從而在基礎設施上能夠盡可能滿足團隊對自動化的需求,何樂而不為呢。

結(jié)語

本次分享只是帶大家領(lǐng)略了一下Fastlane的風采,針對諸如:如何自定義Action,Plugin,如何在Andriod平臺上使用的細節(jié),如何應用在自動化測試場景,以及一些Fastlane的高級用法等,我會在接下來的一段時間內(nèi)做出相應的整理,形成文章,以供大家參考。

由于本人的水平有限,難免會有錯誤和疏漏,也歡迎各位同學指正,如果大家在Fastlane的使用上,有更好的案例,也歡迎交流和分享。

最后,附上一個我們團隊正在使用到的Fastfile腳本和一些自定義Actions:
https://github.com/thierryxing/Fastfiles

另外,F(xiàn)astlane也提供了一些國外團隊的Example:
https://github.com/fastlane/examples

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內(nèi)容