背景
隨著代碼量的日益增加锦积,以及團(tuán)隊(duì)的擴(kuò)大表谊,我們往往因?yàn)樾枨笮枰M快上線以及快速迭代,導(dǎo)致代碼并不是很規(guī)范,時(shí)間長(zhǎng)了就留下了一堆技術(shù)債凿渊,代碼的質(zhì)量也沒(méi)有了保證。所以開(kāi)始嘗試一些代碼質(zhì)量相關(guān)建設(shè)册舞,希望能夠通過(guò)代碼靜態(tài)掃描的方式播演,幫助我們掃描出一些代碼漏洞,然后嘗試去修復(fù)漏洞和bug贯底,以此來(lái)保證代碼質(zhì)量丰辣。
工具與平臺(tái)
本文涉及的工具及平臺(tái):
開(kāi)源方案介紹及配置
大部分iOS平臺(tái)代碼靜態(tài)分析基本是基于開(kāi)源的oclint
或者infer
進(jìn)行的,本文雖然使用sonarqube
禽捆,但免費(fèi)的分析方案核心仍然是oclint
與infer
sonarqube
是一個(gè)開(kāi)源的靜態(tài)代碼分析平臺(tái)笙什,提供免費(fèi)的社區(qū)版,免費(fèi)的社區(qū)版不支持Objective-C
胚想,但github
有提供開(kāi)源的插件琐凭,Objective-C
,付費(fèi)的社區(qū)版plus有支持Objective-C
的分析插件SonarCFamily for C
無(wú)論免費(fèi)方案還是付費(fèi)方案浊服,首先都是基于xcodebuid過(guò)程中的日志來(lái)進(jìn)行的统屈,我們這次主要針對(duì)開(kāi)源方案來(lái)講相關(guān)配置流程。
對(duì)于使用開(kāi)源方案來(lái)說(shuō)牙躺,本質(zhì)流程如下:
xcodebuild
iOS核心工具愁憔,安裝好Xcode
就會(huì)自帶此工具,因?yàn)?code>oclint分析的核心是xcodebuild
在編譯app過(guò)程中的log
孽拷,所以需要xcodebuild
(build
失敗也會(huì)對(duì)已經(jīng)build
的日志進(jìn)行分析吨掌,但盡量保證可以build
成功)
如果項(xiàng)目是在workspace中需要指定-workspace和對(duì)應(yīng)的scheme,可以通過(guò)xcodebuild -list查看
//執(zhí)行
$ xcodebuild -list
//執(zhí)行
$ xcodebuild -workspace CsdnPlus.xcworkspace -scheme CsdnPlus
我們并不需要打出的IPA
包可以安裝到手機(jī)上脓恕,只是需要build
過(guò)程中的日志而已膜宋,所以我們只需要打出模擬器下Debug
包就可以了。
//執(zhí)行
$ xcodebuild -showsdks
因?yàn)?code>xcodebuild會(huì)有緩存炼幔,所以我們每次執(zhí)行前需要clean
$ xcodebuild -workspace CsdnPlus.xcworkspace -scheme CsdnPlus clean
執(zhí)行build
編譯
$ xcodebuild -scheme CsdnPlus -workspace CsdnPlus.xcworkspace -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 12 Pro Max' -configuration Debug
能編譯成功的話(huà)就可以進(jìn)入下一步了
xcpretty
xcpretty is a fast and flexible formatter for xcodebuild.
It does one thing, and it should do it well.
xcpretty
是一個(gè)格式化xcodebuild
輸出的工具激蹲。安裝:
$ gem install xcpretty
-r, --report
指定生成的報(bào)告格式可選為junit, html, json-compilation-database
。
-o, --output
指定生成的文件名稱(chēng)江掩。
這里我們使用json-compilation-database
格式学辱,輸出文件名為compile_commands.json
(注意輸出名稱(chēng)不能更改,否則后面oclint會(huì)報(bào)錯(cuò)环形,因?yàn)閛clint源碼中內(nèi)置了校驗(yàn)名稱(chēng)策泣,具體可查看源碼)
用法:
緊跟在xcodebuild
相關(guān)語(yǔ)句后面,比如:
$ xcodebuild [flags] | xcpretty
可以結(jié)合tee
進(jìn)行日志收集
$ xcodebuild [flags] | tee xcodebuild.log | xcpretty
執(zhí)行完整命令生成編譯數(shù)據(jù)compile_commands.json
文件:
首先需要用
xcodebuild
clean
和build
項(xiàng)目抬吟,并且添加COMPILER_INDEX_STORE_ENABLE=N
O參數(shù)萨咕,不然可能會(huì)出現(xiàn)報(bào)錯(cuò):oclint: error: one compiler command contains multiple jobs
報(bào)錯(cuò)
$ xcodebuild -scheme CsdnPlus -workspace CsdnPlus.xcworkspace -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 12 Pro Max' -configuration Debug GCC_PRECOMPILE_PREFIX_HEADER=YES CLANG_ENABLE_MODULE_DEBUGGING=NO COMPILER_INDEX_STORE_ENABLE=NO OTHER_CFLAGS="-DNS_FORMAT_ARGUMENT(A)= -D_Nullable_result=_Nullable" | tee xcodebuild.log | xcpretty -r json-compilation-database -o compile_commands.json
OCLint
OCLint is a static code analysis tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code
OCLint
是基于 Clang Tooling
開(kāi)發(fā)的靜態(tài)分析工具,主要用來(lái)發(fā)現(xiàn)編譯器檢查不到的那些潛在的關(guān)鍵技術(shù)問(wèn)題。是進(jìn)行OC
代碼分析的核心工具火本,主要對(duì)上一步生成的compile_commands.json
進(jìn)行分析危队,生成報(bào)告
命令安裝:
$ brew tap oclint/formulae
$ brew install oclint
我建議使用安裝包來(lái)安裝
OCLint
,Homebrew
安裝只能安裝到20.11
版本聪建,最新Xcode
版本對(duì)應(yīng)的是22.02
。如果安裝版本不符合茫陆,OClint
分析出來(lái)只有一堆compiler error
金麸。
image
下載安裝包安裝:
https://github.com/oclint/oclint/releases
配置環(huán)境變量:
export PATH="/Users/csdn/oclint-22.02/bin:$PATH"
source ~/.zshrc
在終端輸入 oclint --version
,驗(yàn)證是否安裝成功簿盅。
在終端輸入
oclint --help
查看命令介紹其中我們主要使用oclint-json-compilation-database命令挥下,Github源碼
oclint-json-compilation-database
命令支持指定校驗(yàn)文件夾和過(guò)濾指定文件夾,本質(zhì)上最終執(zhí)行oclint -p
命令桨醋,可以通過(guò)附加-v
查看棚瘟,同時(shí)還支持使用--
后面跟上oclint
執(zhí)行參數(shù)。
例如:
// 此處--符號(hào)后的參數(shù)是傳遞給oclint的
$ oclint-json-compilation-database -v -e Pods -e xxxx -- -report-type html -o report.html
oclint
的-rc
選項(xiàng)可以自定義校驗(yàn)的參數(shù)值喜最,例如:
$ oclint-json-compilation-database -v -e Pods -e xxxx -- -rc LONG_METHOD=60 -rc LONG_LINE=100
另外當(dāng)我們需要自定義多個(gè)
oclint
參數(shù)時(shí)偎蘸,我們可以將配置寫(xiě)在.oclint文件中
disable-rules: // 不使用的規(guī)則
- LongLine
rulePaths: // oclint校驗(yàn)規(guī)則所在的路徑,Mac端默認(rèn)在/usr/local/lib/oclint/rules瞬内,如果不需要自定義規(guī)則的話(huà)可以不配置此項(xiàng)
- /etc/rules
rule-configurations: // 自定義配置參數(shù)
- key: CYCLOMATIC_COMPLEXITY
value: 15
- key: NPATH_COMPLEXITY
value: 300
output: oclint.xml // 生成的報(bào)告
report-type: xml // 生成的報(bào)告格式支持html禀苦、xml、json等
max-priority-1: 20 // 級(jí)別1的問(wèn)題最大個(gè)數(shù)遂鹊,如果檢測(cè)出的問(wèn)題超過(guò)這個(gè)個(gè)數(shù)就會(huì)自動(dòng)終止
max-priority-2: 40 // 級(jí)別2的問(wèn)題最大個(gè)數(shù)
max-priority-3: 60 // 級(jí)別3的問(wèn)題最大個(gè)數(shù)
enable-clang-static-analyzer: false //
以下是OCLint內(nèi)置支持的72條Rule振乏,可以通過(guò) --list-enabled-rules x
查看
$ oclint --list-enabled-rules x
enabled rules:
- TooManyMethods
- DestructorOfVirtualClass
- DeadCode
- EmptyForStatement
- AvoidDefaultArgumentsOnVirtualMethods
- ProblematicBaseClassDestructor
- MisplacedDefaultLabel
- EmptyFinallyStatement
- CallingProhibitedMethod
- RedundantIfStatement
- CollapsibleIfStatements
- UnnecessaryElseStatement
- ConstantConditionalOperator
- DeepNestedBlock
- AssignIvarOutsideAccessors
- UnnecessaryNullCheckForDealloc
- RedundantNilCheck
- RedundantLocalVariable
- EmptyDoWhileStatement
- UnusedMethodParameter
- BitwiseOperatorInConditional
- ReturnFromFinallyBlock
- MultipleUnaryOperator
- DoubleNegative
- MissingCallToBaseMethod
- EmptyWhileStatement
- ShortVariableName
- ParameterReassignment
- UselessParentheses
- ThrowExceptionFromFinallyBlock
- UnnecessaryDefaultStatement
- HighNcssMethod
- PreferEarlyExit
- MissingBreakInSwitchStatement
- TooManyParameters
- CallingProtectedMethod
- AvoidBranchingStatementAsLastInLoop
- MissingAbstractMethodImplementation
- MissingHashMethod
- MisplacedNullCheck
- MisplacedNilCheck
- UseContainerLiteral
- LongLine
- ForLoopShouldBeWhileLoop
- HighNPathComplexity
- LongMethod
- EmptySwitchStatement
- RedundantConditionalOperator
- EmptyTryStatement
- EmptyCatchStatement
- UseObjectSubscripting
- AvoidPrivateStaticMembers
- EmptyElseBlock
- InvertedLogic
- LongClass
- LongVariableName
- GotoStatement
- BrokenOddnessCheck
- UseNumberLiteral
- TooFewBranchesInSwitchStatement
- UseBoxedExpression
- JumbledIncrementer
- EmptyIfStatement
- BranchDivergence
- MissingDefaultStatement
- HighCyclomaticComplexity
- NonCaseLabelInSwitchStatement
- ConstantIfExpression
- BrokenNullCheck
- BrokenNilCheck
- TooManyFields
- UnusedLocalVariable
如果我們使用.oclint
最終我們將.oclint
放在與compile_commands.json
相同的路徑下,并在該路徑下執(zhí)行命令:
$ oclint-json-compilation-database -v -e Pods
或者直接執(zhí)行命令:
$ oclint-json-compilation-database -e Pods -- -report-type pmd \
-rc=LONG_CLASS=1500 \
-rc=NESTED_BLOCK_DEPTH=5 \
-rc=LONG_VARIABLE_NAME=80 \
-rc=LONG_METHOD=200 \
-rc=LONG_LINE=300 \
-disable-rule ShortVariableName \
-disable-rule ObjCAssignIvarOutsideAccessors \
-disable-rule AssignIvarOutsideAccessors \
-allow-duplicated-violations=false\
-max-priority-1=100000 \
-max-priority-2=100000 \
-max-priority-3=100000 >> oclint.xml
最終會(huì)生成oclint.xml
(也可以自己生成html
格式秉扑,直接查看效果)
Infer
Infer
是Facebook
開(kāi)源的一款代碼掃描軟件,可以分析Objective-C
慧邮,Java
或者C
代碼,報(bào)告潛在的問(wèn)題。任何人都可以使用Infer
檢測(cè)應(yīng)用舟陆,這可以將那些嚴(yán)重的 bug 扼殺在發(fā)布之前误澳,同時(shí)防止應(yīng)用崩潰和性能低下。
- 命令安裝
$ brew install infer
在終端輸入 infer --version
秦躯,驗(yàn)證是否安裝成功忆谓。
Infer
與OCLint
一樣,都是分析compile_commands.json
文件踱承。在compile_commands.json
文件相同路徑下執(zhí)行命令:
# --skip-analysis-in-path 是忽略?huà)呙枘夸?$ infer run --skip-analysis-in-path Pods --keep-going --compilation-database compile_commands.json
注意:命令中一定要有
--keep-going
不然會(huì)有錯(cuò)誤導(dǎo)致無(wú)法進(jìn)行分析倡缠。
另外需要在xcodebuild
命令中添加OTHER_CFLAGS="-DNS_FORMAT_ARGUMENT(A)= -D_Nullable_result=_Nullable"
。
掃描出的結(jié)果會(huì)在工程目錄下的
infer-out
文件中茎活,其中具體的代碼會(huì)以 csv昙沦,txt,json 的格式分別存在對(duì)應(yīng)的文件中载荔。
總結(jié):
OCLint
基本上分析都是一些代碼規(guī)范的問(wèn)題盾饮,Infer
可以檢查出空指針訪問(wèn)、資源泄露以及內(nèi)存泄露。
sonarqube
sonarqube
是一個(gè)提供代碼靜態(tài)分析的平臺(tái)丘损,提供了一套完整的靜態(tài)分析方案普办,包括后端及前端頁(yè)面,可以結(jié)合jenkins
徘钥、gitlab
等平臺(tái)來(lái)進(jìn)行代碼分析衔蹲。sonarqube
分社區(qū)版本和商業(yè)化版本,能掃描多種語(yǔ)言并且開(kāi)源。官網(wǎng)地址吏饿。
因?yàn)槠涞讓釉创a為java
開(kāi)發(fā)的,所以對(duì)java
代碼支持比較完善蔬浙,但是免費(fèi)的社區(qū)版并不支持OC
猪落,所以我們?nèi)绻柚似脚_(tái)的話(huà),有以下兩種方式:
- 開(kāi)源插件sonar-swift
畴博,支持Objective-C
和Swift
/Java
笨忌,支持導(dǎo)入SwiftLint
、Infer
俱病、OCLint
官疲、Lizard
、Fauxpas
工具的掃描分析結(jié)果亮隙。最新v1.6
版本途凫,兼容SonarQube 8.9LTS
版本。該插件是好未來(lái)
研發(fā)團(tuán)隊(duì)研發(fā)并且開(kāi)源溢吻。 - 付費(fèi)使用社區(qū)版plus维费,提供了SonarCFamily for C插件
有官方提供技術(shù)支持,250+的rules可供選擇促王,不可自定義規(guī)則犀盟。
我們將使用開(kāi)源插件方案。
sonar-services(sonarqube)安裝
sonarqube
安裝有兩種方式
- docker 安裝
$ docker pull sonarqube:8.9.7-community
- 下載二進(jìn)制安裝包
選中 8.9.7LTS 社區(qū)版本蝇狼,下載
image
下載完安裝包后阅畴,進(jìn)入bin/macosx-universal-64
目錄。執(zhí)行命令:
$ sh sonar.sh start
控制臺(tái)輸出Started SonarQube
說(shuō)明啟動(dòng)成功迅耘。
在瀏覽器訪問(wèn)http://localhost:9000/
,能打開(kāi)頁(yè)面說(shuō)明啟動(dòng)成功贱枣。
默認(rèn)賬號(hào)為admin,密碼為admin颤专。
注意:如果啟動(dòng)失敗可以去
sonarqube/logs
下查看日志冯事。
image
安裝時(shí),發(fā)現(xiàn)sonarqube 8.9.7版本需要Java 11環(huán)境血公。所以需要先安裝Java 11環(huán)境昵仅。
安裝Java 11:
image
image
啟動(dòng)成功后我們?cè)谧钕旅鏁?huì)看到warning
警告建議我們自己配置數(shù)據(jù)庫(kù),需要說(shuō)明的是SonarQube
如果想持久化保存數(shù)據(jù),是需要依賴(lài)數(shù)據(jù)庫(kù)的摔笤。
SonarQube
默認(rèn)提供H2
存儲(chǔ)够滑,只能暫時(shí)存儲(chǔ)一些小項(xiàng)目結(jié)果,僅為了演示使用吕世。
在conf/sonar.properties
下配置數(shù)據(jù)庫(kù)地址即可彰触。可選 MySQL
命辖、Oracle
况毅、PostgreSQL
。
下面我們就來(lái)配置數(shù)據(jù)庫(kù)(mysql后續(xù)將不再支持):這里我們使用的是PostgreSQL
尔艇,配置參考
PostgreSQL
用Homebrew 執(zhí)行命令安裝PostgreSQL:
$ brew install postgresql //安裝
安裝完數(shù)據(jù)庫(kù)后尔许,啟動(dòng)數(shù)據(jù)庫(kù),執(zhí)行命令:
$ pg_ctl -D /usr/local/var/postgres start //啟動(dòng)
$ createdb //創(chuàng)建數(shù)據(jù)庫(kù)
$ psql //登錄控制臺(tái)
數(shù)據(jù)庫(kù)安裝創(chuàng)建好后终娃,我們需要提供一個(gè)數(shù)據(jù)庫(kù)和賬號(hào)sonarqube
使用味廊。執(zhí)行命令:
CREATE USER sonarqube WITH PASSWORD 'sonarqube';//創(chuàng)建用戶(hù)
CREATE DATABASE sonar OWNER sonarqube;//創(chuàng)建屬于該用戶(hù)的數(shù)據(jù)庫(kù)
創(chuàng)建完成后執(zhí)行命令退出:
\q
然后我們?nèi)?code>sonarqube/conf目錄下編輯sonar.properties
,將數(shù)據(jù)庫(kù)相應(yīng)配置配置完成
sonar.jdbc.username=sonarqube
sonar.jdbc.password=sonarqube
sonar.jdbc.url=jdbc:postgresql://localhost/sonar
編輯完成后在sonarqube/bin/macosx-universal-64/
目錄下執(zhí)行: sh sonar.sh restart
棠耕,此時(shí)警告已經(jīng)消除了余佛。
至此我們的sonarqube
的前端服務(wù)已經(jīng)配置完成了。
漢化包安裝
通過(guò)Github 下載對(duì)應(yīng)版本漢化包jar包插件窍荧。
下載插件放到
/extensions/plugins
目錄下辉巡。重啟sonarqube服務(wù),就可以看到漢化后的界面蕊退。sonar-swift
通過(guò)GitHub 下載對(duì)應(yīng)插件
下載插件放到
/extensions/plugins
目錄下红氯。重啟sonarqube服務(wù),就可以了咕痛。
sonar-scanner
sonar-scanner
用來(lái)掃描本地代碼,并且上傳到SonarQube
平臺(tái)中痢甘。
-
下載安裝地址;按照不同的操作系統(tǒng)選擇不同安裝包即可茉贡。
image - 配置環(huán)境變量:
$ vim ~/.bash_profile
#sonar-scanner for cli
export PATH=$PATH:/Users/csdn/scanner/bin:$PATH
$ source ~/.bash_profile
sonar-scanner
分為兩種使用方式:
- 配置文件方式:
在需要掃描項(xiàng)目根目錄下新建sonar-project.properties
文件塞栅,內(nèi)容如下:
sonar.projectKey=CsdnPlus
sonar.projectName=CsdnPlus
sonar.language=objc
sonar.sources=/Users/csdn/.jenkins/workspace/csdn_build_ios/
sonar.objectivec.workspace=CsdnPlus.xcworkspace
sonar.objectivec.appScheme=CsdnPlus
sonar.sourceEncoding=UTF-8
sonar.junit.reportsPath=sonar-reports/
sonar.objectivec.oclint.report=sonar-reports/oclint.xml
sonar.swift.infer.report=infer-out/report.json
進(jìn)入項(xiàng)目根目錄下,然后輸入sonar-scanner
命令腔丧,執(zhí)行代碼分析放椰。
- 命令行方式:
在命令中設(shè)置了參數(shù):
sonar-scanner -Dsonar.projectKey=CsdnPlus -Dsonar.projectName=CsdnPlus -Dsonar.projectName=CsdnPlus -Dsonar.projectVersion=5.1.0
如果我們要SonarQube忽略一些指定目錄或者文件的掃描,可以在配置中添加sonar.exclusions
例如:
//忽略指定文件目錄或者文件
sonar.exclusions=**/Resource/**,**/*.py
或者可以在命令中設(shè)置參數(shù)愉粤,例如:
sonar-scanner -Dsonar.exclusions=**/Resource/**,**/*.py -Dsonar.projectKey=CsdnPlus -Dsonar.projectName=CsdnPlus -Dsonar.projectName=CsdnPlus -Dsonar.projectVersion=5.1.0
這里的核心便是在上面步驟中由OCLint
生成的oclint.xml
文件與Infer
生成的report.json
砾医,另外注意oclint.xml
必須放至sonar-reports
文件下。report.json
在Infer
生成的infer-out
目錄下衣厘。
命令執(zhí)行成功后如蚜,便可在sonarQube的前端頁(yè)面看到對(duì)應(yīng)的檢測(cè)效果了压恒。
檢測(cè)效果圖:
集成進(jìn)Jenkins
我們項(xiàng)目本身已經(jīng)有自動(dòng)化構(gòu)建服務(wù),所以比較方便错邦。
-
Jenkins項(xiàng)目配置探赫,選項(xiàng)中增加OCLint(可以自己命名)選項(xiàng)
image 構(gòu)建Shell命令中,增加OCLint相關(guān)命令
if [ "$MODE"x = "OCLint"x ]
then
sh /Users/csdn/.jenkins/workspace/csdn_build_ios/fastlane/oclint.sh "$GIT_BRANCH"
fi
- 企業(yè)微信通知, Shell中增加企業(yè)微信機(jī)器人URL
//獲取本機(jī)IP
local_ip=$(ifconfig | grep '\<inet\>'| grep -v '127.0.0.1' | awk '{ print $2}' | awk 'NR==1')
curl 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=31ef53a9-1e97-42c6-9cc7-fb4432bd41f9' \
-H 'Content-Type: application/json' \
-d '
{
"msgtype":"news",
"news":{
"articles":[
{
"title":"SonarQube 靜態(tài)代碼掃描完成",
"url":"http://'${local_ip}':9000/",
"description":"APP名稱(chēng):CSDNAPP\n掃描代碼分支:'$1'",
"picurl":"https://img-bss.csdnimg.cn/202103251639445966.png"
}
]
}
}'
一些有用的
shell
命令獲取APP名稱(chēng):
product_name=`sed -n '/PRODUCT_NAME/{s/PRODUCT_NAME = //;s/;//;s/^[[:space:]]*//;s/\"http://g;p;q;}' ./$myscheme.xcodeproj/project.pbxproj`
獲取APP版本:
version_number=`sed -n '/MARKETING_VERSION/{s/MARKETING_VERSION = //;s/;//;s/^[[:space:]]*//;s/\"http://g;p;q;}' ./$myscheme.xcodeproj/project.pbxproj`
獲取本機(jī)IP地址:
local_ip = $(ifconfig | grep '\<inet\>'| grep -v '127.0.0.1' | awk '{ print $2}' | awk 'NR==1')
- 附上完整
oclint.sh
命令:
#!/bin/bash
COLOR_ERR="\033[1;31m" #出錯(cuò)提示
COLOR_SUCC="\033[0;32m" #成功提示
COLOR_QS="\033[1;37m" #問(wèn)題顏色
COLOR_AW="\033[0;37m" #答案提示
COLOR_END="\033[1;34m" #顏色結(jié)束符
# 尋找項(xiàng)目的 ProjectName
function searchProjectName () {
# maxdepth 查找文件夾的深度
find . -maxdepth 1 -name "*.xcodeproj"
}
function oclintForProject () {
# 預(yù)先檢測(cè)所需的安裝包是否存在
if which xcodebuild 2>/dev/null; then
echo 'xcodebuild exist'
else
echo 'xcodebuild 未安裝撬呢,請(qǐng)安裝Xcode'
fi
if which oclint 2>/dev/null; then
echo 'oclint exist'
else
echo 'oclint 未安裝伦吠,請(qǐng)安裝OCLint'
fi
if which xcpretty 2>/dev/null; then
echo 'xcpretty exist'
else
gem install xcpretty
fi
# 指定編碼
export LANG="zh_CN.UTF-8"
export LC_COLLATE="zh_CN.UTF-8"
export LC_CTYPE="zh_CN.UTF-8"
export LC_MESSAGES="zh_CN.UTF-8"
export LC_MONETARY="zh_CN.UTF-8"
export LC_NUMERIC="zh_CN.UTF-8"
export LC_TIME="zh_CN.UTF-8"
export xcpretty=/usr/local/bin/xcpretty # xcpretty 的安裝位置可以在終端用 which xcpretty找到
searchFunctionName=`searchProjectName`
path=${searchFunctionName}
# 字符串替換函數(shù)。//表示全局替換 /表示匹配到的第一個(gè)結(jié)果替換魂拦。
path=${path//.\//} # ./BridgeLabiPhone.xcodeproj -> BridgeLabiPhone.xcodeproj
path=${path//.xcodeproj/} # BridgeLabiPhone.xcodeproj -> BridgeLabiPhone
myworkspace=$path".xcworkspace" # workspace名字
myscheme=$path # scheme名字
# 清除上次編譯數(shù)據(jù)
if [ -d ./derivedData ]; then
echo -e $COLOR_SUCC'-----清除上次編譯數(shù)據(jù)derivedData-----'$COLOR_SUCC
rm -rf ./derivedData
fi
# xcodebuild clean
xcodebuild -scheme $myscheme -workspace $myworkspace clean
# # 生成編譯數(shù)據(jù)
xcodebuild -scheme $myscheme -workspace $myworkspace -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 12 Pro Max' -configuration Debug GCC_PRECOMPILE_PREFIX_HEADER=YES CLANG_ENABLE_MODULE_DEBUGGING=NO COMPILER_INDEX_STORE_ENABLE=NO OTHER_CFLAGS="-DNS_FORMAT_ARGUMENT(A)= -D_Nullable_result=_Nullable" | tee xcodebuild.log | xcpretty -r json-compilation-database -o compile_commands.json
if [ -f ./compile_commands.json ]; then
echo -e $COLOR_SUCC'編譯數(shù)據(jù)生成完畢'$COLOR_SUCC
else
echo -e $COLOR_ERR'編譯數(shù)據(jù)生成失敗'$COLOR_ERR
return -1
fi
echo -e $COLOR_SUCC'OCLint代碼分析開(kāi)始'$COLOR_SUCC
# 生成報(bào)表
oclint-json-compilation-database -e Pods -- -report-type pmd \
-rc=LONG_CLASS=1500 \
-rc=NESTED_BLOCK_DEPTH=5 \
-rc=LONG_VARIABLE_NAME=80 \
-rc=LONG_METHOD=200 \
-rc=LONG_LINE=300 \
-disable-rule ShortVariableName \
-disable-rule ObjCAssignIvarOutsideAccessors \
-disable-rule AssignIvarOutsideAccessors \
-allow-duplicated-violations=false\
-max-priority-1=100000 \
-max-priority-2=100000 \
-max-priority-3=100000 >> oclint.xml
echo -e $COLOR_SUCC'Infer代碼分析開(kāi)始'$COLOR_SUCC
# --skip-analysis-in-path 是忽略?huà)呙枘夸? infer run --skip-analysis-in-path Pods --keep-going --compilation-database compile_commands.json
product_name=`sed -n '/PRODUCT_NAME/{s/PRODUCT_NAME = //;s/;//;s/^[[:space:]]*//;s/\"http://g;p;q;}' ./$myscheme.xcodeproj/project.pbxproj`
version_number=`sed -n '/MARKETING_VERSION/{s/MARKETING_VERSION = //;s/;//;s/^[[:space:]]*//;s/\"http://g;p;q;}' ./$myscheme.xcodeproj/project.pbxproj`
if [ -f ./oclint.xml -a -f ./infer-out/report.json ]; then
rm compile_commands.json
echo -e $COLOR_SUCC'代碼分析完畢'$COLOR_SUCC
mv oclint.xml sonar-reports/
echo -e $COLOR_SUCC'移動(dòng)至sonar-reports完畢'$COLOR_SUCC
echo -e $COLOR_SUCC'開(kāi)始執(zhí)行sonar-scanner掃描文件'$COLOR_SUCC
echo -e $COLOR_SUCC'版本號(hào):'${version_number}''$COLOR_SUCC
sonar-scanner -Dsonar.projectVersion=$version_number
else
echo -e $COLOR_ERR'分析失敗'$COLOR_ERR
curl 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=31ef53a9-1e97-42c6-9cc7-fb4432bd41f9' \
-H 'Content-Type: application/json' \
-d '
{
"msgtype": "text",
"text": {
"content": "APP名稱(chēng):'${product_name}'\nAPP版本:'${version_number}'\nOCLint分析失敗"
}
}'
return -1
fi
local_ip = $(ifconfig | grep '\<inet\>'| grep -v '127.0.0.1' | awk '{ print $2}' | awk 'NR==1')
curl 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=31ef53a9-1e97-42c6-9cc7-fb4432bd41f9' \
-H 'Content-Type: application/json' \
-d '
{
"msgtype":"news",
"news":{
"articles":[
{
"title":"SonarQube 靜態(tài)代碼掃描完成",
"url":"http://'${local_ip}':9000/",
"description":"APP名稱(chēng):'${product_name}'\nAPP版本:'${version_number}'掃描代碼分支:'$1'",
"picurl":"https://csdn-app.csdn.net/1024store_1024pt.png"
}
]
}
}'
}
oclintForProject $1
-
Jenkins 配置PMD(當(dāng)然有了SonarQube毛仪,PMD就很雞肋了)
image
image
image