本文将以对接 SonarQube 扫描服务为例,介绍如何使用新版 Flow-CLI 工具定制开发一个带红线卡点的扫描步骤。
前提条件
-
本地已下载并安装 Flow-CLI 新版本,参考 Flow-CLI工具下载安装
-
准备好一个公网可访问的 Sonar 服务。例如 https://sonarcloud.io/ (公网不可达的服务需使用私有构建机方案,详见 私网环境下如何使用云效流水线进行CI/CD?)
本地开发步骤
参考 RedlineSonar 示例代码 https://atomgit.com/flow-step-custom/RedlineSonar ,本地拉取示例代码:
git clone https://atomgit.com/flow-step-custom/RedlineSonar.git
示例代码目录结构如下:
.
├── README.md # 步骤说明
├── package.json # typescript 工程包声明
├── src # 步骤后端执行逻辑
│ ├── index.ts
│ └── params.ts
├── step.yaml # 步骤前端展示描述信息 yaml
├── tsconfig.eslint.json
└── tsconfig.json
步骤前端展示 step.yaml
step.yaml 文件定义了步骤前端描述,用于定义步骤执行所需的输入参数。参数说明如下:
|
参数 |
参数说明 |
|
id |
步骤唯一标识,全局唯一。(如需发布步骤到企业,请修改 id 为唯一标识后发布) |
|
name |
用于定义步骤名称。 |
|
items |
步骤语言描述,请参考步骤语言YAML描述。 |
|
redline |
红线信息。 |
|
datamap |
type 枚举字段 LE: 实际值小于等于期望值;GE: 实际值大于等于期望值;EQ 实际值等于期望值 key 红线待校验字段。 |
本步骤定义以下几个表单,作为步骤执行参数输入:
-
Sonar服务器地址
-
Sonar Token
-
Sonar Project Key
-
红线信息
---
apiVersion: v2
kind: DefaultJob
id: RedlineSonar
name: RedlineSonar
description: flow redline check with sonar
helpUrl: https://atomgit.com/flow-step-custom/RedlineSonar
execution:
executor: node
main: dist/index.js
items:
- label: Sonar服务器地址
name: STEP_SONAR_HOST
type: input
- label: Sonar Token
name: STEP_SONAR_TOKEN
type: password
rules:
- require: false
- label: Sonar Project Key
name: STEP_SONAR_PROJECT_KEY
type: input
- label: 红线信息
name: CHECK_REDLINES
type: addable_group
rules:
- require: false
add_button:
type: icon
icon: plus
text: 增加红线
tip:
icon: question-circle
description: 红线校验失败任务将失败
template:
items:
- name: redline
label: 红线
position: flat
type: custom_redline_dropdown
datamap: '[{"key": "Bugs","type": "LE"},{"key": "Vulnerabilities","type": "LE"},{"key": "Smells","type": "LE"},{"key": "Coverage","type": "GE"}]'
rules:
- require: false
红线信息key定义如下,以下预置 key 支持显示中文描述,自定义key则直接显示key:
|
key(不区分大小写) |
中文描述 |
|
passedrate |
测试通过率 |
|
total |
Total 问题数 |
|
blocker |
Blocker 问题数 |
|
high |
High 问题数 |
|
medium |
Medium 问题数 |
|
critical |
Critical 问题数 |
|
major |
Major 问题数 |
|
violation |
Violation 问题数 |
|
information |
Information 问题数 |
|
warning |
Warning 问题数 |
|
error |
Error 问题数 |
|
linecoveragerate |
行覆盖率 |
|
branchcoveragerate |
分支覆盖率 |
|
methodcoveragerate |
方法覆盖率 |
|
classcoveragerate |
类覆盖率 |
|
instructioncoveragerate |
指令覆盖率 |
步骤后端执行逻辑 src/index.ts
src/index.ts 文件定义了步骤后端执行逻辑,主要逻辑说明如下:
-
输出基础信息和检验步骤入参
-
调用 sonar api 获取指定项目的指标数据(私有项目需要指定 STEP_SONAR_TOKEN)
-
将 sonar 返回数据格式化为红线数据
-
调用 sdk 进行红线检验和记录报告链接信息
async function runStep(): Promise<void> {
const params = getParams()
// 输出基础信息和检验入参
logAndValidParams(params);
// 调用 sonar api 获取指定项目的指标数据
const metrics = await requestSonarMetrics(`${params.sonarHost}/api/measures/search`, params.sonarToken, {
projectKeys: `${params.sonarProjectKey}`,
metricKeys: 'alert_status,bugs,reliability_rating,vulnerabilities,security_rating,code_smells,sqale_rating,duplicated_lines_density,coverage,ncloc,ncloc_language_distribution'
})
step.infoCyan(`Sonar Metrics: ${JSON.stringify(metrics)}`)
const bugs = Number(metrics['bugs'])
const vulnerabilities = Number(metrics['vulnerabilities'])
const smells = Number(metrics['code_smells'])
const coverage = Number(metrics['coverage'])
// 准备红线数据
const readlineResults = [] as RedlineResult[]
const bugsRR = generateRedlineResult("Bugs", "缺陷", bugs, redline.Error);
readlineResults.push(bugsRR)
const vulnerabilitiesRR = generateRedlineResult("Vulnerabilities", "漏洞", vulnerabilities, redline.Error);
readlineResults.push(vulnerabilitiesRR)
const smellsRR = generateRedlineResult("Smells", "坏味道", smells, redline.Error);
readlineResults.push(smellsRR)
const coverageRR = generateRedlineResult("Coverage", "覆盖率", coverage, redline.Warning);
readlineResults.push(coverageRR)
// 调用 sdk 进行红线检验和记录报告链接信息
const redlineInfo = {} as RedlineInfo
redlineInfo.title = 'Redline Sonar'
redlineInfo.reportUrl = `${params.sonarHost}/component_measures?id=${params.sonarProjectKey}`
redlineInfo.readlineResults = readlineResults
const checkResult = step.redline.redlineCheck(redlineInfo, process.env['CHECK_REDLINES'])
if (!checkResult){
step.error('Redline check failed')
process.exit(-1)
}
}
发布步骤
按需修改上述步骤实现代码后,切换到 step.yaml 文件所在目录,执行以下命令发布步骤到企业:
flow-cli step publish
流水线使用步骤并运行
步骤发布成功后,进入流水线编辑页面,可以在任务编辑页面,指定容器环境 -> 添加步骤 -> 企业步骤,添加 RedlineSonar 这个步骤。
在 RedlineSonar 步骤的配置面板中,按需填写 Sonar服务器地址(如 https://sonarcloud.io)、Sonar Token、Sonar Project Key,并在 红线信息 中配置校验项(如 Coverage 大于等于 15)。
编辑后保存并运行流水线,查看步骤运行结果和日志:
流水线运行结果页面以横向节点流形式展示各步骤的执行状态。其中 SonarRedline 节点因 红线未通过 而标红失败,从而导致整体运行失败,节点中可看到红线校验项的实际指标:缺陷 0、漏洞 27、坏味道 38、覆盖率 11.5。
2024-12-04 04:15:46 [INFO] Sonar Metrics: {"alert_status":"ERROR","bugs":"0","code_smells":"30","coverage":"11.5","reliability_rating":"1.0","security_rating":"1.0"}
2024-12-04 04:15:46 [INFO] STAT_URL_REPORT=https://sonarcloud.io/component_measures?id=cccfeng_sonar-java-test
2024-12-04 04:15:46 [INFO] STAT_NAME_Bugs=缺陷
2024-12-04 04:15:46 [INFO] STAT_VALUE_Bugs=0
2024-12-04 04:15:46 [INFO] REDLINE_ITEM_LINE
{"key":"Bugs","threshold":100,"checkVal":0,"type":"LE","checked":true,"checkResult":true}
2024-12-04 04:15:46 [INFO] STAT_NAME_Vulnerabilities=漏洞
2024-12-04 04:15:46 [INFO] STAT_VALUE_Vulnerabilities=27
2024-12-04 04:15:46 [INFO] REDLINE_ITEM_LINE
{"key":"Vulnerabilities","threshold":25,"checkVal":27,"type":"LE","checked":true,"checkResult":false}
2024-12-04 04:15:46 [INFO] STAT_NAME_Smells=坏味道
2024-12-04 04:15:46 [INFO] STAT_VALUE_Smells=38
2024-12-04 04:15:46 [INFO] REDLINE_ITEM_LINE
{"key":"Smells","threshold":35,"checkVal":38,"type":"LE","checked":true,"checkResult":false}
2024-12-04 04:15:46 [INFO] STAT_NAME_Coverage=覆盖率
2024-12-04 04:15:46 [INFO] STAT_VALUE_Coverage=11.5
2024-12-04 04:15:46 [INFO] REDLINE_ITEM_LINE
{"key":"Coverage","threshold":10,"checkVal":11.5,"type":"GE","checked":true,"checkResult":true}
2024-12-04 04:15:46 [SUCCESS] run step successfully!
高级用法
在流水线中,推荐使用原子的步骤进行组合支持复杂的使用场景。例如以上的 RedlineSonar 步骤只负责从 sonar 读取某个 projectKey 的 metric 数据,对于 mvn 工程的 sonar 卡点可采取步骤组合如下。
推荐在容器环境(如 build-steps/alinux3)中依次添加 配置 MavenSettings 文件、安装 Java、执行命令、RedlineSonar 四个步骤组合使用。
其中执行命令对 mvn 工程进行构建和调用 sonar 插件进行扫描:
# mvn 构建
mvn -B clean package -Dmaven.test.skip=true -Dautoconfig.skip
# 通过 mvn sonar 插件执行 sonar 扫描
mvn verify -Dmaven.test.failure.ignore=true org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.token=<your personal access token> -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=<your organization key> -Dsonar.projectKey=<your project key>
运行效果如下:
运行结果卡片显示 Java 构建 + RedlineSonar 步骤执行成功,耗时 1 分 15 秒,可通过 报告 和 日志 链接进入详情;卡片底部汇总展示 Sonar 扫描的核心质量指标:缺陷 0、漏洞 0、坏味道 3、覆盖率 7.4%。
[INFO] SCM Publisher 2/2 source files have been analyzed (done) | time=153ms
[INFO] CPD Executor 2 files had no CPD blocks
[INFO] CPD Executor Calculating CPD for 1 file
[INFO] CPD Executor CPD calculation finished (done) | time=5ms
[INFO] Analysis report generated in 159ms, dir size=287 KB
[INFO] Analysis report compressed in 19ms, zip size=63 KB
[INFO] Analysis report uploaded in 515ms
[INFO] ANALYSIS SUCCESSFUL, you can find the results at: https://sonarcloud.io/dashboard?id=cccfeng_sonar-java-test
[INFO] Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
[INFO] More about the report processing at https://sonarcloud.io/api/ce/task?id=AZOQ-dopFA2SZIKknz46
[INFO] Sensor cache published successfully
[INFO] Analysis total time: 25.078 s
[INFO] SonarScanner Engine completed successfully
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 57.651 s
[INFO] Finished at: 2024-12-04T17:21:55+08:00
[INFO] Final Memory: 30M/134M
[INFO] ------------------------------------------------------------------------
2024-12-04 17:21:55 [SUCCESS] run step successfully!
点击「报告」查看sonar扫描结果详情如下:
Sonar 报告页面切换到 Measures 标签后,左栏 Overall Code 区域汇总展示项目度量:Debt Ratio 0.0%、Rating A、Code Smells 3、Debt 25min;右栏可进一步查看 Code Smells 在 src 目录和 pom.xml 文件中的分布。
在同一 Measures 视图的 Overall Code 区域,Coverage(覆盖率)显示为 7.4%。