代碼 lint 試水【iOS】

一绩社、關(guān)于 lint

對于已經(jīng)搭建CI開發(fā)環(huán)境的團隊來說从铲,代碼規(guī)范管理必然會成為團隊協(xié)作的基石澜建。但人工的CodeReview中加入格式及規(guī)范檢查會存在如下問題

  1. 技術(shù)含量低米丘,大量重復勞動
  2. 容易出現(xiàn)誤判
  3. 規(guī)范變更同步困難赶撰,難以維護

針對以上問題舌镶,代碼lint概念誕生。

歷史背景

相比其他技術(shù)豪娜,代碼lint其實由來已久餐胀。維基百科解釋,lint 作為一種工具程序瘤载,主要負責靜態(tài)源碼分析否灾,負責代碼規(guī)范、代碼缺陷等檢測鸣奔,最早出現(xiàn)在 Unix 系統(tǒng)中墨技,用于C語言代碼檢測惩阶。

使用場景

而在實際lint 場景中,凡是作為第三方檢測校驗的輔助工具都可算lint范疇扣汪。比如:

主要用途
commitizen lint 檢測 git commit 提交信息規(guī)范
eslint 靜態(tài)檢測 js 代碼規(guī)范及缺陷
imageSizeLint 檢查項目中的異常圖片尺寸是否異常

常用的代碼 lint 庫

語言 lint 庫
Objective-C OCLint
Swift SwiftLint
java(android) AndroidStudio Lint
kotlin klint
javascript eslint
go golint

lint 可參與的生命周期

image

IDE 支持

Jetbrain 出品的系列 IDE(WebStorm断楷、AndroidStudio、AppCode)崭别、VSCode 都擁有豐富的 lint 插件脐嫂,大多數(shù)是基于常用lint庫開發(fā)的。上述的兩個 IDE 除了Objective-C紊遵,其他語言基本都支持。
Xcode 已不再支持插件植入侥蒙,但可以通過 Xcode 輔助API暗膜,在編譯時進行 lint 錯誤日志輸出,代表作為 OClint鞭衩、SwiftLint学搜。

其他周期

除了 IDE 支持,其他的生命周期均可使用 lint 庫自帶的命令行工具實現(xiàn)论衍。

二瑞佩、定制自己的 lint 工作流

看完上面的介紹,大家可能會想坯台。我只要在 CI 階段集成 lint 不就一勞永逸了炬丸?這里其實會類比一個場景--- SVN 和 Git 的特性差異,其中最主要的一個就是集中式分布式蜒蕾。
說回 lint 流稠炬,當一些 lint 檢查,堆積在一個 PR 提交時再做最終攔截時咪啡,會有以下問題:

  1. 反饋鏈太長首启,要到最后 PR 跑 CI 才能監(jiān)聽到。
  2. CI單點反饋影響因素較多撤摸,包括網(wǎng)速毅桃、CI機器性能、代碼集成等等准夷。
  3. 修復體驗差钥飞,無法針對已修復的問題做實時驗證。
    綜上冕象,我們需要根據(jù)分布式集中式的問題進行相互補充代承。

關(guān)于 集中式 lint 模式也有非常完善的實踐,但側(cè)重點和本文討論主題有所差異渐扮,這里不做深入討論论悴。

多 repo 場景

根據(jù)上圖掖棉,我們嘗試解決如下問題:

  1. 在代碼的不同階段,均有 lint 進行監(jiān)控膀估。
  2. 每個階段均有 lint 配置中心進行規(guī)則分發(fā)幔亥。
  3. 多個 repo 項目,同時由 lint 配置中心進行統(tǒng)一管理察纯,特指后端微服務帕棉、前端多 repo 這種場景。
  4. 最終的信息收集會通過 CI 檢測后饼记,通過反饋服務進行郵件同步香伴,反饋每次CI集成的質(zhì)量,lint質(zhì)量作為集成質(zhì)量的一個子集具则。

如何實現(xiàn) iOS 的 lint 流管理

根據(jù)上文的環(huán)節(jié)即纲,我們需要逐步進行實現(xiàn)。

IDE編輯器實踐

對于 iOS博肋,你有如下選擇

IDE Type OCLint SwiftLint IDE default lint
Xcode ? ? ?
AppCode ? ? ?
VSCode nonsupport ? ?

如上低斋,除了 VSCode 不支持 OC 之外,其他編輯器大大小小都集成了lint環(huán)境匪凡。

其中膊畴,只有 AppCode 支持代碼編輯實時反饋。

IDE default lint 基本不支持自定義規(guī)則制定病游,大家在使用時可以有所取舍唇跨。

Xcode lint 集成

Xcode 支持的lint檢查,基本都是要基于編譯的衬衬,所以 lint 結(jié)果查看位置比較特別轻绞,并不是在代碼書寫時實時反饋的,如下圖所示佣耐。


image

image

Xcode OCLint 集成

OCLint 官網(wǎng)提供了《Use OCLint in Xcode》進行 Xcode 集成政勃。并且為項目級別 lint,需要跟隨編譯進行l(wèi)int檢測兼砖。

Xcode SwitLint 集成

官網(wǎng)提供的《Use SwiftLint in Xcode》奸远,配置更簡單,同樣為項目級 lint讽挟,跟隨編譯進行懒叛。這里強烈推薦使用 Pod 集成,主要可以降低大家集成的成本(避開Homebrew耽梅,路徑配置這些成本),其他好處下文 git lint 關(guān)節(jié)會提到薛窥。
但可以通過命令行方式進行單個文件 Lint,使用方式如下。

$ swiftlint lint <source file0> <source file1> ...

Xcode default lint

主要指 Clang Static Analyzer诅迷,是 Xcode 編譯時自己產(chǎn)生的 warning 及 error佩番,但缺乏代碼風格檢查,不過多贅述。

AppCode lint 配置

AppCode SwiftLint 集成

使用 JetBrain 插件進行集成,具體可以參考這里蕉扮。

AppCode Default lint

image

image

除了編輯是的實時反饋,手動 lint 和 JetBrain 其他編輯器一樣赋秀,通過自帶的 Inspect Code 功能實現(xiàn),并且可以指定 lint 的范圍和需要檢測的規(guī)則律想,如上圖猎莲。

VSCode

VSCode 僅支持 SwiftLint 的應用市場插件,使用非常小眾技即,不做贅述益眉。

IDE lint 總結(jié)

綜上,考慮到統(tǒng)一性和擴展性姥份,優(yōu)先推薦 AppCode 進行日常代碼的開發(fā)和 lint 反饋,更加輕量年碘,不依賴編譯澈歉。

編譯 lint

在上文 IDE Lint 其實已經(jīng)涉及到編譯 lint,不管是 OCLint 還是 SwiftLint 天然支持屿衅,這里也不再過多贅述埃难。

Git 提交 lint

本次試水耗時最長的環(huán)節(jié),描述一下在這個時機做 lint 的優(yōu)勢涤久。

  1. 只 lint 最小范圍涡尘,即本次提交的 staged 區(qū)的文件,文件最少响迂,性能最優(yōu)考抄。
  2. 老項目存在的通病,由于老舊代碼沒有適配新的 lint 規(guī)則蔗彤,導致在項目 lint 適配之前川梅,基本無法通過 IDE lint編譯 lint
  3. 除了和上面的周期同樣具備分布式性能優(yōu)勢然遏,相對反饋周期相比CI也更及時贫途,粒度為每個 commit。

所以待侵,對于公司自己的項目丢早,由于老舊代碼 lint 規(guī)則適配周期較長,我們首先在項目中集成了這個時機的 lint秧倾。

Git Lint Flow

image

由于 OCLint 配置相對繁雜怨酝,我們先拿 SwiftLint 練手傀缩。如上圖,我們需要按照流程實現(xiàn)這2個關(guān)鍵點凫碌。

  1. lint 環(huán)境配置扑毡。
  2. commit hook 觸發(fā)器。

lint 環(huán)境配置

在上文的 IDE Lint 環(huán)節(jié)其實已經(jīng)介紹了盛险,SwiftLint 支持單文件的 lint瞄摊。

$ swiftlint lint <source file0> <source file1> ...

但如何將其與 git hook 完美結(jié)合?

不出意外你會遇到以下問題:

  1. git hook 的維護困難苦掘,需要自己編寫完 hook 腳本后换帜,在群里告訴大家把腳本復制到 .git 目錄中。
  2. git hook 默認使用 shell 編寫鹤啡,需要一定的 shell 經(jīng)驗惯驼。
  3. 如何判斷出哪些是待提交的文件,雖然 Git 提供了相關(guān)的命令递瑰,但需要自己和 git hook 做事件綁定祟牲。
  4. 判斷出待提交文件后,如何在 lint 失敗時跳出 commit 并提供有好的提示抖部?

這個在 iOS 領(lǐng)域基本沒有相關(guān)的實踐说贝,不如我們抬頭看下其他技術(shù)棧的解決方案。

image

上圖是前端關(guān)于 eslint 的一個解決方案慎颗。

說一下這幾個環(huán)節(jié)

husky:主要負責對 git hook 的管理乡恕,實際上是一個 node 編寫的觸發(fā)器,并且對 git hook 做了依賴反轉(zhuǎn)俯萎,方便你的 repo 或者其他配置中心統(tǒng)一管理傲宜,避免 .git 目錄頻繁的復制粘貼。附《husky 使用教程》夫啊。

lint-staged:主要負責檢測 Git 待提交的文件函卒,并將 list 提交給 lint 工具。附《lint-staged 使用教程》

lint 工具eslint撇眯、SwiftLint 等 lint 工具谆趾。

動手實踐

  1. 在項目根目錄配置 package.json
{
  "name": "ycMath",
  "version": "0.0.1",
  "private": true,
  "devDependencies": { # 在開發(fā)環(huán)境配置兩個工具
    "husky": "^2.7.0",
    "lint-staged": "^8.2.1"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged" # 指定在 pre-commit hook 時觸發(fā) lint-staged
    }
  },
  "lint-staged": {
    "linters": {
      "*.swift":["Pods/SwiftLint/swiftlint lint"] # 使用pod安裝 SwiftLint
    }
  }
}
  1. 根目錄執(zhí)行 npm install(這里默認大家都安裝了 npm,因為實在太高頻使用了??)
$ npm install

note!: 這里不要忘記在 .gitignore 文件里忽略根目錄的 node_modules 這個文件夾叛本。

  1. 創(chuàng)建一個新的 swift 文件進行驗證
$ vim AppDelegate.swift # 在文件里寫一寫超長注釋沪蓬,比如218個字符的注釋。
  1. 得到反饋結(jié)果来候,并提交失敗
$ git add .
$ git commit -m "test"
husky > pre-commit (node v8.9.1)
  ↓ Stashing changes... [skipped]
    → No partially staged files found...
  ? Running linters...
    ? Running tasks for *.swift
      ? Pods/SwiftLint/swiftlint lint

? Pods/SwiftLint/swiftlint lint found some errors. Please fix them and try committing again.
/Users/chaoyang/Dev/testLint/AppDelegate.swift
?? Line 27: Line should be 120 characters or less: currently 218 characters
?? Line 40: Line should be 120 characters or less: currently 128 characters
...

至此跷叉,你的 git lint 環(huán)節(jié)已經(jīng)完成功能。

基于 DRY 繼續(xù)優(yōu)化

在把這些教程和原理同步大家后,發(fā)現(xiàn)很多人會忘記 npm install lint 工具云挟,或者不知道如何安裝梆砸。本著 DRY 原則,能不重復的工作盡量不要重復园欣。
那么我需要解決以下問題:

  1. 如何探測大家的 lint 環(huán)境是否安裝完畢帖世?
  2. 如果有探測方案,應該選在什么時機沸枯?
  3. 如果探測到日矫,如何提示開發(fā)者進行安裝?

針對問題绑榴,又開始了新一輪的探索哪轿,終于在《基于 cocoapod 進行 iOS 開發(fā)》這片文章找到了靈感。

  1. 配置你的 Podfile翔怎,在里面添加如下 ruby 代碼
## lint 插件校驗
pre_install do |installer|
  # 獲取插件路徑
  sandbox_root = Pathname(installer.sandbox.root)
  ycroot = File.expand_path("..", sandbox_root)
  node_module_lint_stage = File.expand_path("node_modules/lint-staged/",ycroot)
  node_module_husky = File.expand_path("node_modules/husky",ycroot)
  
  has_lint_stage = File.exist?(node_module_lint_stage)
  has_husky = File.exist?(node_module_husky)
  
  # 檢查是否安裝 lint-staged 及 husky
  if has_husky && has_lint_stage
    Pod::UI.puts "lint staged 和 husky 存在窃诉,請繼續(xù)。"
  else
    # 方案一
    raise "warning by @SuperYang\n\nYCLog error: lint staged 或 husky 不存在赤套, 請使用以下命令安裝: npm install "

    # 這里的異常提示可能不太友好飘痛,如果你覺得大家本地都是必裝 npm 的,你可以使用下面的方案二
    # 方案二
    # Pod::UI.puts "lint staged 和 husky 不存在容握,正在嘗試安裝宣脉。"
    # `rm -rf node_modules && npm install&&echo lint staged 和 husky 安裝完畢`
    # Pod::UI.puts "lint staged 和 husky 完成安裝??????~~~"
  end
end
  1. 在根目錄刪除 node_modules 目錄。
$ rm -rf node_modules
  1. 執(zhí)行 pod install或update 命令唯沮。
$ pod install
  1. 查看錯誤提示
# 方案一
[!] An error occurred while processing the pre-install hook of the Podfile.

warning by @SuperYang

YCLog error: lint staged 或 husky 不存在, 請使用以下命令安裝: npm install
# 方案二
lint staged 和 husky 不存在堪遂,正在嘗試安裝介蛉。
lint staged 和 husky 完成安裝??????~~~

強烈推薦方案二,實測額外問題很少溶褪,只有幾個人的新電腦忘裝npm币旧。

CI Lint 配置 & 自動化 lint 報告

上文花了大幅度的篇幅介紹了幾個場景的 lint 玩法,關(guān)于CI lint 和 反饋報告發(fā)送環(huán)節(jié)猿妈,本文不做詳細介紹吹菱,之后會在項目實戰(zhàn)中進行測試,完成后會通過博客分享給大家彭则。

三鳍刷、總結(jié)

  • 回顧一下我們的知識點

    1. 基于分布式思想的 lint 架構(gòu)設(shè)計。
    2. 對于不同生命周期的lint實踐
    3. 對于 git commit lint 環(huán)節(jié)的設(shè)計及實踐俯抖。
      以上環(huán)節(jié)输瓜,git lint 是使用后感覺最輕量的,也是最容易自動化完成的流程。對于老舊項目對lint規(guī)則還未及時適配的尤揣,優(yōu)先推薦進行實踐搔啊,從文件級別進行檢測,也是業(yè)界比較常用的 lint 切口北戏。
  • 以上方案的大多數(shù)設(shè)計负芋,同樣適用于其他技術(shù)棧。

  • 當一個問題出現(xiàn)時嗜愈,首先要接受他的必然性旧蛾,同時盡量避難閉門造車,同樣的問題芝硬,其他人肯定也會遇到蚜点,更不要把自己束縛在自己的技術(shù)棧。擁抱更廣的社區(qū)拌阴,擁抱其他技術(shù)棧??绍绘。

  • 本文涉及的其他技術(shù)棧nodeJSRuby迟赃、Git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末陪拘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子纤壁,更是在濱河造成了極大的恐慌左刽,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酌媒,死亡現(xiàn)場離奇詭異欠痴,居然都是意外死亡,警方通過查閱死者的電腦和手機秒咨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門喇辽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雨席,你說我怎么就攤上這事菩咨。” “怎么了陡厘?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵抽米,是天一觀的道長。 經(jīng)常有香客問我糙置,道長云茸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任谤饭,我火速辦了婚禮查辩,結(jié)果婚禮上胖笛,老公的妹妹穿的比我還像新娘。我一直安慰自己宜岛,他們只是感情好长踊,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著萍倡,像睡著了一般身弊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上列敲,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天阱佛,我揣著相機與錄音,去河邊找鬼戴而。 笑死凑术,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的所意。 我是一名探鬼主播淮逊,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼扶踊!你這毒婦竟也來了泄鹏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤秧耗,失蹤者是張志新(化名)和其女友劉穎备籽,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體分井,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡车猬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了尺锚。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片珠闰。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缩麸,靈堂內(nèi)的尸體忽然破棺而出铸磅,到底是詐尸還是另有隱情赡矢,我是刑警寧澤杭朱,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站吹散,受9級特大地震影響弧械,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜空民,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一刃唐、第九天 我趴在偏房一處隱蔽的房頂上張望羞迷。 院中可真熱鬧,春花似錦画饥、人聲如沸衔瓮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽热鞍。三九已至,卻和暖如春衔彻,著一層夾襖步出監(jiān)牢的瞬間薇宠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工艰额, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留澄港,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓柄沮,卻偏偏與公主長得像回梧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子铡溪,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

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