所有工具下载地址
http://download.csdn.net/download/ly13237009762/11995111
window系统+Jdk1.8+mysql5.6+python3.6
工具包 | 描述 | 下载地址(未精确到版本号) |
---|---|---|
sonarqube-7.4.zip | sonarqube核心包 | https://www.sonarqube.org/downloads/ |
sonar-scanner-2.8.zip | 代码扫描器 | https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/ |
jenkins-2.190.2.zip | jenkins核心 | http://mirrors.jenkins.io/war-stable/ |
SonarQube需要连接mysql,并且mysql需要开启innodb存储引擎,查询是否开启的sql语句是SHOW ENGINES。mysql5.6默认开启了innodb,那么直接在数据库中创建以下数据库,Sql如下:
创建数据库sonar:
CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE USER 'sonar' IDENTIFIED BY 'sonar';
GRANT ALL ON sonar.* TO 'sonar'@'%' IDENTIFIED BY 'sonar';
GRANT ALL ON sonar.* TO 'sonar'@'localhost' IDENTIFIED BY 'sonar';
FLUSH PRIVILEGES;
本项目解压到了D:\jenkins_sonar\sonarqube-7.4,目录结构如图2-1
图2-1
2.3修改SonarQube配置文件
conf目录下的sonar.properties增加以下配置,主要是连接数据库的配置和tomcat端口。
sonar.jdbc.username=root
sonar.jdbc.password=root
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance
sonar.web.port=9999
因为SonarQube需要jdk1.8或者以上才能启动,如图2-3所示wrapper.conf指定jdk版本为1.8。
图2-3
下载汉化插件sonar-l10n-zh-plugin-1.24.jar放到extentions下的plugins目录下,下载地址https://github.com/SonarQubeCommunity/sonar-l10n-zh/releases
打开图示windows批处理文件,用本机浏览器输入localhost:9999能正常进入首页,则如果命令行出现SonarQube is up说明SonarQube配置成功。
把解压后得到的bin目录加入到环境变量中,图示目录是D:\jenkins_sonar\sonar-scanner-3.2.0.1227-windows\bin。(不会配置的百度)
在一个项目根目录下创建sonar-project.properties配置文件,并添加以下配置,以目录D:\jenkins_sonar\WebStarter-security为例。
注意:是在需要检查的项目根目录下
#sonarqube服务器地址
sonar.host.url=http://localhost:9999
#sonarqube用户名默认就是admin
sonar.login=admin
#sonarqube密码
sonar.password=admin默认就是admin
#项目唯一标识(不能出现重复)
sonar.projectKey=WebStarter-security
#项目名称
sonar.projectName=WebStarter-security
#源代码目录
sonar.sources=./
#编译生成的class文件的所在目录
sonar.java.binaries=target
#版本号
sonar.projectVersion=1.0
sonar.language=java
#源代码文件编码
sonar.sourceEncoding=UTF-8
用cmd进入项目根目录D:\jenkins_sonar\WebStarter-security,执行sonar-scanner命令,出现以下提示则说明项目代码扫描成功。
浏览器进入http://localhost:9999/projects,右上角进行登录,默认管理员用户名和密码都是admin。
点击项目名进入对应的项目,出现以下扫描结果,就是成功扫描代码了。
从官网下载到的Jenkins是一个.msi文件,安装这个文件,在安装目录里面有个Jenkins.war,把它放入到tomcat的webapps里面,然后启动,就正常启动Jenkins了。
因为我设置的tomcat的端口是9998,所以用浏览器输入localhost:9998/jenkins就能进入jenkins,根据页面提示找到密码并输入进去系统。如图4-1
第一次进去会提示安装插件,先跳过,等会统一安装,跳过后出现添加用户的界面。我添加了一个用户名admin,密码为123456的用户。如图4-2
图4-2
然后进入到实例配置中把localhost改为ip,如图4-3
图4-3
最后进入到Jenkins首页,如图4-4
图4-4
修改tomcat配置
首次登录后会有以下提示,需要修改tomcat的server.xml 加入URIEncoding=”UTF-8”。
在jenkins首页左边导航栏,点击Manage jenkins,然后找到二级导航Manage Plugins,然后点击可选插件,最后右上角上面搜索需要的插件,点击直接安装就可以。
需要安装以下插件,安装完成需要重启jenkins。
插件名称 | 插件描述 |
---|---|
SonarQube Scanner for Jenkins | jenkins集成SonarQube 所需要的 |
Subversion Plug-in | Svn插件 |
Localization: Chinese (Simplified) Svn插件 | 汉化Jenkins插件 |
Email Extension Plugin | 发送邮件的插件 |
配置刚才安装在好的插件
Sonarqube配置
Jenkins访问地址配
测试邮箱配置是否成功
集成jdk和扫描器,导航如图
4.4安装python3.6
jenkins集成sonarqube时,需要将sonarqube检查的代码结果发送到指定邮箱,需要使用python脚本。
安装python-3.6.0-amd64.exe,并勾上把python添加到环境变量。如果无法自动添加,可以手动添加python根目录到环境变量。
安装python操作mysql的包,用cmd命令输入python -m pip install PyMySQL
提示successfully则安装成功,
安装jinja2模块,用cmd命令输入pip install jinja2,提示successfully则安装成功,
如图
提示:192.168.150.129服务器上面有python2.7,但是不支持发送邮件的脚本,所以我安装了python3.6和原来的2.7共存,并手动添加了python3.6的环境变量,把python3.6安装根目录的python.exe改成了python3.exe。所以129上面,使用cmd输入python命令执行的是python2.7,使用python3执行的是python3.6。
文档中脚本会执行python3命令。
安装好插件,先重启Jenkins,进入首页,点击新建项目,然后按照箭头进行设置,如图
然后进入输入项目表单界面,如图
然后点击添加svn账号
Svn检出策略
构建触发器,定期构建一次代码
Poll SCM:定时检查源码变更,如果有更新就checkout最新code下来,然后执行构建动作。
Build periodically:周期进行项目构建(源码是否发生变化没有关系)
H H * * 1 (每星期1构建一次)
H 8 * * * (每天8:00 必须build一次源码)
构建环境,选中无
构建
构建参数
projectKey,projectName:唯一标识,一般填写项目名,需要和python脚本后面的参数一致。
sources:是扫描代码的路径,./表示项目所有代码。
login,password:对应sonar的管理员账号和密码
java.binaries:编译后的字节码
sonar.projectKey=nkspt
sonar.projectName=nkspt
sonar.sources=./
sonar.projectVersion=1.0
sonar.language=java
sonar.sourceEncoding=UTF-8
sonar.java.binaries=./
sonar.login=admin
sonar.password=admin
构建脚本
进入到脚本目录,并运行脚本,脚本名称后面需要加参数(项目名)。
cd /d D:\jenkins_sonar\scripts
Python3命令
python3 sonar.py nkspt
脚本如下
注意:其中cd /d 后面是脚本的路径
nkspt是sonarqube项目名称,建议用一致的。
import pymysql,os,sys
from jinja2 import FileSystemLoader,Environment
def select_project_uuid(project_name):
db = pymysql.connect(host="localhost", port=3306, user="root", passwd="root", db="sonar")
cursor = db.cursor()
select_p_uuid="SELECT project_uuid,kee FROM projects WHERE `name`= '%s'" %(project_name)
cursor.execute(select_p_uuid)
result = cursor.fetchone()
p_uuid = result[0]
projectKey = result[1]
db.close()
return(p_uuid, projectKey)
def select_total_info(p_uuid):
total_info=[]
db = pymysql.connect(host="localhost", port=3306, user="root", passwd="root", db="sonar")
cursor = db.cursor()
select_p_links = "SELECT text_value FROM project_measures WHERE text_value LIKE 'java=%' and component_uuid=" + "\'" + p_uuid + "\'"
cursor.execute(select_p_links)
p_links = cursor.fetchone()[0].split("=")[1]
sql_info = "SELECT count(*) FROM issues WHERE project_uuid='%s' and issue_type =%s"
for leak in [2,3,1]:
search_data = sql_info %(p_uuid, leak)
cursor.execute(search_data)
total_info.append(cursor.fetchone()[0])
db.close()
return p_links,total_info
def select_bugs(p_uuid):
bugs=[]
db = pymysql.connect(host="localhost", port=3306, user="root", passwd="root", db="sonar")
cursor = db.cursor()
sql_info = "SELECT count(*) FROM issues WHERE project_uuid='%s' and issue_type =2 AND severity ='%s'"
for leak in ['BLOCKER','CRITICAL',"MAJOR",'MINOR','INFO']:
search_data=sql_info % (p_uuid,leak)
cursor.execute(search_data)
bugs.append(cursor.fetchone()[0])
db.close()
return bugs
def select_leaks(p_uuid):
leaks=[]
db = pymysql.connect(host="localhost", port=3306, user="root", passwd="root", db="sonar")
cursor = db.cursor()
sql_info = "SELECT count(*) FROM issues WHERE project_uuid='%s' and issue_type =3 AND severity ='%s'"
for leak in ['BLOCKER','CRITICAL',"MAJOR",'MINOR','INFO']:
search_data=sql_info % (p_uuid,leak)
cursor.execute(search_data)
leaks.append(cursor.fetchone()[0])
db.close()
return leaks
def select_bad_tastes(p_uuid):
tastes=[]
db = pymysql.connect(host="localhost", port=3306, user="root", passwd="root", db="sonar")
cursor = db.cursor()
sql_info="SELECT count(*) FROM issues WHERE project_uuid='%s' and issue_type =1 AND severity ='%s'"
for leak in ['BLOCKER','CRITICAL',"MAJOR",'MINOR','INFO']:
search_data=sql_info % (p_uuid,leak)
cursor.execute(search_data)
tastes.append(cursor.fetchone()[0])
db.close()
return tastes
curpath = os.getcwd()
table_tem_name="table.html"
def generate_errmsg_table(s_lines="", total_data=[], bugs=[],leaks=[],tastes=[],report_url=""):
env = Environment(loader=FileSystemLoader(curpath, 'utf-8'))
template = env.get_template(table_tem_name)
html_content = (template.render(lins=s_lines,total_data=total_data, bugs=bugs,leaks = leaks,tastes=tastes,report_url=report_url))
fh = open(report_html_path, 'w')
fh.write(html_content)
fh.close()
project_name = sys.argv[1]
report_html_path="report\\"+project_name+".html"
p_uuid, projectKey=select_project_uuid(project_name)
s_lines,total_data=select_total_info(p_uuid)
bugs=select_bugs(p_uuid)
leaks=select_leaks(p_uuid)
tastes=select_bad_tastes(p_uuid)
report_url="http://192.168.150.129:9999/dashboard?id=%s" %(projectKey)
generate_errmsg_table(s_lines,total_data,bugs,leaks,tastes,report_url)
执行脚本,需要一个模(mú)板table.html,
注意模(mú)板需要和脚本放在同一目录
代码如下
<!DOCTYPE html>
<head>
<meta charset="GB2312"">
<body>
<p style="font-weight:bold;">一、总体情况:</p>
<ul>
<li style="font-weight:bold;">整体运行情况:扫描代码行数:<span style="color:blue">{{lins}}</span>, bugs:<span style="color:red">{{total_data[0]}}</span>, 漏洞:<span style="color:red">{{total_data[1]}}</span>, 坏味道:<span style="color:red">{{total_data[2]}}</span></li>
<li style="font-weight:bold;">URL地址:<a style="font-weight:bold;" href={{report_url}} >{{report_url}}</a></li>
<li style="font-weight:bold;">用户名:登陆用户名为您的名字拼音,密码为123456</a></li>
</ul>
<p style="font-weight:bold;">二、错误信息详情:</p>
<table border="1" cellpadding="10" width="540" height="120">
<tr ><th></th><th>阻断</th><th>严重</th><th>主要</th><th>次要</th><th>提示</th><th>总数</th></tr>
<tr bgcolor=#ECFFFF><td>bugs</td><td align="center">{{bugs[0]}}</td><td align="center">{{bugs[1]}}</td><td align="center">{{bugs[2]}}</td><td align="center">{{bugs[3]}}</td><td align="center">{{bugs[4]}}</td><td align="center" style="color:red">{{total_data[0]}}</td></tr>
<tr bgcolor=#D2E9FF><td>漏洞</td><td align="center">{{leaks[0]}}</td><td align="center">{{leaks[1]}}</td><td align="center">{{leaks[2]}}</td><td align="center">{{leaks[3]}}</td><td align="center">{{leaks[4]}}</td><td align="center" style="color:red">{{total_data[1]}}</td></tr>
<tr bgcolor=#ECFFFF><td>坏味道</td><td align="center">{{tastes[0]}}</td><td align="center">{{tastes[1]}}</td><td align="center">{{tastes[2]}}</td><td align="center">{{tastes[3]}}</td><td align="center">{{tastes[4]}}</td><td align="center" style="color:red">{{total_data[2]}}</td></tr>
</table>
<br></br>
</body>
</html>
点击高级设置
增加一个触发器,点击allways
再点高级
最后的操作。
保存
4.4测试项目
首页找到刚才创建的项目,并点击build now,完成项目构建。
构建过程会产生一个构建状态,点击进去
然后查看控制台输出
出现success则说明项目构建成功,然后查看邮件是否正常成功发送到邮箱。最后访问sonarqube系统查看项目扫描信息是否存在。
SonarQube默认是所有项目都是公开的,即使用户未登录,也能查看扫描结果,所以需要给项目分配给用户,让指定的用户能够访问。
先创建群组并把需要的用户添加到群组,如下图
点击一个项目,然后进入权限配置,如下图
如下图,把项目权限改成私有
设置用户的权限或者群组的权限。
5.2 Jenkins创建中文名称的项目
在使用Jenkins创建项目使用中文时,发现钉钉邮箱无法接收到邮件,而其他平台的邮箱能够正常接收,目前原因未知,所以建议,在创建项目时,尽量不要出现中文字符。
5.3 Jenkins第一次构建项目会失败
如图,第一次构建有时会无法正常执行python脚本,是正常情况,因为sonarqube进行代码扫描时,需要把扫描的结果保存到数据库,而此时,往数据库插入的数据尚未提交。
解决的方法是重新构建一次。
5.4 sonarqube添加checkstyle规则
使用CheckStyle代码规则配置文件
注意:这种方法只有新建一个质量配置时才能用,质量配置创建好后,就不能利用配置文件来配置代码规则了。
按照上面两个图,填写好相关信息后,点击创建按钮。这里有几个问题需要注意下:
问题一 配置文件不能以开头,否则点击创建按钮时会有如下错误提示:
因此要把此标签去掉,直接以标签开头,如下图所示:
问题二 配置文件中不能有重复的规则,否则点击创建按钮时,会有报错提示
问题三 配置文件中不能有规则模板(规则模板后面介绍),当配置文件中有规则模板,点击创建按钮时,会有报错提示,如下图,看不到具体错误信息,可以打开f12查询HTTP请求。
问题4:激活checkstyle规则。
搜索规则
创建自定义规则
填写规则表单,根据实际需求。
点击活动激活规则
5.5同时使用checkstyle规则和自带规则
进去创建好的规则
继承自带规则
5.6 sonarqube进行代码标记
当扫描的结果,进行标记的时候,会将这个结果从未处理加入到其他类别,如图我点击误判则将结果存放到误判的分类,下次扫描也不会影响本次标记的结果。
1.标记为解决,如果下次扫描还未解决,则会重开,也就是把结果从解决中移动到未处理中。
2.标记为误报,如下图,如果发现检查结果误判,可以点击误判,则下次不会检查此bug。
4.标记为不会修复,即使下次扫描还未解决,也不会出现在未处理中。
5.标记为确认,只是告诉开发人员,此代码需要进行修改,无其他作用。
总之,除了点击解决,但是下次扫描还未解决,会重新加入到未处理,其他都不会重新加入到未处理。
5.7安装翻译插件
Sonarqube的扫描结果的提示信息是没有办法汉化的,解决的方法是安装谷歌浏览器的一个插件,效果如图。
安装插件教程
第一步,打开拓展程序
第二步,打开开发者模式,并安装插件,如图
第三步,选择插件文件夹
第四步,配置插件
第五步,切换翻译引擎
选中百度翻译。
选中要翻译的文字,并点击翻译
查看翻译结果
5.8关于无法正确显示新增bug的问题
如图,当未配置版本号或者配置的版本号不发生改变时,无法正确显示新增的问题。
解决的方法是使用动态版本号如图
sonar.projectVersion= S V N R E V I S I O N 其 中 SVN_REVISION 其中 SVNREVISION其中SVN_REVISION是Jenkins内置变量,可以用表达式直接获得.
5.9关于扫描结果会发送上一次的
正常情况下,扫描结果应该是发送当前扫描结果的,但是有时候会发送上一次的,造成这一现象的问题是Jenkins只是调用了sonar扫描的api之后,就直接执行下一步脚本发送了,而没有去判断结果有没有出来。
解决方法,python脚本延长等待时间如图。
6.Jenkins发送检查结果到钉钉
6.1创建钉钉群机器人
在钉钉群中,点击管理群助手
添加机器人
添加关键字,当标题或者内容具有关键字的消息,才会被发送,所以添加代码为关键字。
得到webhook地址。
6.2使用自定义机器人
获取到 Webhook 地址后,用户可以使用任何方式向这个地址发起 HTTP POST 请求,即可实现给该群组发送消息。注意,发起POST请求时,必须将字符集编码设置成 UTF-8。
发送消息类型如下图
6.3使用python脚本发送消息
Jenkins设置
由于我的 Jenkins 跑在 window 平台,执行脚本需要加到 Post build task 批处理中。(需要安装 Post build task plugin)
如图设置运行脚本即可。