PAYATHON 2026

Jenkins CI/CD pipeline 中跳过 Build Code 阶段有什么影响?

技术老齐

构建阶段可以保留,也可以与分析合并

题目中的 Jenkinsfile 通常应保留 mvn clean package,也可以把它与 SonarQube 分析合并为一次 Maven 调用。

这两个命令默认不会重复编译:

  • mvn clean package 清理旧产物,执行构建生命周期,通常包括编译、单元测试和打包。
  • mvn sonar:sonar 调用 SonarScanner for Maven,分析代码并提交分析报告。单独执行这个目标,通常不会编译、测试或打包项目。

直接删除 Build Code 阶段,只运行 mvn sonar:sonar,可能导致 Java 分析因缺少字节码而失败,也会失去对本次提交的编译、测试和打包验证。

Jenkins 的阶段名称只用于组织流程,是否编译取决于阶段里执行的命令。

两个 Maven 命令分别做什么?

mvn clean package:构建并生成产物

这个命令包含两部分:

  1. clean:清理上一次构建的输出,通常是 target 目录。
  2. package:执行默认生命周期中截至 package 的阶段。

对于常见的 Java JAR 项目,流程可以简化为:

处理资源 → 编译主代码 → 编译测试代码 → 执行单元测试 → 打包

成功后,通常会得到:

target/classes/         编译后的主代码
target/test-classes/    编译后的测试代码
target/surefire-reports/ 单元测试报告
target/*.jar           打包产物

实际行为取决于 pom.xml、项目的 packaging 类型、启用的 profile 和插件配置。例如,设置跳过测试的参数后,构建成功也不能说明测试已经通过。

package 尚未执行后面的 integration-test 和 verify 阶段。如果项目把集成测试和相关检查绑定在这些阶段,可以考虑使用:

mvn clean verify

verify 会先经过 package,因此仍然包含打包。具体执行哪些集成测试,则取决于项目配置的相应插件。

mvn sonar:sonar:执行静态分析

sonar:sonar 是 Maven 插件目标。它读取项目配置、源码和分析所需的构建输出,生成分析报告并提交给 SonarQube。

Java 分析器会使用编译后的 .class 文件完成部分语义分析。包含多个 Java 源文件的项目通常需要提供这些字节码,SonarScanner for Maven 可以根据 Maven 项目配置找到相应的输出目录。

因此,静态代码分析仍可能需要先编译:分析器要使用编译结果,而扫描命令本身通常不负责生成这些结果。

工作mvn clean package单独执行 mvn sonar:sonar
编译项目源码通常会通常不会
执行单元测试默认会,受配置影响不会主动执行
生成 JAR/WAR按 packaging 配置生成不负责生成
提交 SonarQube 分析报告默认不会会

如果项目通过自定义插件配置增加了其他行为,应以实际 Maven 执行日志为准。

跳过 Build Code 后会发生什么?

干净的工作区可能无法完成 Java 分析

假设 Jenkins 使用新 agent,检出后只有源码,没有 target/classes:

Checkout
    ↓
mvn sonar:sonar
    ↓
缺少分析所需的 Java 字节码,分析可能失败

具体表现取决于项目内容和分析器版本。不同语言的 SonarQube 分析对编译的要求不同,题目中的 Maven Java 项目应优先按“先构建,再分析”安排。

复用工作区可能掩盖问题

如果工作区保留了上次构建的 target 目录,删除构建阶段后,扫描可能仍能启动。但此时源码来自当前提交,字节码却来自旧提交。分析可能失败,也可能使用不匹配的输入,导致结果不可靠。

即使删除阶段后 Jenkins 仍显示绿色,也要检查扫描使用的字节码、测试报告和其他输入是否属于当前提交,才能判断构建步骤是否可以省略。

编译、测试和交付验证会缺失

一个方法可能正常编译,却返回错误的业务结果。单元测试可以通过断言发现这个问题,SonarQube 不会替你执行测试。

静态分析完成,也不能据此确认:

  • 当前提交能够成功编译。
  • 单元测试或集成测试已经通过。
  • 项目能够成功打包。
  • 后续部署需要的 JAR/WAR 已经生成。

如果后面还有归档、制作镜像或部署阶段,缺少本次构建产物会直接影响这些步骤,工作区中的旧产物也可能被误用。

如何安排 Jenkins 阶段?

方案一:保留独立的构建和分析阶段

分开执行便于排查失败原因。构建阶段失败时,先处理编译或测试问题;分析阶段失败时,再检查扫描配置、认证或 SonarQube 连接。

下面沿用 Windows agent 的 bat,构建执行到 verify:

pipeline {
    agent any

    options {
        skipDefaultCheckout(true)
    }

    environment {
        SONAR_HOST_URL = 'https://sonarqube.example.com'
        SONAR_PROJECT_KEY = 'your-project-key'
    }

    stages {
        stage('Checkout') {
            steps {
                checkout([
                    $class: 'GitSCM',
                    branches: [[name: '*/main']],
                    userRemoteConfigs: [[url: 'git-url']]
                ])
            }
        }

        stage('Build and Test') {
            steps {
                bat 'mvn -B clean verify'
            }
        }

        stage('Static Code Analysis') {
            steps {
                withCredentials([
                    string(
                        credentialsId: 'sonarqube',
                        variable: 'SONAR_TOKEN'
                    )
                ]) {
                    bat '@mvn -B sonar:sonar "-Dsonar.token=%SONAR_TOKEN%" "-Dsonar.host.url=%SONAR_HOST_URL%" "-Dsonar.projectKey=%SONAR_PROJECT_KEY%"'
                }
            }
        }
    }
}

使用前需要替换仓库地址、SonarQube 地址和项目 key,并确保 agent 上的 JDK、Maven 及扫描插件配置兼容。

Groovy 单引号字符串让 Windows 命令行展开 %SONAR_TOKEN%,避免通过 Groovy 字符串插值传入凭据。

两个阶段需要使用同一份源码和构建输出。示例没有配置阶段级 agent,正常执行时会共享顶层 agent 的工作区。如果改用不同节点或容器,需要显式传递扫描所需的构建输出,target 不会自动出现在新环境中。

方案二:把构建与分析合并

如果不需要分别展示耗时和失败位置,可以把上述两个阶段替换为:

stage('Build, Test and Analyze') {
    steps {
        withCredentials([
            string(
                credentialsId: 'sonarqube',
                variable: 'SONAR_TOKEN'
            )
        ]) {
            bat '@mvn -B clean verify sonar:sonar "-Dsonar.token=%SONAR_TOKEN%" "-Dsonar.host.url=%SONAR_HOST_URL%" "-Dsonar.projectKey=%SONAR_PROJECT_KEY%"'
        }
    }
}

Maven 会先完成截至 verify 的构建,再执行 sonar:sonar。默认情况下,构建失败后,扫描不会继续执行。

合并后,独立的 Build Code 阶段可以删除,编译、测试和打包工作仍然保留。sonar:sonar 本身不会再执行一遍完整构建。

如果项目目前只需要执行到打包,也可以使用:

mvn clean package sonar:sonar

哪些情况下可以跳过构建?还要注意什么?

扫描所需的构建结果已经可靠准备好时,才适合跳过当前流水线中的构建步骤。例如,上游任务已经为同一提交生成并传递了所需字节码和报告。除了确认文件存在,还要检查构建配置、依赖及工具链是否与当前分析匹配,并确保当前提交已有测试验证。

安排阶段时,还需注意:

  • 扫描前要保留构建输出。不要先构建,再执行 mvn clean sonar:sonar,因为 clean 会删除刚生成的字节码和报告。
  • 覆盖率报告需要单独生成。SonarQube 不会通过静态扫描运行测试并计算覆盖率,需要配置 JaCoCo 等工具生成报告,再由扫描器导入。
  • 多模块项目拆成两次 Maven 调用时,扫描可能需要从本地仓库解析模块间依赖。这类项目通常应先执行 mvn clean install,再单独扫描。install 会额外把构建产物安装到 agent 的本地 Maven 仓库。
  • 扫描成功与 Quality Gate 通过需要分别处理。如果发布受质量门禁约束,应在分析后等待 Quality Gate 结果。使用 Jenkins 的 waitForQualityGate 时,需要按插件要求配置 withSonarQubeEnv 和 SonarQube webhook。
  • 在项目配置中明确插件版本,并让构建与分析使用一致的 profile、源码和 JDK 配置,避免不同阶段实际处理不同的项目内容。

备注:内容仅供参考。