SonarQube+Jenkins+GitLab配置使用

2022/05/24

参考文章来源于SonarQube+Jenkins+GitLab配置使用

参考文章来源于Jenkins+Gitlab+SonarQube 代码质量管理集成

参考文章来源于8.4版本的SonarQube上使用p3c-pmd调研

参考文章来源于Gitlab集成Sonarqube实现自动检测代码并发送报告给提交者

参考文章来源于gitlab配合Sonar实现提交后自动代码检测

文章目录

前言

最近使用Rancher搭建SonarQube,要和Jenkins与GitLab一起使用,在此记录,如有错误,希望可以指出。


一、环境准备

1.1 SonarQube安装配置

https://blog.csdn.net/qq_43610090/article/details/114880220

官方文档:https://docs.sonarqube.org/latest/setup/install-server/

1.2 Jenkins安装配置

https://blog.csdn.net/xishaoguo/article/details/88577459

官方文档:https://www.jenkins.io/zh/doc/book/installing/

1.3 GitLab安装配置

https://www.cnblogs.com/linyufeng/p/11672534.html

官方文档:https://docs.gitlab.com/ee/install/

1.4 GitLab runner安装配置

参考文档:Docker安装Gitlab和Gitlab-Runner并实现项目的CICD

参考文档:基于 GitLab+SonarQube 搭建自动化代码检测平台

参考文档:Linux 安装并注册gitlab-runner

二、Jenkens连接GitLab

2.1 系统配置

Jenkins连接gitlab需要配置access token,所以先在gitlab上生成access token,后将该token配置在Jenkins上。(access token只需配置一次,后续每个工程直接使用即可)

2.1.1获取连接token

登陆gitlab,在用户头像下拉图标,选择“Setting”

选择AccessToken,输入“Name”和“Expries at”,勾选“api”;点击“Create personal access token”,生成access token,记录下来。

2.1.2配置系统Gitlab连接信息

登陆Jenkins,点击“系统管理”->“系统设置”-> “gitlab”,配置如下:

Connetction name:连接名称,随便填写;

URL:gitlab的访问地址;

Credentials:鉴权凭证,即添加access token的地方,记得选择为GitLab Access Token;

2.2 项目设置

在项目设置中会指定使用的gitlab连接

2.2.1 源码管理相关配置

URL:工程的gitlab地址,本例中使用的是用户名密码鉴权的http访问;

Credentials:此处填写访问gitlab项目的用户名和密码。添加方式与之前系统配置的类似,只是类型为用户名密码方式。

这样Jenkins上使用gitlab配置完毕

三、SonarQube连接Jenkens

3.1 SonarQube相关设置

3.1.1 开启强制用户身份验证

登录sonarqube并开启服务,进入配置–>配置–>权限,开启Force user authentication

3.1.2 生成token

点击登录用户的图标,进入我的账号–>安全,填写新令牌名称,点击生成,复制生成的token保存到一个文档中(token只出现一次,需要及时复制)

3.2 Jenkins相关设置

3.2.1 在Jenkins安装sonarqube插件

进入Jenkins–>系统管理–>管理插件–>可选插件,输入sonar检索,选择sonarqube scanner for Jenkins插件安装

3.2.2 配置Jenkins上的sonarqube

进入Jenkins–>系统管理–>系统设置,找到sonarqube servers,填写相关信息,name自己起,url要填写完全,token使用前面复制的token,保存。

3.2.3 配置sonar-scanner

进入设置中的全局工具配置

配置sonar-scanner,这里sonar-scanner要选择对应兼容的版本

3.2.4 配置项目构建

返回Jenkins的项目设置中,在构建中进行配置

其中:

sonar.projectKey,sonar.projectName(注意:社区版sonarqube不支持分支管理,这里建议写分支名称)

sonar.projectVersion是版本(pom.xml中的版本信息)

sonar.sources是需要sonar分析的项目工程中的文件路径

sonar.exclusions是排除文件类型

sonar.projectKey=项目示例123
sonar.projectName=项目示例123
sonar.projectVersion=1.0-SNAPSHOT
sonar.sourceEncoding=UTF-8
sonar.language=java
sonar.sources=./
sonar.java.binaries=./
sonar.exclusions=**/*.doc,**/*.docx,**/*.sql,**/*.excel,**/*.js,**/*.html,**/*.css,**/*.less,**/*.scss,**/*.zip

以及构建环境勾选准备SonarQube Scanner环境:

保存应用之后立即构建,查看运行结果,如果出现SonarQube的图标并可以点击查看,说明成功。

点击SonarQube,即跳转到SonarQube页面查看分析

四、扩展

4.1 SonarQube集成GitLab用户验证

4.1.1 GitLab设置Application

使用管理员账户登录GitLab,点击个人账户——>setting——>Application,设置Application的名称以及回调链接,勾选api和read_user

  • 这里Redirect URI是最重要的参数,后面的/oauth2/callback/gitlab是固定的

    http://你的地址及端口/oauth2/callback/gitlab>

保存Application后,记下ApplicationID和Secret,在配置SonarQube时要用

4.1.2 SonarQube下载插件

使用管理员帐号登录Sonarqube,下载GitLab Auth插件,这里要选择兼容的版本

下载好插件后,点击配置——>配置——>GitLab,填入GitLab的地址和刚才的数据

注销掉当前登录用户,用GitLab的方式登录

进行授权,登录成功

4.2 添加阿里P3C规则

虽然gitbub上已有集成了p3c的sonar-pmd,但版本是2.6,不支持7.x版本的sonar;这里对sonar-pmd的改造基于网上GitHub上已有的sonar-p3c-pmd

gitbub上已有的sonar-p3c-pmd地址:https://github.com/mrprince/sonar-p3c-pmd

4.2.1 下载PMD项目

选择合适的PMD版本,这里选择的是sonar-pmd-3.2,可参考版本对应表

4.2.2 项目改造

项目改造参考这篇文章,这里不在赘述 sonarqube中添加p3c-pmd整合阿里java开发规范

4.2.3 应用在SonarQube

将改造好的项目打包,将jar包放在SonarQube插件的目录中,重启SonarQube服务

在SonarQube的规则中即可看到P3C规则

4.3 自动检测代码并发送报告给提交者

1、在项目根目录创建.gitlab-ci.yml文件

配置 .gitlab-ci.yml 文件内容:



stages:
  - sonarqube_scan
  - feedback_to_gitlab
  - sendmail

sonarqube_scan_job:
  stage: sonarqube_scan
  only:
    - master
  script:
    #    - mvn clean package
    - sonar-scanner -Dsonar.projectName=$CI_PROJECT_NAME -Dsonar.projectKey=$CI_PROJECT_NAME  -Dsonar.language=java -Dsonar.host.url=sonarQube web 地址 -Dsonar.login=登录名 -Dsonar.password=密码  -Dsonar.sources=./  -Dsonar.java.binaries=./  -Dsonar.exclusions=**/*.doc,**/*.docx,**/*.sql,**/*.excel,**/*.js,**/*.html,**/*.css,**/*.less,**/*.scss,**/*.zip
  tags:
    - cms-runner

#执行 SonarQube 分析,并将检测结果反馈至 GitLab
sonarqube_gitlab_comment:
  stage: feedback_to_gitlab
  only:
    - master
  script:
    - sonar-scanner -Dsonar.projectName=$CI_PROJECT_NAME -Dsonar.projectKey=$CI_PROJECT_NAME  -Dsonar.language=java -Dsonar.host.url=sonarQube web 地址 -Dsonar.login=登录名 -Dsonar.password=密码  -Dsonar.sources=./  -Dsonar.java.binaries=./  -Dsonar.exclusions=**/*.doc,**/*.docx,**/*.sql,**/*.excel,**/*.js,**/*.html,**/*.css,**/*.zip -Dsonar.analysis.mode=preview -Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA -Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME -Dsonar.gitlab.project_id=$CI_PROJECT_ID
  tags:
    - cms-runner

sendmail_job:
  stage: sendmail
  script:
    - echo $GITLAB_USER_EMAIL
    - echo $CI_PROJECT_NAME
    - echo $CI_COMMIT_REF_NAME
    - python3 /home/codescann/nodocker/sonarqube_api.py $CI_PROJECT_NAME $CI_COMMIT_REF_NAME $GITLAB_USER_EMAIL
  tags:
    - cms-runner




2、sonarqube_api.py代码如下:


#
# -*- coding: UTF-8 -*-
 
import requests,json,sys,time
import smtplib
from email.mime.text import MIMEText
from email.header import Header
 
from_addr='TODO'   #邮件发送账号
qqCode='TODO'   #授权码
smtp_server='smtp.exmail.qq.com' #授权服务器地址
smtp_port=465                    #授权服务器端口号
 
def getSonarinfo(component):
    sonar_url="http://sonarQube web 地址/api/measures/component?component={0}&metricKeys=bugs,vulnerabilities,code_smells,ncloc,new_bugs,new_code_smells,new_lines,new_vulnerabilities,new_lines_to_cover".format(component,)
    print(sonar_url)
    sonar_token ="TODO"
    session = requests.Session()
    session.auth = sonar_token,''
    call = getattr(session, 'get')
    res = call(sonar_url)
    binary = res.content
    result = json.loads(binary)
    print(result)
    result_dict = {}
    if "errors" in result:
        for info_dict in result["errors"]:
            if "msg" in info_dict:
                print(info_dict["msg"])
                return result_dict
    for info_dict in result["component"]["measures"]:
        if "value" in info_dict:
            result_dict[info_dict["metric"]] = info_dict["value"]
        else:
            result_dict[info_dict["metric"]] = info_dict["period"]["value"]
    return result_dict
 
def sendmail(to_addrs,mail_msg):
    stmp=smtplib.SMTP_SSL(smtp_server,smtp_port)
    stmp.login(from_addr,qqCode)
    message = MIMEText(mail_msg, 'html', 'utf-8')   
    message['From'] = Header("管理员", 'utf-8')  
    message['To'] = Header("Me", 'utf-8')   
    subject = 'Gitlab代码安全检测结果'
    message['Subject'] = Header(subject, 'utf-8')  
 
    try:
        stmp.sendmail(from_addr, to_addrs, message.as_string())
    except Exception as e:
        sys.exit('邮件发送失败--' + str(e))
    print ('邮件发送成功')
 
if __name__ == '__main__':
    project = sys.argv[1]
    branch = sys.argv[2]
    user_email = sys.argv[3]
    time.sleep(10)
    sonarqube_data = getSonarinfo(component=branch,)
    if not sonarqube_data:
        print ("sonarQube 扫描分支不存在,退出执行")
        sys.exit(0)
    project_url = "http://sonarQube web 地址/dashboard?id={0}".format(branch,)
    
 
    html_text = """
<
    <html lang="en">
        <head>
            <title></title>
                <meta charset="utf-8">
        </head>
    <body>
        <div class="page" style="margin-left: 30px">
            <h3>{user_email}, 你好!</h3>
            <h3> 本次提交代码检查结果如下:</h3>
            <h3> 项目名称:{project} </h3>
            <h3> 分支:{branch} </h3>
            <h3>一、总体情况</h3>
                <ul>
                    <li style="font-weight:bold;">
                        项目扫描代码行数: &nbsp; <span style="color:blue">{lines} </span>,
                        bugs: &nbsp;<span style="color:red">{bugs}</span>,
                        漏洞: &nbsp;<span style="color:red">{vulnerabilities}</span>,
                        坏味道: &nbsp; <span style="color:red">{code_smells}</span>
                    </li>
                    <li style="font-weight:bold;">
                    <h4>本次提交</h4>
                        新增覆盖率-新代码: &nbsp; <span style="color:blue">{new_lines_to_cover} </span>,
                        新增重复率-新代码: &nbsp; <span style="color:blue">{new_lines} </span>,
                        新增代码Bugs: &nbsp;<span style="color:red">{new_bugs}</span>,
                        新增代码漏洞: &nbsp;<span style="color:red">{new_vulnerabilities}</span>,
                        新增代码异味: &nbsp; <span style="color:red">{new_code_smells}</span>
                    </li>
                    <li style="font-weight:bold;margin-top: 10px;">
                        sonarQube web 登陆地址:&nbsp;
                        <a style="font-weight:bold;"
                           href={project_url}>{project_url}
                        </a>
                    </li>
                </ul>
             
</div>
</body>
</html>
""".format(user_email=user_email,project=project,branch=branch,lines=sonarqube_data["ncloc"],bugs=sonarqube_data["bugs"],vulnerabilities=sonarqube_data["vulnerabilities"],code_smells=sonarqube_data["code_smells"],new_lines_to_cover=sonarqube_data["new_lines_to_cover"],new_lines=sonarqube_data["new_lines"],new_bugs=sonarqube_data["new_bugs"],new_vulnerabilities=sonarqube_data["new_vulnerabilities"],new_code_smells=sonarqube_data["new_code_smells"],project_url=project_url)
            
    #print(html_text)
    sendmail(to_addrs=user_email,mail_msg=html_text)



3、实现效果

(1)模拟用户提交代码,新建测试文件填写测试字符,然后commit提交。

(2)在GitLab,CI/CD–>Pipelines,可以查看运行状态,点击进入可查看详情。

(3)完成后,用户邮箱收到代码检测报告。

(4)在sonar可以查看到对应的项目检测情况。

4.4 sonarQube Web Api

数据库定义 ,但 不建议 直接查询DB,使用Sonar提供的Web_Api,默认在SonarQube服务的/web_api下可以查看到提供的所有API信息,如http://localhost:9000/web_api/api/project_analyses

查询示例1

查询示例2


对应的属性含义参考:

数据来源方法:

  1. 获取项目总数:

http://example.sonar.com/api/components/search_projects?pageIndex=2&ps=500

2.获取最近一次的分析结果时间:

API: /api/components/search_projects Para: ps? #大小,最大500 f? # example: http://example.sonar.com/api/components/search_projects?ps=50&f=analysisDate result:

{
"paging":{
"pageIndex":1,
"pageSize":50,
"total":2337
},
"organizations":[

    ],
    "components":Array[50],
    "facets":[
    ]
}

# 其中components中包含项目name 和时间戳,如
{
"organization":"default-organization",
"id":"AW0j4CH4yaNpfFfxGPl2",
"key":"projectGroup1:projectNameExample",
"name":"projectGroup1:projectNameExample",
"isFavorite":false,
"analysisDate":"2019-11-27T20:37:05+0800",
"tags":[],
"visibility":"public"
}

  1. 根据component,查询不同的metrics: API: /api/measures/search Para: projectKeys? # 逗号分隔多个项目 metricKeys? # 查询的各个标准 example: http://example.sonar.com/api/measures/search?projectKeys=projectGroup1:projectNameExample&metricKeys=alert_status,bugs,reliability_rating,vulnerabilities,security_rating,code_smells,sqale_rating,duplicated_lines_density,coverage,ncloc,ncloc_language_distribution

result:

    
    {
    "measures": [
        {
            "metric": "alert_status",
            "value": "OK",
            "component": "projectGroup1:projectNameExample"
        },
        {
            "metric": "bugs",
            "value": "6",
            "component": "projectGroup1:projectNameExample",
            "bestValue": false
        },
        {
            "metric": "code_smells",
            "value": "185",
            "component": "projectGroup1:projectNameExample",
            "bestValue": false
        },
        {
            "metric": "coverage",
            "value": "0.0",
            "component": "projectGroup1:projectNameExample",
            "bestValue": false
        },
        {
            "metric": "duplicated_lines_density",
            "value": "64.6",
            "component": "projectGroup1:projectNameExample",
            "bestValue": false
        },
        {
            "metric": "ncloc",
            "value": "14566",
            "component": "projectGroup1:projectNameExample"
        },
        {
            "metric": "ncloc_language_distribution",
            "value": "java=4756;js=9582;web=228",
            "component": "projectGroup1:projectNameExample"
        },
        {
            "metric": "reliability_rating",
            "value": "3.0",
            "component": "projectGroup1:projectNameExample",
            "bestValue": false
        },
        {
            "metric": "security_rating",
            "value": "2.0",
            "component": "projectGroup1:projectNameExample",
            "bestValue": false
        },
        {
            "metric": "sqale_rating",
            "value": "1.0",
            "component": "projectGroup1:projectNameExample",
            "bestValue": true
        },
        {
            "metric": "vulnerabilities",
            "value": "27",
            "component": "projectGroup1:projectNameExample",
            "bestValue": false
        }
    ]
}
  1. 查询增量内容

项目新增的内容:

http://example.sonar.com/api/measures/component?additionalFields=metrics,periods&component=projectGroup1:projectNameExample&metricKeys=alert_status,quality_gate_details,bugs,new_bugs,reliability_rating,new_reliability_rating,vulnerabilities,new_vulnerabilities,security_rating,new_security_rating,code_smells,new_code_smells,sqale_rating,new_maintainability_rating,sqale_index,new_technical_debt,coverage,new_coverage,new_lines_to_cover,tests,duplicated_lines_density,new_duplicated_lines_density,duplicated_blocks,ncloc,ncloc_language_distribution,projects,new_lines


接口调用可以使用Basic的认证方式:参考

  • Use token
  • curl -u admin:SuPeRsEcReT "https://sonar.mydomain.com/api/resources?resource=com.mydomain.project:MY&metrics=ncloc&format=json"
  • curl -u THIS_IS_MY_TOKEN: https://sonarqube.com/api/user_tokens/search
  • note that the colon after the token is required in curl to set an empty password

Post Directory