4 Java与Jenkins和SonarQube
如图在Manage Jenkins/Tools配置
如图在Manage Jenkins/Tools配置
在Manage Jenkins System
在Manage Jenkins System
在Jerkins中配置JUnit环境的步骤如下。
1)如下配置pom.xml文件。
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven-compiler-plugin-version>2.3.2</maven-compiler-plugin-version>
</properties>
…
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
…
</plugin>
</plugins>
</build>
…
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
2)安装Jenkins JUnit插件,如图所示。
安装Jenkins JUnit插件
3)书写Pipeline脚本:
pipeline {
agent any
stages {
stage('Build'){
steps {
bat "mvn clean test"
}
}
}
post{
always{
junit testResults:"**/target/surefire-reports/*.xml"
}
}
}
Pipeline脚本的基本架构如下:
pipeline {
agent any
tools{
//工具名 '工具标识'
} // tools为可选项
stages {
stage('StageName1'){
steps {
…
}
}
stage('StageName2'){
steps {
…
}
}
…
stage('StageNamen'){
steps {
…
}
}
}
post{//事后处理,比如展示测试报告
always{
}
}
}
4)查看JUnit测试报告,如图所示。
Jenkins JUnit测试报告
Allure 是一个轻量级、灵活且多语言的测试报告工具,用于生成美观、交互式的测试报告。它最初由 Yandex 团队开发,现在已成为开源项目。
1.多语言支持:支持 Java、Python、JavaScript、Ruby、PHP、.NET 等多种编程语言
2.丰富的可视化:提供直观的图表和图形展示测试结果
3.高度可定制:可以添加步骤、附件、描述等信息增强报告
4.历史趋势:支持保存历史记录并展示测试趋势
5.集成友好:可与 Jenkins、TeamCity 等 CI 工具集成
·测试分类:按特性、故事、严重程度等维度组织测试
·步骤记录:详细记录测试执行步骤
·附件支持:可附加截图、日志、视频等
·环境信息:记录测试执行环境
·缺陷跟踪:与问题跟踪系统集成
1.在测试框架中添加 Allure 适配器
2.执行测试并生成原始数据
3.使用 Allure 命令行工具生成 HTML 报告
在Jerkins中配置Allure环境的步骤如下。
1) 安装Allure软件,将bin目录设为path
C:\Users\xiang>allure --version
2.34.1
2)安装Jenkins Allure插件,如图所示。
安装Jenkins Allure插件
3)选择菜单“Manage Jenkins→Global Tool Configuration”,根据所示进行配置。
4)选择菜单“Manage Jenkins→Configure System”,按照图所示进行配置。
5)配置pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version> <!-- 或更高稳定版本 -->
<configuration>
<argLine>${surefireArgLine}</argLine>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<include>**/*Test.java</include>
<include>**/Test*.java</include>
<include>**/*Tests.java</include>
<include>**/*TestCase.java</include>
</includes>
<systemProperties>
<property>
<name>allure.results.directory</name>
<value>${project.build.directory}/allure-results</value>
</property>
<property>
<name>allure.link.issue.pattern</name>
<value>https://your-issue-tracker.com/issue/{}</value>
</property>
</systemProperties>
</configuration>
…
注意
<property>
<name>allure.results.directory</name>
<value>${project.build.directory}/allure-results</value>
</property>
<property>
<name>allure.link.issue.pattern</name>
<value>https://your-issue-tracker.com/issue/{}</value>
</property>
以及
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>2.29.1</version>
<scope>test</scope>
</dependency>
6)书写Pipeline脚本:
pipeline {
agent any
tools{
maven 'mvn-3.9.6'
}
stages{
stage('junit'){
steps {
bat "mvn clean test"
}
}
}
post{
always{
junit testResults:"**/target/surefire-reports/*.xml"
script{
allure([
includeProperties:false,
jdk:'',
properties:[],
reportBuildPolicy:'ALWAYS',
results:[[path:'target/surefire-reports']]
])
}
}
}
}
其中,maven 'mvn-3.9.6'为配置的Maven Name值,表示使用maven工具。script后面的代码表示测试完毕展示Allure报告。关于Allure的具体配置,可以查看网上的资料。
7)运行完毕,如图所示,单击“Allure Report”展示Allure报告。
Allure JUnit 报告
JaCoCo (Java Code Coverage) 是一个开源的 Java 代码覆盖率分析工具,广泛用于测量单元测试对源代码的覆盖程度。
1)多维度覆盖率分析:
o行覆盖率 (Line Coverage)
o分支覆盖率 (Branch Coverage)
o方法覆盖率 (Method Coverage)
o类覆盖率 (Class Coverage)
o指令覆盖率 (Instruction Coverage)
o圈复杂度 (Cyclomatic Complexity)
2)轻量级:作为 Java 代理运行,无需对源代码进行修改
3)多种集成方式:
o命令行工具
oAnt 任务
oMaven 插件
oGradle 插件
oEclipse EclEmma 插件
JaCoCo 通过以下方式收集覆盖率数据:
1)插桩(Instrumentation):在字节码层面插入探针
2)执行测试:运行测试时记录执行路径
3)生成报告:分析收集的数据生成可视化报告
·持续集成环境中的代码质量门禁
·开发过程中检查测试充分性
·识别未被测试覆盖的代码区域
·监控测试覆盖率趋势
JaCoCo 生成的 HTML 报告包含:
·覆盖率概览 (所有包和类的汇总数据)
·源代码高亮显示 (绿色表示已覆盖,红色表示未覆盖)
·分支覆盖详情
·方法覆盖详情
·圈复杂度分析
1)零侵入性:不需要修改源代码
2)高性能:对应用性能影响极小
3)丰富的报告格式:支持 HTML、XML、CSV 等多种格式
4)阈值检查:可设置覆盖率最低要求,构建失败条件
5)与构建工具深度集成:Maven、Gradle、Ant 等
JaCoCo 是 Java 生态中最流行的代码覆盖率工具之一,特别适合需要监控和提升代码质量的 Java 项目。
1)配置pom.xml文件。
<!--Jacoco -->
…
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.9</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/jacoco.exec</destFile>
<propertyName>surefireArgLine</propertyName>
<!-- 添加以下配置 -->
<append>true</append>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
2)在Jenkins中安装JaCoCo插件,如所示。
安装JaCoCo插件
3)创建pipeline脚本:
…
stage('jacoco') {
steps {
// 只需要执行report目标,测试已在Build阶段完成
jacoco(
execPattern: 'target/**/*.exec',
classPattern: 'target/classes',
sourcePattern: 'src/main/java'
)
}
}
…
post{
…
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'target/site/jacoco',
reportFiles:'index.html',
reportName:'jacoco Reports',
reportTitles:'jacoco Report'])
}
4)运行,获得测试结果,如图所示。
Jenkins JaCoCo的概要测试报告
5)单击图标,查看报告的详细信息,如图所示。
Jenkins JaCoCo测试报告详细信息
PMD 深入解析:静态代码分析利器
PMD 是一款专注于源代码级别分析的静态检测工具,通过解析抽象语法树(AST)深度扫描代码结构,能在不运行程序的情况下发现:
·编码缺陷(如空指针风险、资源未关闭)
·风格违规(如命名不规范、冗余代码)
·设计问题(如过长方法、过度耦合)
·安全漏洞(如硬编码密码、XSS风险)
1)语言解析层
o支持多语言解析器:
§Java(基于JavaCC)
§Apex(Salesforce专属语言)
§JavaScript(配合Rhino引擎)
§PL/SQL(Oracle数据库脚本)
o生成AST供规则引擎分析
2)规则引擎
oXPath规则:通过XML定义代码模式匹配规则(示例):
xml
<rule name="AvoidDoubleBraceInitialization">
<description>禁止使用双括号初始化</description>
<priority>3</priority>
<xpath>//AllocationExpression[ClassOrInterfaceBody]</xpath>
</rule>
oJava规则:通过继承AbstractJavaRule实现复杂检测逻辑
3)扩展机制
o支持开发自定义规则(JAR包形式加载)
o插件化架构,可扩展新语言支持
CI/CD 集成范例(Jenkins Pipeline)
groovy
pipeline {
agent any
stages {
stage('Static Analysis') {
steps {
sh 'mvn pmd:pmd' // Maven项目执行分析
pmd canComputeNew: false,
pattern: '**/pmd.xml',
healthy: 10,
unHealthy: 100 // 质量门禁
}
}
}
}
关键质量指标(KQI)监控
sql
-- 结合SonarQube存储分析结果
SELECT
project_key,
COUNT(*) AS violations,
SUM(CASE WHEN severity = 'BLOCKER' THEN 1 ELSE 0 END) AS blockers
FROM pmd_issues
GROUP BY project_key
ORDER BY blockers DESC;
4. 高级使用技巧
1)增量分析(仅扫描变更代码)
sql
-- 结合SonarQube存储分析结果
SELECT
project_key,
COUNT(*) AS violations,
SUM(CASE WHEN severity = 'BLOCKER' THEN 1 ELSE 0 END) AS blockers
FROM pmd_issues
GROUP BY project_key
ORDER BY blockers DESC;
2) 自定义规则开发
java
public class CustomStreamRule extends AbstractJavaRule {
@Override
public Object visit(ASTMethodDeclaration node, Object data) {
if (node.getMethodName().contains("Stream")) {
addViolation(data, node, "避免使用Stream命名方法");
}
return super.visit(node, data);
}
}
3)基准测试(性能优化)
text
# 使用--benchmark参数
pmd check -d src/ --benchmark -R rulesets/java/quickstart.xml
5.行业对比深度分析
维度 | PMD | Checkstyle | SonarQube |
---|---|---|---|
检测粒度 | 代码逻辑层面 | 代码风格层面 | 全生命周期质量 |
规则定制 | XPath+Java双模式 | 仅XML配置 | 需购买商业版 |
处理速度 | 单项目<10s | 单项目<5s | 分钟级 |
内存消耗 | 200MB左右 | 100MB以内 | 需要独立服务器 |
适用阶段 | 开发/构建阶段 | 代码提交阶段 | 持续监测阶段 |
1)渐进式引入:
o初期只启用category/java/errorprone.xml核心规则
o逐步增加design.xml等规则集
2)技术债管理:
bash
# 使用@SuppressWarnings注解临时豁免
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
public class Demo { ... }
3)团队协作方案:
o将规则配置文件ruleset.xml纳入版本控制
o使用Git pre-commit hook触发基础检查
·AI增强:正在试验基于机器学习的误报过滤
·多语言融合:增强对Kotlin/Swift的支持
·云原生方案:提供SaaS化分析服务(PMD Cloud)
·规则库:https://docs.pmd-code.org/
·学术论文:《AST-Based Source Code Analysis with PMD》(IEEE SANER 2020)
·企业支持:提供商业版PMD Pro(含优先级支持)
PMD 特别适合追求高效代码审查和深度质量管控的技术团队,其平衡了检测深度与执行效率,是现代DevOps工具链中不可或缺的一环。建议从核心规则集入手,逐步构建定制化的代码质量防护体系。
简单配置
1)在Jerkins下安装Violations插件。
2)配置pom.xml文件。
<!-- PMD 代码检查 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.27.0</version>
<configuration>
<failOnViolation>false</failOnViolation>
<printFailingErrors>true</printFailingErrors>
<rulesets>
<ruleset>/rulesets/java/quickstart.xml</ruleset>
</rulesets>
<excludes>
<exclude>**/generated/**/*.java</exclude>
<exclude>**/test/**/*.java</exclude>
</excludes>
<outputDirectory>${project.build.directory}/site/</outputDirectory>
<format>html</format>
<targetJdk>17</targetJdk>
<linkXRef>true</linkXRef>
<minimumTokens>100</minimumTokens> <!-- 可选:设置最小代码量阈值 -->
</configuration>
</plugin>
<!-- 必需:交叉引用支持 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>3.3.0</version>
</plugin>
JDK17 必须>3.20
3)在Jenkins中创建Freestyle project。
4)在“Build Steps”中选择“Execute Windows batch command”。
5)输入命令:
mvn pmd:pmd
6)在“构建后操作”中选择“Report Violations”。
这时会出现多行数据,每行分别有四列:
l第一列是“太阳”图标,是生成晴朗天气报告的此类违规次数最少的图标。例如,如果值为10,表示违规数目从0到10,生成晴天报告;11或更高则生成其他的图标。
l第二列是“暴风雨”图标,是生成暴风雨天气报告的此类违规次数最少的图标。
l第三列是“不稳定”图标,是导致构建不稳定类的违规数量。
l第四列是XML文件名模式,这是一种Ant类型模式,用于匹配工作区中这种类型的冲突文件。多个模式之间用逗号分隔。
7)在“Source encoding”中选择“UTF-8”。
8)在PMD行中按照图所示输入,开始构建。
设置PMD
9)构建完毕,单击图标,如图所示。
PMD简单配置概要报告信息
stage('PMD Analysis') {
steps {
script {
// 1. 先执行PMD检查
bat "mvn pmd:pmd pmd:cpd"
// 2. 单独生成站点报告(包含HTML格式)
bat "mvn site:site -DgenerateReport=true"
// 3. 验证报告生成
if (!fileExists('target/site/pmd.html')) {
echo "警告: 未找到HTML报告,尝试备用路径..."
// 多模块项目可能路径不同
if (fileExists('target/site/pmd-pmd.html')) {
bat 'copy target/site/pmd-pmd.html target/site/pmd.html'
} else {
error "PMD HTML报告生成失败"
}
}
}
}
}
post{
always{
junit testResults:"**/target/surefire-reports/*.xml"
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'target/site',
reportFiles:'pmd.html',
reportName:'Pmd Reports',
reportTitles:'Pmd Report'])
}
10)单击图中的某个文件,查看详细信息,如所示(PMD软件自身的缺陷,这里中文显示了乱码)。
PMD简单配置详细报告信息
图形化报告配置
1)构建pipeline脚本:
stage('PMD Analysis') {
steps {
script {
// 1. 先执行PMD检查
bat "mvn pmd:pmd pmd:cpd"
// 2. 单独生成站点报告(包含HTML格式)
bat "mvn site:site -DgenerateReport=true"
// 3. 验证报告生成
if (!fileExists('target/site/pmd.html')) {
echo "警告: 未找到HTML报告,尝试备用路径..."
// 多模块项目可能路径不同
if (fileExists('target/site/pmd-pmd.html')) {
bat 'copy target/site/pmd-pmd.html target/site/pmd.html'
} else {
error "PMD HTML报告生成失败"
}
}
}
}
}
post{
always{
junit testResults:"**/target/surefire-reports/*.xml"
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'target/site',
reportFiles:'pmd.html',
reportName:'Pmd Reports',
reportTitles:'Pmd Report'])
}
2)运行,单击图标获得测试报告,如图所示。
Jenkins PMD图形化报告配置测试报告
SonarQube 深度解析:企业级代码质量与安全管控平台
SonarQube 是开源的代码质量持续监测平台,通过静态分析技术(SAST)实现:
·多维度质量检测:代码缺陷、安全漏洞、技术债务、测试覆盖率
·27+ 语言支持:Java/C#/Python/Go/JS/TS 等主流语言
·DevOps 集成:深度对接 CI/CD 流程,实现质量门禁(Quality Gate)
模块 | 技术实现 | 典型应用场景 |
---|---|---|
代码解析引擎 | 基于各语言编译器(Java→ECJ) | 构建抽象语法树(AST) |
规则引擎 | 内置 5000+ 条规则(CWE/OWASP) | 检测SQL注入、XSS等漏洞 |
质量模型 | SQALE 方法(技术债务量化) | 计算修复成本(分钟/行) |
分析器 | SonarScanner(独立进程) | 本地/CI 环境执行扫描 |
存储层 | 嵌入式H2/生产级PostgreSQL | 历史趋势分析 |
维度 | SonarQube Community | 商业版(Developer/Enterprise) |
---|---|---|
语言支持 | Java/JS/Python等基础语言 | 支持C/C++/Kotlin/Swift等 |
安全检测 | 基础漏洞规则 | 含CWE Top 25/OWASP Top 10 |
分支分析 | 仅主分支 | 多分支/PR分析 |
LDAP/SSO | 不支持 | 企业级身份集成 |
集群部署 | 单节点 | 横向扩展(HA模式) |
1)Jenkins Pipeline 集成
groovy
pipeline {
agent any
stages {
stage('SonarQube Analysis') {
steps {
withSonarQubeEnv('SonarQube-Server') {
sh 'mvn sonar:sonar -Dsonar.projectVersion=${BUILD_ID}'
}
}
}
stage("Quality Gate") {
steps {
timeout(time: 1, unit: 'HOURS') {
waitForQualityGate abortPipeline: true
}
}
}
}
}
2)自定义规则开发(Java示例)
java
@Rule(key = "AvoidSystemOut")
public class AvoidSystemOutRule extends IssuableSubscriptionVisitor {
@Override
public List<Tree.Kind> nodesToVisit() {
return Collections.singletonList(Tree.Kind.METHOD_INVOCATION);
}
@Override
public void visitNode(Tree tree) {
MethodInvocationTree mit = (MethodInvocationTree)tree;
if (mit.symbol().name().equals("println") &&
mit.symbol().owner().name().equals("System.out")) {
reportIssue(mit, "禁止使用System.out.println()");
}
}
}
5.企业级实践案例
某金融企业质量门禁配置(sonar-project.properties)
properties
# 关键质量阈值
sonar.qualitygate.wait=true
sonar.qualitygate.timeout=300
# 安全类指标
sonar.security.rating=1.0 (必须无高危漏洞)
sonar.security_review.rating=2.0
# 覆盖率要求
sonar.coverage.exclusions=**/test/**/*
sonar.java.coverage.minimum=80%
# 技术债务控制
sonar.debt.ratio.threshold=5%
6.性能优化技巧
1)增量扫描(仅分析变更文件)
bash
sonar.scanType=incremental
2)排除测试代码
properties
sonar.exclusions=**/*Test.java,**/generated/**/*
3)分布式扫描
bash
sonar.scanner.memory=4096m # 分配更大内存
sonar.analysis.worker=4 # 多线程分析
工具 | 分析深度 | 语言覆盖 | 集成复杂度 | 适用规模 |
---|---|---|---|---|
SonarQube | 代码+安全+架构 | 27+语言 | 中等 | 中大型企业 |
Checkstyle | 代码风格 | Java为主 | 简单 | 小型项目 |
PMD | 代码逻辑缺陷 | 6种语言 | 简单 | 中小团队 |
Fortify | 安全漏洞 | 20+语言 | 复杂 | 金融/政府 |
8.演进路线
·v10.x:支持Java 17+、增强Clean Code概念
·v11.x:内置AI辅助修复建议(SonarFix)
·Cloud版:SAAS化服务(AWS/GCP集成)
·社区版下载:https://www.sonarsource.com/products/sonarqube/
·规则库:https://rules.sonarsource.com/
·学术论文:《Metrics-Based Software Quality Assessment in SonarQube》(IEEE ICSME 2021)
SonarQube 特别适合需要建立标准化质量体系的研发组织,建议从社区版入手,逐步演进到商业版实现企业级管控
1)下载安装“SonarQube Scanner”插件。
2)通过菜单“Manage Jenkins→Manage Credentials”,选择“Stores scoped to Jenkins”下的“System”,如图所示。单击“Global credentials(unrestricted)”后,再单击图标添加凭据。
添加凭据
按照图所示的信息设置安全凭证。其中,Secret为SonarQube提供的token值。
3)通过菜单“Manage Jenkins→Configure System→SonarQube servers”对SonarQube servers进行设置,如图所示。
lhttp://192.168.0.123:9000:SonarQube的URL地址。
lServer authentication token:选择第2)步设置的安全凭证的名称。
4) 由于SonarQube网络调用不支持192.168.X.X、127.0.0.1和localhost回路地址,必须先下载Linux或Windows版本的nginx。配置conf/nginx.conf
server {
listen 80;
server_name sonar-webhook-proxy;
location /sonarqube-webhook {
proxy_pass http://localhost:8090/sonarqube-webhook;
proxy_set_header Host $host;
}
启动nginx.exe(nginx)文件
5)在SonarQube中,通过菜单“配置→配置→网络调用”创建网络调用:http://sonar-webhook-proxy/sonarqube-webhook/,如图所示。
6)创建pipeline 脚本:
pipeline {
agent any
tools{
maven 'mvn-3.8.6'
}
stages{
stage('Code Analysis'){
steps{
withSonarQubeEnv('SonarQube'){
bat '''
mvn clean verify sonar:sonar\
-Dsonar.projectKey=Java \
-Dsonar.host.url=http://127.0.0.1:9000
'''
}
}
}
stage('Quality Gate'){
steps{
script {
timeout(time:1,unit:'HOURS'){
sleep(5)
def qg = waitForQualityGate()
if (qg.status != 'OK'){
echo "Status:${qg.status}"
error "Pipeline aborted due to quality gate failure:${qg.status}"
}
}
}
}
}
}
}
注意:“withSonarQubeEnv('SonarQube'){”中的SonarQube必须与图中创建的name值保持一致。
在Jenkins中使用SonarQube进行扫描,不要使用“-Dsonar.login=admin \”和“-Dsonar.password=123456 \”。
PMD version: 7.14.0
allure version: 2.34.1
Jenkins:Version 2.523
SonarQube:25.8.0.112029
最后用我将要出版的《带着ChatGPT玩转软件开发》作为案例
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ebusiness</groupId>
<artifactId>ChatGPTEbusiness</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version> <!-- 或更高稳定版本 -->
<configuration>
<argLine>${surefireArgLine}</argLine>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<include>**/*Test.java</include>
<include>**/Test*.java</include>
<include>**/*Tests.java</include>
<include>**/*TestCase.java</include>
</includes>
<systemProperties>
<property>
<name>allure.results.directory</name>
<value>${project.build.directory}/allure-results</value>
</property>
<property>
<name>allure.link.issue.pattern</name>
<value>https://your-issue-tracker.com/issue/{}</value>
</property>
</systemProperties>
</configuration>
</plugin>
<!-- PMD 代码检查 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>3.27.0</version>
<configuration>
<failOnViolation>false</failOnViolation>
<printFailingErrors>true</printFailingErrors>
<rulesets>
<ruleset>/rulesets/java/quickstart.xml</ruleset>
</rulesets>
<excludes>
<exclude>**/generated/**/*.java</exclude>
<exclude>**/test/**/*.java</exclude>
</excludes>
<outputDirectory>${project.build.directory}/site/</outputDirectory>
<format>html</format>
<targetJdk>17</targetJdk>
<linkXRef>true</linkXRef>
<minimumTokens>100</minimumTokens> <!-- 可选:设置最小代码量阈值 -->
</configuration>
</plugin>
<!-- 必需:交叉引用支持 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>3.3.0</version>
</plugin>
<!--Jacoco -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.9</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/jacoco.exec</destFile>
<propertyName>surefireArgLine</propertyName>
<!-- 添加以下配置 -->
<append>true</append>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version> <!-- 存在安全漏洞 -->
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea</artifactId>
<version>1.1.14</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.16</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-reflect</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>2.29.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
4.2.3 pipeline的书写
注意顺序
pipeline {
agent any
tools{
maven 'mvn-3.9.6'
}
stages {
stage('Build'){
steps {
bat "mvn clean test"
}
}
stage('Code Analysis'){
steps{
withSonarQubeEnv('SonarQube'){
bat '''
mvn clean verify sonar:sonar\
-Dsonar.projectKey=Java \
-Dsonar.host.url=http://127.0.0.1:9000
'''
}
}
}
stage('Quality Gate'){
steps{
script {
timeout(time:5,unit:'MINUTES'){
sleep(5)
def qg = waitForQualityGate()
if (qg.status != 'OK'){
echo "Status:${qg.status}"
error "Pipeline aborted due to quality gate failure:${qg.status}"
}
}
}
}
}
stage('jacoco') {
steps {
// 只需要执行report目标,测试已在Build阶段完成
jacoco(
execPattern: 'target/**/*.exec',
classPattern: 'target/classes',
sourcePattern: 'src/main/java'
)
}
}
stage('PMD Analysis') {
steps {
script {
// 1. 先执行PMD检查
bat "mvn pmd:pmd pmd:cpd"
// 2. 单独生成站点报告(包含HTML格式)
bat "mvn site:site -DgenerateReport=true"
// 3. 验证报告生成
if (!fileExists('target/site/pmd.html')) {
echo "警告: 未找到HTML报告,尝试备用路径..."
// 多模块项目可能路径不同
if (fileExists('target/site/pmd-pmd.html')) {
bat 'copy target/site/pmd-pmd.html target/site/pmd.html'
} else {
error "PMD HTML报告生成失败"
}
}
}
}
}
}
post{
always{
junit testResults:"**/target/surefire-reports/*.xml"
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'target/site',
reportFiles:'pmd.html',
reportName:'Pmd Reports',
reportTitles:'Pmd Report'])
}
script{
publishHTML (target :[
allowMissing:false,
alwaysLinkToLastBuild:true,
keepAll:true,
reportDir:'target/site/jacoco',
reportFiles:'index.html',
reportName:'jacoco Reports',
reportTitles:'jacoco Report'])
}
script{
allure([
includeProperties:false,
jdk:'',
properties:[],
reportBuildPolicy:'ALWAYS',
results:[[path:'target/surefire-reports']]
])
}
}
}
}
2最后结果