SonarQube 9.x集成eslint静态分析前端vue代码;
SonarQube 9.x集成eslint静态分析前端vue代码;
文章目录
前言
因为我们公司前端主用的是vue,在进行sonar代码检测的时候默认使用的是sonar检测规则,经过会议讨论要使用eslint自定义规则来进行检测vue代码;
注:
eslint自定义规则需要修改前端项目下的.eslintrc.js
文件,这里就不赘述了,本篇使用默认的eslint规则,主要是和sonarqube、jenkins进行集成 实现使用eslint自动化分析前端代码;
一、sonar新建"JavaScript"质量配置
sonar在前端的JavaScript校验不支持自行编写规则,只能使用sonar提供的内置规则;
需要注意,把eslint的检查报告作为导入到sonar并不意味着sonar只维护导入的问题,在导入时sonarQube也会根据根据不同语言使用其默认的sonar规则进行扫描检查,最后sonar界面上显示的问题情况是两个数据的合并。
若是两个方式都使用,则会导致开发者本地使用eslint风格校验没问题,但是有些代码却不符合sonar的内置规则,因此需要把sonar的内置规则禁用,只保留eslint检查报告导入的方式。
但是,sonar不允许禁用内置规则,只能通过创建一个空规则,然后把规则作为项目默认规则即可。
基本流程:sonar对内置所有的前端语言都创建一个空规则,然后把eslint检测报告导入到sonar进行问题管理和统计。
#将新建的质量规则设为默认,不使用sonar自带的检测规则
二、前端项目引入eslint插件导出检测报告
需要在前端项目中的package.json文件"scripts"处添加以下脚本
{
"scripts": {
"lint:report": "eslint ./src -f json -o report.json --ext .js,.vue,.css,.scss || exit 0"
}
}
- .src:表示eslint校验的文件在src目录;
- -f json:表示校验的内容结构以json形式导出报告;
- -o report.json:表示导出的报告将写入到根目录的report.json文件中;
- –ext .js,.vue,.css,.scss:表示校验的文件扩展名为js、vue、css和scss文件,如果有其他文件可以继续添加;
配置如下:
三、导入eslint报告到sonarqube系统中
默认的sonar代码检测配置为如下:
默认的sonar代码检测配置集成到jenkins
如下:
集成到jenkins可参考SonarQube 9.x与Jenkins进行集成并扫描后端java以及前端vue代码;
需要将上面默认的配置修改为
npm install
npm run lint:report
sonar-scanner \
-Dsonar.projectKey=${Gitee_Code_Project} \
-Dsonar.sources=. \
-Dsonar.host.url=${SonarQube_URL} \
-Dsonar.login=${SonarQube_Secret} \
-Dsonar.eslint.reportPaths=report.json
首先执行npm instal
l用于安装eslint等包
,接着执行npm run lint:report
导出eslint的报告内容,最后添加一个reportPaths
参数,把eslint错误报告文件导入到SonarQube系统中。
jenkins配置如下:
修改好后再次构建项目查看日志会包含以下内容
...
INFO: ------------- Run sensors on module gotone-admin
INFO: Load metrics repository
INFO: Load metrics repository (done) | time=24ms
INFO: Sensor CSS Metrics [cssfamily]
INFO: Sensor CSS Metrics [cssfamily] (done) | time=111ms
INFO: Sensor CSS Rules [cssfamily]
INFO: 32 source files to be analyzed
INFO: 32/32 source files have been analyzed
INFO: Sensor CSS Rules [cssfamily] (done) | time=1473ms
INFO: Sensor JaCoCo XML Report Importer [jacoco]
INFO: 'sonar.coverage.jacoco.xmlReportPaths' is not defined. Using default locations: target/site/jacoco/jacoco.xml,target/site/jacoco-it/jacoco.xml,build/reports/jacoco/test/jacocoTestReport.xml
INFO: No report imported, no coverage information will be imported by JaCoCo XML Report Importer
INFO: Sensor JaCoCo XML Report Importer [jacoco] (done) | time=3ms
INFO: Sensor JavaScript analysis [javascript]
INFO: 8 source files to be analyzed
INFO: 8/8 source files have been analyzed
INFO: Sensor JavaScript analysis [javascript] (done) | time=6364ms
INFO: Sensor TypeScript analysis [javascript]
...
INFO: ------------- Run sensors on project
INFO: Sensor Zero Coverage Sensor
INFO: Sensor Zero Coverage Sensor (done) | time=29ms
INFO: SCM Publisher SCM provider for this project is: git
INFO: SCM Publisher 8 source files to be analyzed
INFO: SCM Publisher 8/8 source files have been analyzed (done) | time=280ms
INFO: CPD Executor 9 files had no CPD blocks
INFO: CPD Executor Calculating CPD for 102 files
INFO: CPD Executor CPD calculation finished (done) | time=62ms
INFO: Analysis report generated in 75ms, dir size=835.9 kB
INFO: Analysis report compressed in 261ms, zip size=463.9 kB
INFO: Analysis report uploaded in 72ms
INFO: ANALYSIS SUCCESSFUL, you can browse http://internal.sonarqube.wonderlink.cc/dashboard?id=gotone-admin
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
去sonarqube系统上查看检测详情
完整的jenkinsfile文件内容如下:
pipeline {
agent any
tools{
nodejs 'node-14.19.2'
}
//全局变量
environment {
//Harbor仓库地址以及以及镜像所在Harbor项目
Harbor_Registry_URL= 'rexxxx.net'
Harbor_Registry_Cert= 'HQT_Harbor_Cert'
Fat_Harbor_Registry_Project= 'hqt-registry-fat' //-开发仓库
Pro_Harbor_Registry_Project= 'hqt-registry-pro'
//gitee代码仓库地址以及项目名称
Gitee_Registry_URL= 'https://xxxxdmin.git'
Gitee_Code_Project= 'gotxxxxin'
//-SonqrQube信息
SonarQube_URL= 'http://intxxxxnk.cc'
SonarQube_Secret= 'bb2fb7c8ad5exxxxxxxbb9653'
//项目的Dockerfile所在目录
Dockerfile_Directory_path= '/hqtxxxx/Dockerfile'
//项目所在kubernetes命名空间(环境)
Kubernetes_Project_Namespace_fat= 'fat' //本地环境
Kubernetes_Project_Namespace_fat1= 'fat1'
}
parameters {
gitParameter branch: '', branchFilter: 'origin/(.*)', defaultValue: 'master', description: '选择拉取代码的分支', name: 'Branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'GitParameterDefinition'
booleanParam description: '是否进行代码质量检测;', name: 'IS_CODE_DETECTION'
choice choices: ['faxxxxone.com', 'guxxxxne.com', 'zhangxxxxne.com', 'wuxxxxne.com', 'shaxxxxne.com', 'liuxxxxone.com', 'zouxxxxne.com'], description: '''********************************************
* 请在下方选择接收检测报告的邮箱 *
* 请在下方选择接收检测报告的邮箱 *
********************************************''', name: 'RECEIVE_MAILBOX'
choice(choices: ['fat1','fat','prod'], description: '请选择需要部署的环境', name: 'deploy_env')
booleanParam description: '是否部署到fat环境;', name: 'IS_DEPLOY_FAT'
booleanParam description: '是否部署到fat1环境;', name: 'IS_DEPLOY_FAT1'
booleanParam description: '是否将本次构建镜像推送到pro线上仓库;', name: 'Push_Image_To_Pro_Registry'
choice(name:'Replicase', choices:'1\n3\n5', description:'请选择副本数(如果对此参数不清楚的话,默认即可);' )
}
stages {
stage('拉取代码') {
steps {
checkout([$class: 'GitSCM', branches: [[name: "${params.Branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: 'Pull-Code_Gitee_fandaoshuai', url: "${Gitee_Registry_URL}"]]])
}
}
stage('git merge') {
steps {
sh """
git remote set-url origin https://fanxxxx:fdsxxxxx@gitee.com/ciecinfo/${env.Gitee_Code_Project}.git
git checkout ${params.Branch}
git fetch --all && git reset --hard origin/${params.Branch}
git pull
git checkout master
git pull
git checkout ${params.Branch}
git merge master
"""
//git checkout refs/remotes/origin/${params.Branch}
}
}
stage('init vars '){
agent any
steps {
script{
echo "======================"
echo "$deploy_env"
switch("$deploy_env"){
case "fat":
println "This is fat"
//OPERATION_URL = "http://internal.fat-1.operation-server.wonderlink.cc"
env_vue = "fat"
break
case "prod":
println "This is prod"
//OPERATION_URL = "http://merchant-server.cngotone.com"
env_vue = "prod"
break
case "fat1":
println "This is fat"
//OPERATION_URL = "http://internal.fat-1.operation-server.wonderlink.cc"
env_vue = "fat1"
break
default:
echo "############ fat Job name ############"
println "This is fat"
//OPERATION_URL = "http://merchant-server.ciecdev.com"
env_vue = "fat"
break
}
}
}
}
stage('质量检测') {
when { expression { return params.IS_CODE_DETECTION } }
steps {
script{
scannerHome = tool 'sonar-scanner'
}
withSonarQubeEnv('SonarQube') {
sh"""
npm install
npm run lint:report
${scannerHome}/bin/sonar-scanner \
-Dsonar.projectKey=${Gitee_Code_Project} \
-Dsonar.sources=. \
-Dsonar.host.url=${SonarQube_URL} \
-Dsonar.login=${SonarQube_Secret} \
-Dsonar.eslint.reportPaths=report.json
cd .scannerwork
ls
echo "${JOB_NAME}-第${BUILD_NUMBER}次代码扫描报告" > mail.txt
echo "项目名称 : ${JOB_NAME}" >> mail.txt
echo "构建编号 : 第${BUILD_NUMBER}次构建" >> mail.txt
echo "代码路径 : ${Gitee_Registry_URL}" >> mail.txt
echo "构建日志 : ${BUILD_URL}consoleText" >> mail.txt
echo "构建Url : ${JOB_URL}" >> mail.txt
echo "工作目录 : ${WORKSPACE}" >> mail.txt
ls
cat mail.txt | mail -s "SonarQube 检测报告" -a *.pdf ${RECEIVE_MAILBOX}
"""
}
}
}
stage('代码编译') {
steps {
sh """
npm cache clear --force
npm config set registry https://registry.npm.taobao.org
npm run build:${env_vue}
"""
//npm run build:${env_vue}
}
}
stage('构建并上传到测试仓库') {
steps {
withCredentials([usernamePassword(credentialsId: "${Harbor_Registry_Cert}", passwordVariable: 'password', usernameVariable: 'username')]) {
sh """
cp -pr /hqtbj/hqtwww/Dockerfile/${JOB_NAME}/Dockerfile ${WORKSPACE}/Dockerfile
docker login -u ${username} -p ${password} ${env.Harbor_Registry_URL}
docker build -t ${Harbor_Registry_URL}/${Fat_Harbor_Registry_Project}/${Gitee_Code_Project}:F-${BUILD_NUMBER}-${BUILD_TIMESTAMP} -f ${Dockerfile_Directory_path} .
docker push ${Harbor_Registry_URL}/${Fat_Harbor_Registry_Project}/${Gitee_Code_Project}:F-${BUILD_NUMBER}-${BUILD_TIMESTAMP}
"""
}
}
}
//-部署到fat环境
stage('部署到测试环境') {
when { expression { return params.IS_DEPLOY_FAT } }
steps {
sh "kubectl set image deployment.apps/${Gitee_Code_Project} ${Gitee_Code_Project}=${Harbor_Registry_URL}/${Fat_Harbor_Registry_Project}/${Gitee_Code_Project}:F-${BUILD_NUMBER}-${BUILD_TIMESTAMP} -n ${Kubernetes_Project_Namespace_fat} --kubeconfig=/root/.kube/aliyun-fat.config"
sh "kubectl scale deployment.apps/${Gitee_Code_Project} --replicas=${params.Replicase} -n ${Kubernetes_Project_Namespace_fat} --kubeconfig=/root/.kube/aliyun-fat.config"
}
}
//-部署到fat1环境
stage('部署到测试-1环境') {
when { expression { return params.IS_DEPLOY_FAT1 } }
steps {
sh "kubectl set image deployment.apps/${Gitee_Code_Project} ${Gitee_Code_Project}=${Harbor_Registry_URL}/${Fat_Harbor_Registry_Project}/${Gitee_Code_Project}:F-${BUILD_NUMBER}-${BUILD_TIMESTAMP} -n ${Kubernetes_Project_Namespace_fat1} --kubeconfig=/root/.kube/aliyun-fat.config"
sh "kubectl scale deployment.apps/${Gitee_Code_Project} --replicas=${params.Replicase} -n ${Kubernetes_Project_Namespace_fat1} --kubeconfig=/root/.kube/aliyun-fat.config"
}
}
stage('将本次构建的镜像传到pro仓库') {
when { expression { return params.Push_Image_To_Pro_Registry } }
steps {
withCredentials([usernamePassword(credentialsId: "${Harbor_Registry_Cert}", passwordVariable: 'password', usernameVariable: 'username')]) {
sh """
docker login -u ${username} -p ${password} ${env.Harbor_Registry_URL}
docker tag ${Harbor_Registry_URL}/${Fat_Harbor_Registry_Project}/${Gitee_Code_Project}:F-${BUILD_NUMBER}-${BUILD_TIMESTAMP} ${Harbor_Registry_URL}/${Pro_Harbor_Registry_Project}/${Gitee_Code_Project}:P-${BUILD_NUMBER}-${BUILD_TIMESTAMP}
docker push ${Harbor_Registry_URL}/${Pro_Harbor_Registry_Project}/${Gitee_Code_Project}:P-${BUILD_NUMBER}-${BUILD_TIMESTAMP}
"""
}
}
}
stage('清除本地镜像') {
steps {
sh "docker rmi -f ${Harbor_Registry_URL}/${Fat_Harbor_Registry_Project}/${Gitee_Code_Project}:F-${BUILD_NUMBER}-${BUILD_TIMESTAMP}"
sh "docker rmi -f ${Harbor_Registry_URL}/${Pro_Harbor_Registry_Project}/${Gitee_Code_Project}:P-${BUILD_NUMBER}-${BUILD_TIMESTAMP}"
}
}
}
}
更多推荐
所有评论(0)