本文将以对接 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 读取某个 projectKey 的 metric 数据,对于 mvn 工程的 sonar 卡点可采取步骤组合如下。

其中执行命令对 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>运行效果如下:


点击「报告」查看sonar扫描结果详情如下:

