開篇:代碼檢測(cè)遇 “黑天鵝”
在咱們?nèi)粘S?SonarQube 給代碼做 “體檢” 的常規(guī)操作里,原本項(xiàng)目中的 SonarQube 和大多數(shù)項(xiàng)目一樣,都乖乖用著 JDK8。在 GitLab CI 里,代碼質(zhì)量檢測(cè)的配置也順風(fēng)順?biāo)?/p>
sonarqube_check:
stage: 代碼質(zhì)量檢測(cè)
tags:
- sonar
image: $REGISTRY/devops/maven:3.6.3-openjdk-8-slim
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
GIT_DEPTH: "0" # 告訴git獲取所有的分支, 分析任務(wù)強(qiáng)制要求
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- mvn verify sonar:sonar -Dmaven.test.skip=false -Dsonar.host.url=${SONAR_HOST_URL} -Dsonar.login=${SONAR_LOGIN} -Dsonar.password=${SONAR_PASSWORD} -Dsonar.projectKey=${SVC_NAME} -Dsonar.projectVersion=${JAR_VERSION} -Dsonar.projectName=${SVC_NAME} -Dsonar.qualitygate.wait=true
when: manual #手動(dòng)執(zhí)行觸發(fā)
allow_failure: false
誰能想到,AI 這股風(fēng)一吹,領(lǐng)導(dǎo)一拍腦袋,想著用 AI 給代碼掃描,一看 SonarQube 最新版有相關(guān)功能,鏈接在此https://docs.sonarsource.com/sonarqube-server/latest/ai-capabilities/overview/ ,沒仔細(xì)調(diào)研就把部門的 SonarQube 升級(jí)到了 2025.1 版。這一升級(jí),好家伙,問題來了!
問題大揭秘:JDK 版本 “掐架”
SonarQube 2025 是基于 JDK17 編譯的,可咱還在用老配置掃描:
sonarqube_check:
stage: 代碼質(zhì)量檢測(cè)
tags:
- sonar
image: $REGISTRY/devops/maven:3.6.3-openjdk-8-slim
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
GIT_DEPTH: "0" # 告訴git獲取所有的分支, 分析任務(wù)強(qiáng)制要求
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- mvn verify sonar:sonar -Dmaven.test.skip=false -Dsonar.host.url=${SONAR_HOST_URL} -Dsonar.login=${SONAR_LOGIN} -Dsonar.password=${SONAR_PASSWORD} -Dsonar.projectKey=${SVC_NAME} -Dsonar.projectVersion=${JAR_VERSION} -Dsonar.projectName=${SVC_NAME} -Dsonar.qualitygate.wait=true
when: manual #手動(dòng)執(zhí)行觸發(fā)
allow_failure: false
結(jié)果報(bào)錯(cuò)了:
Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar (default-cli) on project nisbos-api-gateway: Execution default-cli of goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar failed: An API incompatibility was encountered while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.7.0.1746:sonar: java.lang.UnsupportedClassVersionError: org/sonar/batch/bootstrapper/EnvironmentInformation has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0
簡(jiǎn)單來說,就是 SonarQube 插件里的org.sonar.batch.bootstrapper.EnvironmentInformation類是用高版本 Java(對(duì)應(yīng) Java 17)編譯的,咱當(dāng)前的 Java 運(yùn)行環(huán)境(Java 8)不認(rèn),這下代碼掃描直接 “罷工” 了。
修復(fù)方案大比拼
- 升級(jí) Java 版本
把 Java 運(yùn)行時(shí)環(huán)境升級(jí)到和 SonarQube 插件匹配的版本,也就是 Java 17 或更高。比如把maven:3.6.3-openjdk-8-slim鏡像升級(jí)成支持 JDK17 的鏡像。但問題是,一堆歷史遺留項(xiàng)目都是基于 JDK8 構(gòu)建的,短期內(nèi)改造,那成本和工作量,想想都頭大。
2、降低 SonarQube 版本
理論上把 SonarQube 版本降回用 JDK8 的版本,問題就能解決。可現(xiàn)實(shí)是,SonarQube 現(xiàn)在和 AI 有點(diǎn)關(guān)聯(lián),你懂的,在團(tuán)隊(duì)里要推動(dòng)降級(jí),阻力重重。
3、構(gòu)建與掃描 “分家”
把mvn sonar:sonar拆成兩個(gè)流程,先基于 Maven 構(gòu)建,再把構(gòu)建好的物料送到 Sonar - Scanner 掃描。這個(gè)方案比較靠譜,具體腳本如下:
maven_deploy:
stage: 編譯生成
only:
- branches
tags:
- sonar
image: $REGISTRY/devops/maven:3.6.3-openjdk-8-slim
script:
- mvn deploy -DskipTests -Dmaven.repo.local=/root/.m2/repository -s /root/.m2/settings-nisbos.xml
cache:
key: maven_target_cache
paths:
- $BUILD_TARGET_DIR
policy: push
when: manual #手動(dòng)執(zhí)行觸發(fā)
allow_failure: false
sonarqube_check:
stage: 代碼質(zhì)量檢測(cè)
only:
- branches
tags:
- sonar
image: $REGISTRY/sonarsource/sonar-scanner-cli:11.2.1.1844_7.0.2
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
GIT_DEPTH: "0" # 告訴git獲取所有的分支, 分析任務(wù)強(qiáng)制要求
script:
- sonar-scanner -Dsonar.java.binaries=$BUILD_TARGET_DIR -Dsonar.host.url=${SONAR_HOST_URL} -Dsonar.token=${SONAR_TOKEN} -Dsonar.projectKey=${SONAR_PROJECT_NAME} -Dsonar.projectVersion=${JAR_VERSION} -Dsonar.projectName=${SONAR_PROJECT_NAME} -Dsonar.qualitygate.wait=true
cache:
- key: maven_target_cache
paths:
- $BUILD_TARGET_DIR
policy: pull
- key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
#when: manual #手動(dòng)執(zhí)行觸發(fā)
allow_failure: false
總結(jié):避坑指南與經(jīng)驗(yàn)之談
這篇主要講了 SonarQube 和項(xiàng)目 JDK 版本不兼容,導(dǎo)致掃描失敗的修復(fù)辦法。其實(shí)官網(wǎng)也給了個(gè)解法,大概意思是:在某些情況下,要是分析的項(xiàng)目構(gòu)建用的 Java 版本和執(zhí)行分析時(shí)的 Java 版本不一樣,像用 Java 17 運(yùn)行分析,項(xiàng)目構(gòu)建用 Java 11 或更早版本,就得手動(dòng)設(shè)置sonar.java.jdkHome屬性,指向合適的 JDK。比如分析 Java 11 項(xiàng)目:
# Here maven uses the default version of Java on the system but we specify that we want to analyze a Java 11 project.
mvn org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \
# other analysis parameters
-Dsonar.java.jdkHome=/usr/lib/jvm/jdk11/
# other analysis parameters
但一開始我被誤導(dǎo)了,這個(gè)屬性只是讓 SonarQube 分析器在分析代碼時(shí)知道用哪個(gè) JDK 的類,不是指定執(zhí)行 Maven 和 SonarScanner 的 Java 版本,執(zhí)行它們的 Java 版本還是由JAVA_HOME環(huán)境變量或者系統(tǒng)默認(rèn) Java 版本決定,所以官網(wǎng)這招解決不了我們的問題。
最終我們靠隔離關(guān)注點(diǎn)、遵循單一職責(zé)原則解決了問題。大家在遇到類似情況時(shí),希望這篇文章能幫你少走彎路,趕緊解決問題!要是覺得有用,記得點(diǎn)贊、轉(zhuǎn)發(fā),讓更多人看到,一起在代碼的坑里 “互幫互助”!