You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在CircleCI流水线中存储并对比Node覆盖率测试结果

实现CircleCI覆盖率对比与流水线失败控制

步骤1:保存本次覆盖率结果为工件

修改build_and_test任务,将npx lcov-total的输出保存到本地文件,再上传为CircleCI工件以便后续读取:

jobs:
  build_and_test:
    executor: node/default
    steps:
      - nodesetup
      - run: npm run test
      - run: npm run ci-coverage
      # 计算覆盖率并写入文件
      - run:
          name: Calculate and save coverage total
          command: |
            npx lcov-total coverage/lcov.info > coverage_total.txt
            echo "本次覆盖率: $(cat coverage_total.txt)"
      # 上传覆盖率文件为工件
      - store_artifacts:
          path: coverage_total.txt
          destination: coverage_total

步骤2:拉取上次成功流水线的覆盖率结果

通过CircleCI API获取上一次成功流水线的覆盖率工件,需要先在项目设置中添加环境变量CIRCLE_API_TOKEN(需拥有read-pipelines和read-artifacts权限),然后在任务中添加拉取步骤:

jobs:
  build_and_test:
    executor: node/default
    steps:
      - nodesetup
      # 获取上次成功流水线的覆盖率数据
      - run:
          name: Fetch previous coverage total
          command: |
            # 获取上一次成功的流水线ID(跳过当前正在执行的流水线)
            PREV_PIPELINE_ID=$(curl -s -H "Circle-Token: $CIRCLE_API_TOKEN" \
              "https://circleci.com/api/v2/project/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/pipeline?status=success&limit=2" | \
              jq -r '.items[1].id')
            
            if [ -n "$PREV_PIPELINE_ID" ]; then
              # 查找对应工件的下载链接
              ARTIFACT_URL=$(curl -s -H "Circle-Token: $CIRCLE_API_TOKEN" \
                "https://circleci.com/api/v2/pipeline/$PREV_PIPELINE_ID/workflow" | \
                jq -r '.items[0].id' | xargs -I {} curl -s -H "Circle-Token: $CIRCLE_API_TOKEN" \
                "https://circleci.com/api/v2/workflow/{}/artifact" | \
                jq -r '.items[] | select(.path | contains("coverage_total.txt")) | .url')
              
              # 下载上次的覆盖率文件
              if [ -n "$ARTIFACT_URL" ]; then
                curl -s -H "Circle-Token: $CIRCLE_API_TOKEN" "$ARTIFACT_URL" > previous_coverage_total.txt
                echo "上次覆盖率: $(cat previous_coverage_total.txt)"
              else
                echo "未找到上次覆盖率工件,跳过对比"
                touch previous_coverage_total.txt
              fi
            else
              echo "无历史成功流水线,跳过对比"
              touch previous_coverage_total.txt
            fi
          environment:
            CIRCLE_API_TOKEN: $CIRCLE_API_TOKEN

步骤3:对比覆盖率并控制流水线状态

添加对比逻辑,若本次覆盖率低于上次则主动终止流水线:

jobs:
  build_and_test:
    executor: node/default
    steps:
      # 前面的nodesetup、拉取上次结果、测试生成覆盖率步骤同上
      # ...
      # 计算覆盖率并写入文件步骤同上
      # ...
      # 对比覆盖率数值
      - run:
          name: Compare coverage totals
          command: |
            # 检查是否存在有效历史数据
            if [ -s previous_coverage_total.txt ]; then
              # 去除百分号,转为纯数字
              PREV_TOTAL=$(cat previous_coverage_total.txt | tr -d '%')
              CURRENT_TOTAL=$(cat coverage_total.txt | tr -d '%')
              
              # 浮点数值对比,若本次更低则失败
              if (( $(echo "$CURRENT_TOTAL < $PREV_TOTAL" | bc -l) )); then
                echo "错误:本次覆盖率($CURRENT_TOTAL%)低于上次($PREV_TOTAL%),流水线终止"
                exit 1
              else
                echo "覆盖率符合要求:本次($CURRENT_TOTAL%) ≥ 上次($PREV_TOTAL%)"
              fi
            else
              echo "无历史覆盖率数据,跳过对比"
            fi
      # 上传本次覆盖率工件步骤同上
      # ...

完整修改后的config.yaml

orbs:
  node: circleci/node@5.0.2

commands:
  nodesetup:
    description: checkout code, restore cache, install dependencies, save cache
    steps:
      - checkout
      - node/install-packages:
         cache-path: ~/project/node_modules
         app-dir: ~/project/

jobs:
  build_and_test:
    executor: node/default
    steps:
      - nodesetup
      # 获取上次成功流水线的覆盖率结果
      - run:
          name: Fetch previous coverage total
          command: |
            PREV_PIPELINE_ID=$(curl -s -H "Circle-Token: $CIRCLE_API_TOKEN" \
              "https://circleci.com/api/v2/project/gh/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/pipeline?status=success&limit=2" | \
              jq -r '.items[1].id')
            
            if [ -n "$PREV_PIPELINE_ID" ]; then
              ARTIFACT_URL=$(curl -s -H "Circle-Token: $CIRCLE_API_TOKEN" \
                "https://circleci.com/api/v2/pipeline/$PREV_PIPELINE_ID/workflow" | \
                jq -r '.items[0].id' | xargs -I {} curl -s -H "Circle-Token: $CIRCLE_API_TOKEN" \
                "https://circleci.com/api/v2/workflow/{}/artifact" | \
                jq -r '.items[] | select(.path | contains("coverage_total.txt")) | .url')
              
              if [ -n "$ARTIFACT_URL" ]; then
                curl -s -H "Circle-Token: $CIRCLE_API_TOKEN" "$ARTIFACT_URL" > previous_coverage_total.txt
                echo "上次覆盖率: $(cat previous_coverage_total.txt)"
              else
                echo "未找到上次覆盖率工件,跳过对比"
                touch previous_coverage_total.txt
              fi
            else
              echo "无历史成功流水线,跳过对比"
              touch previous_coverage_total.txt
            fi
          environment:
            CIRCLE_API_TOKEN: $CIRCLE_API_TOKEN
      - run: npm run test
      - run: npm run ci-coverage
      # 计算覆盖率并保存到文件
      - run:
          name: Calculate and save coverage total
          command: |
            npx lcov-total coverage/lcov.info > coverage_total.txt
            echo "本次覆盖率: $(cat coverage_total.txt)"
      # 对比覆盖率,若本次更低则失败
      - run:
          name: Compare coverage totals
          command: |
            if [ -s previous_coverage_total.txt ]; then
              PREV_TOTAL=$(cat previous_coverage_total.txt | tr -d '%')
              CURRENT_TOTAL=$(cat coverage_total.txt | tr -d '%')
              
              if (( $(echo "$CURRENT_TOTAL < $PREV_TOTAL" | bc -l) )); then
                echo "错误:本次覆盖率($CURRENT_TOTAL%)低于上次($PREV_TOTAL%),流水线终止"
                exit 1
              else
                echo "覆盖率符合要求:本次($CURRENT_TOTAL%) ≥ 上次($PREV_TOTAL%)"
              fi
            else
              echo "无历史覆盖率数据,跳过对比"
            fi
      # 上传覆盖率文件为工件
      - store_artifacts:
          path: coverage_total.txt
          destination: coverage_total
  
workflows:
  models_pipeline:
    jobs:
      - build_and_test

注意事项

  • CircleCI默认Ubuntu镜像已包含jq(JSON解析工具)和bc(浮点运算工具),无需额外安装
  • CIRCLE_API_TOKEN需在项目设置的「环境变量」中添加,权限至少包含read-pipelines和read-artifacts
  • 首次执行流水线时无历史数据,会自动跳过对比;从第二次成功执行开始,后续流水线会触发覆盖率校验

内容的提问来源于stack exchange,提问作者bitterman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 03:40:40