一绩社、關(guān)于 lint
對于已經(jīng)搭建CI開發(fā)環(huán)境的團隊來說从铲,代碼規(guī)范管理必然會成為團隊協(xié)作的基石澜建。但人工的CodeReview中加入格式及規(guī)范檢查會存在如下問題
- 技術(shù)含量低米丘,大量重復勞動
- 容易出現(xiàn)誤判
- 規(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 可參與的生命周期
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 提交時再做最終攔截時咪啡,會有以下問題:
- 反饋鏈太長首启,要到最后 PR 跑 CI 才能監(jiān)聽到。
- CI單點反饋影響因素較多撤摸,包括網(wǎng)速毅桃、CI機器性能、代碼集成等等准夷。
- 修復體驗差钥飞,無法針對已修復的問題做實時驗證。
綜上冕象,我們需要根據(jù)分布式
和集中式
的問題進行相互補充代承。
關(guān)于
集中式
lint 模式也有非常完善的實踐,但側(cè)重點和本文討論主題有所差異渐扮,這里不做深入討論论悴。
根據(jù)上圖掖棉,我們嘗試解決如下問題:
- 在代碼的不同階段,均有 lint 進行監(jiān)控膀估。
- 每個階段均有 lint 配置中心進行規(guī)則分發(fā)幔亥。
- 多個 repo 項目,同時由 lint 配置中心進行統(tǒng)一管理察纯,特指后端微服務帕棉、前端多 repo 這種場景。
- 最終的信息收集會通過 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é)果查看位置比較特別轻绞,并不是在代碼書寫時實時反饋的,如下圖所示佣耐。
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
除了編輯是的實時反饋,手動 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)勢涤久。
- 只 lint 最小范圍涡尘,即本次提交的 staged 區(qū)的文件,文件最少响迂,性能最優(yōu)考抄。
- 老項目存在的通病,由于老舊代碼沒有適配新的 lint 規(guī)則蔗彤,導致在項目 lint 適配之前川梅,基本無法通過
IDE lint
和編譯 lint
。 - 除了和上面的周期同樣具備分布式性能優(yōu)勢然遏,相對反饋周期相比CI也更及時贫途,粒度為每個 commit。
所以待侵,對于公司自己的項目丢早,由于老舊代碼 lint 規(guī)則適配周期較長,我們首先在項目中集成了這個時機的 lint秧倾。
Git Lint Flow
由于 OCLint 配置相對繁雜怨酝,我們先拿 SwiftLint 練手傀缩。如上圖,我們需要按照流程實現(xiàn)這2個關(guān)鍵點凫碌。
- lint 環(huán)境配置扑毡。
- commit hook 觸發(fā)器。
lint 環(huán)境配置
在上文的 IDE Lint
環(huán)節(jié)其實已經(jīng)介紹了盛险,SwiftLint 支持單文件的 lint瞄摊。
$ swiftlint lint <source file0> <source file1> ...
但如何將其與 git hook 完美結(jié)合?
不出意外你會遇到以下問題:
- git hook 的維護困難苦掘,需要自己編寫完 hook 腳本后换帜,在群里告訴大家把腳本復制到
.git
目錄中。 - git hook 默認使用 shell 編寫鹤啡,需要一定的 shell 經(jīng)驗惯驼。
- 如何判斷出哪些是待提交的文件,雖然 Git 提供了相關(guān)的命令递瑰,但需要自己和 git hook 做事件綁定祟牲。
- 判斷出待提交文件后,如何在 lint 失敗時跳出 commit 并提供有好的提示抖部?
這個在 iOS 領(lǐng)域基本沒有相關(guān)的實踐说贝,不如我們抬頭看下其他技術(shù)棧的解決方案。
上圖是前端關(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 工具谆趾。
動手實踐
- 在項目根目錄配置 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
}
}
}
- 根目錄執(zhí)行 npm install(這里默認大家都安裝了 npm,因為實在太高頻使用了??)
$ npm install
note!: 這里不要忘記在 .gitignore 文件里忽略根目錄的 node_modules
這個文件夾叛本。
- 創(chuàng)建一個新的 swift 文件進行驗證
$ vim AppDelegate.swift # 在文件里寫一寫超長注釋沪蓬,比如218個字符的注釋。
- 得到反饋結(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
原則,能不重復的工作盡量不要重復园欣。
那么我需要解決以下問題:
- 如何探測大家的 lint 環(huán)境是否安裝完畢帖世?
- 如果有探測方案,應該選在什么時機沸枯?
- 如果探測到日矫,如何提示開發(fā)者進行安裝?
針對問題绑榴,又開始了新一輪的探索哪轿,終于在《基于 cocoapod 進行 iOS 開發(fā)》這片文章找到了靈感。
- 配置你的 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
- 在根目錄刪除
node_modules
目錄。
$ rm -rf node_modules
- 執(zhí)行 pod install或update 命令唯沮。
$ pod install
- 查看錯誤提示
# 方案一
[!] 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é)
-
回顧一下我們的知識點
- 基于
分布式
思想的 lint 架構(gòu)設(shè)計。 - 對于不同生命周期的lint實踐
- 對于 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ù)棧
nodeJS
、Ruby
迟赃、Git