天天看点

Mac-Sonar系统执行代码分析

Mac-Sonar系统配置可以参考Mac-Sonar系统配置

一、JS/Java代码扫描配置

1、在sonar创建项目

Mac-Sonar系统执行代码分析
Mac-Sonar系统执行代码分析

2、在项目根目录创建sonar-project.properties

2.1 js 的项目配置

js/sonar-project.properties

# 项目key配置
 sonar.projectKey=com.xx.jstest
# 项目工程名称
 sonar.projectName=jstest
# 工程版本号
sonar.projectVersion=1.0
# 需要扫描的目录,也可以是制定文件'src/person2.js,src/person3.js'
sonar.sources=src
# sonar地址,sonar-scanner中配置了就行,此处配不配置都行
#sonar.host.url=http://127.0.0.1:9000

# 不设置则默认分析多种语言, 此处为js
sonar.language = js
           

2.2 Android 的项目配置

android/sonar-project.properties

# 项目key配置
sonar.projectKey=com.xx.android
# 项目名称
sonar.projectName=android
# 工程版本号
sonar.projectVersion=1.0

# 需要扫描的目录,也可以是制定文件
sonar.sources=app/src/main/java/com/example/zw/androidlearndemo/MainActivity.java
# 二进制文件
sonar.java.binaries=app/build/intermediates

# sonar地址,sonar-scanner中配置了就行,此处配不配置都行
#sonar.host.url=http://127.0.0.1:9000

# 不设置则默认分析多种语言
sonar.language = java
           

3、进入项目根目录执行

sonar-scanner
           

二、 iOS 代码扫描配置

1、iOS 代码扫描需要一些工具

1.1、OCLint 的下载和安装(Issues-代码规则)

brew tap oclint/formulae   
brew install oclint
           

1.2、xcpretty(Tests-测试)

xctool现已被xcodebuild和xcpretty取代

安装步骤如下

git clone [https://github.com/Backelite/xcpretty.git](https://github.com/Backelite/xcpretty.git)  --找一个文件夹存放xcpretty的源码
cd xcpretty
git checkout fix/duration_of_failed_tests_workaround 
gem build xcpretty.gemspec 
sudo gem install --both xcpretty-0.2.2.gem
           

1.3、slather (Code coverage-代码覆盖率)

要求安装版本高于 2.1.0 (Xcode7之前的版本使用gcovr,Xcode7以后选用 slather

)

gem install slather --如果ruby版本低于2.1.0,则需要更新ruby
           

1.4、lizard(Complexity-复杂性)

lizard(ci上的版本1.12.15)

sudo pip install lizard
           

2、 iOS 的项目配置

ios/sonar-project.properties

# 目录名称最好和项目名称保持一致 Test -> Test.xcodeproj,否则会出现检测不出来问题代码的问题
sonar.projectKey=com.xx.ios
# 决定了在sonar服务器上显示的名称
sonar.projectName=ios
sonar.projectVersion=1.0
sonar.language=objc

# Project description
sonar.projectDescription=Fake description

# Path to source directories 工程文件目录, 也可以是制定文件
sonar.sources=ios/ViewController.h,ios/ViewController.m
# Path to test directories (comment if no test) 测试文件目录
#sonar.tests=

#sonar.objectivec.simulator=platform=iOS Simulator,name=iPhone 6,OS=9.2

# 二选一
sonar.objectivec.project=ios.xcodeproj
#sonar.objectivec.workspace=xx.xcworkspace

# Scheme to build your application
sonar.objectivec.appScheme=ios
# Scheme to build and run your tests (comment following line of you don't have any tests)
sonar.objectivec.testScheme=iosTests
 
 # Encoding of the source code
sonar.sourceEncoding=UTF-8

# JUnit report generated by run-sonar.sh is stored in sonar-reports/TEST-report.xml
# Change it only if you generate the file on your own
# The XML files have to be prefixed by TEST- otherwise they are not processed 
# sonar.junit.reportsPath=sonar-reports/
#sonar.objectivec.junit.reportsPath=TEST-report.xml

# Cobertura report generated by run-sonar.sh is stored in sonar-reports/coverage.xml
# Change it only if you generate the file on your own
#sonar.objectivec.coverage.reportPattern=sonar-reports/coverage.xml
#sonar.objectivec.cobertura.reportPath=sonar-reports/coverage-SuYun.xml

# OCLint report generated by run-sonar.sh is stored in sonar-reports/oclint.xml
# Change it only if you generate the file on your own
#sonar.objectivec.oclint.reportPath=sonar-reports/oclint.xml
sonar.objectivec.oclint.report=build/sonar-reports/oclint.xml


# Paths to exclude from coverage report (tests, 3rd party libraries etc.)
# sonar.objectivec.excludedPathsFromCoverage=pattern1,pattern2
# 排除的路径,使用正则匹配
sonar.objectivec.excludedPathsFromCoverage=.*Tests.*,.*Specs.*
#,*.plist,*.json,.*Specs.*

# Project SCM settings
#sonar.scm.enabled=true
# sonar.scm.url=scm:git:https://...
# sonar地址,sonar-scanner中配置了就行,此处配不配置都行
#sonar.host.url=http://127.0.0.1:9000

#sonar.scm.provider=svn
           

3、 执行检查

run-sonar.sh

#!/bin/bash
## INSTALLATION: script to copy in your Xcode project in the same directory as the .xcodeproj file
## USAGE: ./run-sonar.sh
## DEBUG: ./run-sonar.sh -v
## WARNING: edit your project parameters in sonar-project.properties rather than modifying this script
#

trap "echo 'Script interrupted by Ctrl+C'; stopProgress; exit 1" SIGHUP SIGINT SIGTERM

function startProgress() {
	while true
	do
    	echo -n "."
	    sleep 5
	done
}

function stopProgress() {
	if [ "$vflag" = "" -a "$nflag" = "" ]; then
		kill $PROGRESS_PID &>/dev/null
	fi
}

function testIsInstalled() {

	hash $1 2>/dev/null
	if [ $? -eq 1 ]; then
		echo >&2 "ERROR - $1 is not installed or not in your PATH"; exit 1;
	fi
}

function readParameter() {
	
	variable=$1
	shift
	parameter=$1
	shift

	eval $variable="\"$(sed '/^\#/d' sonar-project.properties | grep $parameter | tail -n 1 | cut -d '=' -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')\""
}

# Run a set of commands with logging and error handling
function runCommand() {

	# 1st arg: redirect stdout 
	# 2nd arg: command to run
	# 3rd..nth arg: args
	redirect=$1
	shift

	command=$1
	shift
	
	if [ "$nflag" = "on" ]; then
		# don't execute command, just echo it
		echo
		if [ "$redirect" = "/dev/stdout" ]; then	
			if [ "$vflag" = "on" ]; then
				echo "+" $command "[email protected]"
			else
				echo "+" $command "[email protected]" "> /dev/null"
			fi
		elif [ "$redirect" != "no" ]; then
			echo "+" $command "[email protected]" "> $redirect"
		else
			echo "+" $command "[email protected]"
		fi
		
	elif [ "$vflag" = "on" ]; then
		echo

		if [ "$redirect" = "/dev/stdout" ]; then	
			set -x #echo on
			$command "[email protected]"
			returnValue=$?	
			set +x #echo off			
		elif [ "$redirect" != "no" ]; then
			set -x #echo on
			$command "[email protected]" > $redirect
			returnValue=$?	
			set +x #echo off			
		else
			set -x #echo on
			$command "[email protected]"
			returnValue=$?	
			set +x #echo off			
		fi
		
		if [[ $returnValue != 0 && $returnValue != 5 ]] ; then
			stopProgress
			echo "ERROR - Command '$command [email protected]' failed with error code: $returnValue"
			exit $returnValue
		fi
	else
		echo "--------------------------------"
		echo $command
		echo "[email protected]"
		if [ "$redirect" = "/dev/stdout" ]; then	
			$command "[email protected]" > /dev/null
		elif [ "$redirect" != "no" ]; then
			$command "[email protected]" > $redirect
		else
			$command "[email protected]"
		fi

        returnValue=$?
		if [[ $returnValue != 0 && $returnValue != 5 ]] ; then
			stopProgress
			echo "ERROR - Command '$command [email protected]' failed with error code: $returnValue"
			exit $?
		fi

	
		echo	
	fi	
}

## COMMAND LINE OPTIONS
vflag=""
nflag=""
oclint="on"
while [ $# -gt 0 ]
do
    case "$1" in
    -v)	vflag=on;;
    -n) nflag=on;;
	-nooclint) oclint="";;	    
	--)	shift; break;;
	-*)
        echo >&2 "Usage: $0 [-v]"
		exit 1;;
	*)	break;;		# terminate while loop
    esac
    shift
done

# Usage OK
echo "Running run-sonar.sh..."

## CHECK PREREQUISITES

# xctool, gcovr and oclint installed
# testIsInstalled xctool
testIsInstalled xcpretty
#testIsInstalled gcovr
testIsInstalled oclint

# sonar-project.properties in current directory
if [ ! -f sonar-project.properties ]; then
	echo >&2 "ERROR - No sonar-project.properties in current directory"; exit 1;
fi

## READ PARAMETERS from sonar-project.properties

# Your .xcworkspace/.xcodeproj filename
workspaceFile=''; readParameter workspaceFile 'sonar.objectivec.workspace'
projectFile=''; readParameter projectFile 'sonar.objectivec.project'
# Source directories for .h/.m files
srcDirs=''; readParameter srcDirs 'sonar.sources'
# The name of your application scheme in Xcode
appScheme=''; readParameter appScheme 'sonar.objectivec.appScheme'

# The name of your test scheme in Xcode
testScheme=''; readParameter testScheme 'sonar.objectivec.testScheme'
# The file patterns to exclude from coverage report
excludedPathsFromCoverage=''; readParameter excludedPathsFromCoverage 'sonar.objectivec.excludedPathsFromCoverage'

if [ "$vflag" = "on" ]; then
 	echo "Xcode workspace file is: $workspaceFile"
 	echo "Xcode project file is: $projectFile"
 	echo "Xcode application scheme is: $appScheme"
 	echo "Xcode test scheme is: $testScheme"
 	echo "Excluded paths from coverage are: $excludedPathsFromCoverage" 	
fi

if [[ $projectFile != "" ]]; then
	#statements
	# 设置XCode的签名方式为手动签名
	echo "-----设置自动签名, projectFile: $projectFile \n"
	sed -i "" "s%\ProvisioningStyle.*%\ProvisioningStyle = Manual;%g" "${projectFile}/project.pbxproj"
	# 删除TeamID设置
	sed -i "" "s%\DevelopmentTeam.*%\ %g" "${projectFile}/project.pbxproj"
	sed -i "" "s%\DEVELOPMENT_TEAM.*%\ %g" "${projectFile}/project.pbxproj"
fi

if [[ "$workspaceFile" != "" ]] ; then
	# 17/03/01 修改: 将证书描述文件设置改成模拟器设置
	xcodebuildCmdPrefix="xcodebuild -workspace $workspaceFile -scheme ${appScheme} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' ONLY_ACTIVE_ARCH=NO -configuration Release "
else
	xcodebuildCmdPrefix="xcodebuild -project $projectFile -scheme ${appScheme} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' ONLY_ACTIVE_ARCH=NO -configuration Release"
fi	



# Check for mandatory parameters
if [ -z "$projectFile" -o "$projectFile" = " " ]; then

	if [ ! -z "$workspaceFile" -a "$workspaceFile" != " " ]; then
		echo >&2 "ERROR - sonar.objectivec.project parameter is missing in sonar-project.properties. You must specify which projects (comma-separated list) are application code within the workspace $workspaceFile."
	else
		echo >&2 "ERROR - sonar.objectivec.project parameter is missing in sonar-project.properties (name of your .xcodeproj)"
	fi
	exit 1
fi
if [ -z "$srcDirs" -o "$srcDirs" = " " ]; then
	echo >&2 "ERROR - sonar.sources parameter is missing in sonar-project.properties. You must specify which directories contain your .h/.m source files (comma-separated list)."
	exit 1
fi
if [ -z "$appScheme" -o "$appScheme" = " " ]; then
	echo >&2 "ERROR - sonar.objectivec.appScheme parameter is missing in sonar-project.properties. You must specify which scheme is used to build your application."
	exit 1
fi



## SCRIPT

# Start progress indicator in the background
if [ "$vflag" = "" -a "$nflag" = "" ]; then
	startProgress &
	# Save PID
	PROGRESS_PID=$!
fi

# Create sonar-reports/ for reports output
if [[ ! (-d "build/sonar-reports") && ("$nflag" != "on") ]]; then
	if [ "$vflag" = "on" ]; then
		echo 'Creating directory sonar-reports/'
	fi
	mkdir build/sonar-reports
	if [[ $? != 0 ]] ; then
		stopProgress
    	exit $?
	fi
fi

# Extracting project information needed later
echo -n 'Extracting Xcode project information'
#runCommand /dev/stdout $xctoolCmdPrefix -scheme "$appScheme" clean
#runCommand /dev/stdout $xctoolCmdPrefix -scheme "$appScheme" -reporter json-compilation-database:compile_commands.json build
#runCommand /dev/stdout $xcodebuildCmdPrefix clean

xcodebuild clean

export LC_ALL="en_US.UTF-8"
if [[ "$workspaceFile" != "" ]] ; then
	xcodebuild -workspace "${workspaceFile}" -scheme "${appScheme}" -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' ONLY_ACTIVE_ARCH=NO -configuration Release  build | tee xcodebuild.log | xcpretty -r json-compilation-database --output compile_commands.json
else
	echo "${projectFile}--${appScheme}"
	xcodebuild -project "${projectFile}" -scheme "${appScheme}" -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' ONLY_ACTIVE_ARCH=NO -configuration Release  build | tee xcodebuild.log | xcpretty -r json-compilation-database --output compile_commands.json
fi

#  ---- 单元测试 与 覆盖率 部分 ----
# Unit tests and coverage
# if [ "$testScheme" = "" ]; then
# 	echo 'Skipping tests as no test scheme has been provided!'
	
# 	# Put default xml files with no tests and no coverage...
# 	echo "<?xml version='1.0' encoding='UTF-8' standalone='yes'?><testsuites name='AllTestUnits'></testsuites>" > sonar-reports/TEST-report.xml
# 	echo "<?xml version='1.0' ?><!DOCTYPE coverage SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-03.dtd'><coverage><sources></sources><packages></packages></coverage>" > sonar-reports/coverage.xml
# else

# 	echo -n 'Running tests using xctool'	
# 	# runCommand sonar-reports/TEST-report.xml $xctoolCmdPrefix -scheme "$testScheme" -reporter junit GCC_GENERATE_TEST_COVERAGE_FILES=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES test
# 	# ctf:这个命令出错, 用下面的命令代替
# 	$xctoolCmdPrefix -scheme "$testScheme" -reporter junit:TEST-report.xml GCC_GENERATE_TEST_COVERAGE_FILES=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES test

# 	echo -n 'Computing coverage report'

# 	# We do it for every xcodeproject (in case of workspaces)

# 	# Extract the path to the .gcno/.gcda coverage files
# 	echo $projectFile | sed -n 1'p' | tr ',' '\n' > tmpFileRunSonarSh
# 	while read projectName; do
	
# 		coverageFilesPath=$(grep 'command' compile_commands.json | sed 's#^.*-o \\/#\/#;s#",##' | grep "${projectName%%.*}.build" | awk 'NR<2' | sed 's/\\\//\//g' | sed 's/\\\\//g' | xargs -0 dirname)
# 		if [ "$vflag" = "on" ]; then
# 			echo
# 			echo "Path for .gcno/.gcda coverage files is: $coverageFilesPath"
# 		fi

# 		# Build the --exclude flags
# 		excludedCommandLineFlags=""
# 		if [ ! -z "$excludedPathsFromCoverage" -a "$excludedPathsFromCoverage" != " " ]; then
# 			echo $excludedPathsFromCoverage | sed -n 1'p' | tr ',' '\n' > tmpFileRunSonarSh2
# 			while read word; do
# 				excludedCommandLineFlags+=" --exclude $word"
# 			done < tmpFileRunSonarSh2
# 			rm -rf tmpFileRunSonarSh2
# 		fi
# 		if [ "$vflag" = "on" ]; then
# 			echo "Command line exclusion flags for gcovr is:$excludedCommandLineFlags"
# 		fi
	
# 		# Run gcovr with the right options
# 		echo "coverageFilesPath is: $coverageFilesPath"
# 		echo "excludedCommandLineFlags is: $excludedCommandLineFlags"
# 		runCommand "sonar-reports/coverage-${projectName%%.*}.xml" gcovr -r . "$coverageFilesPath" $excludedCommandLineFlags --xml 

# 	done < tmpFileRunSonarSh
# 	rm -rf tmpFileRunSonarSh
	
# fi

#  ---- 单元测试 与 覆盖率 部分 ----	

if [ "$oclint" = "on" ]; then

	# OCLint
	echo -n 'Running OCLint...'
	
	# Build the --include flags
	currentDirectory=${PWD##*/}
	includedCommandLineFlags=""
	echo "$srcDirs" | sed -n 1'p' | tr ',' '\n' > tmpFileRunSonarSh
	while read word; do
		includedCommandLineFlags+=" --include .*/${currentDirectory}/${word}"
	done < tmpFileRunSonarSh
	rm -rf tmpFileRunSonarSh
	if [ "$vflag" = "on" ]; then
		echo
		echo -n "Path included in oclint analysis is:$includedCommandLineFlags"
	fi
	
	# Run OCLint with the right set of compiler options
    maxPriority=10000
	# runCommand no oclint-json-compilation-database $includedCommandLineFlags -- -max-priority-1 $maxPriority -max-priority-2 $maxPriority -max-priority-3 $maxPriority -rc LONG_LINE=150 -report-type pmd -o sonar-reports/oclint.xml
	oclint-json-compilation-database \
 	-v \
	-- \
	-report-type pmd -o build/sonar-reports/oclint.xml \
	-max-priority-1=10000 -max-priority-2=10000 -max-priority-3=10000 \
	-rc LONG_METHOD=300 \
	-rc LONG_VARIABLE_NAME=50 \
	-rc LONG_CLASS=3000 \
	-rc NCSS_METHOD=300 \
	-rc NESTED_BLOCK_DEPTH=8 \
	#oclint-json-compilation-database -e Pods -- -stats -verbose -report-type=html -o=oclint.html -max-priority-1=99999 -max-priority-2=99999 -max-priority-3=99999 -rc LONG_LINE=200 -rc LONG_METHOD=100 -rc LONG_VARIABLE_NAME=40 -disable-rule=BrokenOddnessCheck -disable-rule=VerifyProhibitedCall -disable-rule=VerifyProtectedMethod -disable-rule=SubclassMustImplement -disable-rule=BaseClassDestructorShouldBeVirtualOrProtected -disable-rule=DestructorOfVirtualClass -disable-rule=ParameterReassignment -disable-rule=AvoidDefaultArgumentsOnVirtualMethods -disable-rule=AvoidPrivateStaticMembers -disable-rule=TooManyParameters

else
	echo 'Skipping OCLint (test purposes only!)'
fi

# SonarQube
echo -n 'Running SonarQube using sonar-scanner'
#runCommand /dev/stdout sonar-runner
sonar-scanner
	
# Kill progress indicator
stopProgress

exit 0
           

直接进入项目根目录执行

sh run-sonar.sh

即可

最后感谢大佬的帮助: https://github.com/ChenTF/iOS-sonarShell