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

GitHub Actions覆盖率报告MongoDB存储、查看及报错排查

问题解决与实现方案

一、当前报错的解决办法

报错提示rootDirectory undefined,核心问题是代码参数使用错误+逻辑bug,直接修改store-coverage.js如下:

const fs = require('fs');
const archiver = require('archiver');
const MongoClient = require('mongodb').MongoClient;

const uri = process.env.MONGODB_URI;
const client = new MongoClient(uri);

// 用GitHub Run ID作为唯一标识,避免同秒多次运行冲突
const uniqueId = process.env.GITHUB_RUN_ID || new Date().toISOString();

async function storeCoverageReport() {
  try {
    await client.connect();
    const db = client.db('coverage-reports');
    const collection = db.collection('reports');

    const rootDirectory = 'coverage';
    // 先校验目录是否存在
    if (!fs.existsSync(rootDirectory)) {
      throw new Error(`覆盖率目录 ${rootDirectory} 不存在,请检查测试命令是否生成覆盖率`);
    }

    const coverageReportBuffer = await compressCoverageFolder(rootDirectory);

    // 存入MongoDB,附带元信息方便后续查询
    const result = await collection.insertOne({
      _id: uniqueId,
      runId: process.env.GITHUB_RUN_ID,
      branch: process.env.GITHUB_REF_NAME,
      createdAt: new Date(),
      coverageReport: coverageReportBuffer,
    });

    console.log(`覆盖率报告已存储,ID: ${result.insertedId}`);
  } catch (err) {
    console.error('存储失败:', err);
    process.exit(1);
  } finally {
    await client.close();
  }
}

// 修复压缩逻辑,用Promise正确封装流处理
async function compressCoverageFolder(rootDirectory) {
  return new Promise((resolve, reject) => {
    const archive = archiver('zip', { zlib: { level: 9 } });
    const chunks = [];

    archive.on('data', (chunk) => chunks.push(chunk));
    archive.on('end', () => resolve(Buffer.concat(chunks)));
    archive.on('error', reject);

    archive.directory(rootDirectory, false);
    archive.finalize();
  });
}

storeCoverageReport();

同时调整工作流步骤:

  • 将Install MongoDB dependencies步骤改为安装所有依赖:
    - name: Install dependencies for coverage storage
      run: npm install mongodb archiver
    
  • 确保Run tests命令生成覆盖率(比如Jest需要加--coverage参数):
    - name: Run tests
      run: npm run test -- --coverage --json --outputFile=test-results.json
      continue-on-error: true
    

二、完整实现方案(存储+浏览器查看)

1. 存储流程

  • 测试运行生成coverage目录
  • 压缩目录为ZIP格式Buffer
  • 连同GitHub Run ID、分支名、时间戳等元数据存入MongoDB
  • 保留工作流中的actions/upload-artifact作为备份

2. 浏览器查看报告的实现

需要一个简单的Web服务读取MongoDB中的ZIP文件,解压后提供静态访问:

const express = require('express');
const MongoClient = require('mongodb').MongoClient;
const extract = require('extract-zip');
const fs = require('fs');
const path = require('path');
const os = require('os');

const app = express();
const uri = process.env.MONGODB_URI;
const client = new MongoClient(uri);

// 列出所有报告元数据
app.get('/reports', async (req, res) => {
  try {
    await client.connect();
    const reports = await client.db('coverage-reports').collection('reports')
      .find({}, { projection: { _id: 1, branch: 1, createdAt: 1 } })
      .sort({ createdAt: -1 }).toArray();
    res.json(reports);
  } catch (err) {
    res.status(500).send(err.message);
  } finally {
    await client.close();
  }
});

// 查看指定ID的报告
app.get('/reports/:id', async (req, res) => {
  const reportId = req.params.id;
  try {
    await client.connect();
    const report = await client.db('coverage-reports').collection('reports').findOne({ _id: reportId });
    if (!report) return res.status(404).send('报告不存在');

    // 创建临时目录存放解压后的文件
    const tempDir = path.join(os.tmpdir(), `cov-${reportId}`);
    if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir);

    // 写入ZIP文件并解压
    const zipPath = path.join(tempDir, 'report.zip');
    fs.writeFileSync(zipPath, report.coverageReport);
    await extract(zipPath, { dir: tempDir });

    // 提供静态文件访问,重定向到index.html
    app.use(`/reports/${reportId}`, express.static(tempDir));
    res.redirect(`/reports/${reportId}/lcov-report/index.html`);
  } catch (err) {
    res.status(500).send(err.message);
  } finally {
    await client.close();
  }
});

app.listen(3000, () => console.log('覆盖率报告服务运行在3000端口'));

将这个服务部署到你的EC2或服务器,配置好MongoDB连接即可通过浏览器访问。

三、更优方案推荐

  1. 替代MongoDB的存储方案

    • GitHub Pages托管:每次运行后把lcov-report目录推送到gh-pages分支,用Run ID作为子目录名(如/coverage/{runId}/index.html),无需自建服务
    • AWS S3存储:将ZIP文件存在S3,元数据存在DynamoDB,S3支持直接静态托管,访问更高效
  2. 工作流优化

    • 拆分测试和部署为独立Job,测试Job生成覆盖率后,部署Job仅在通过率达标时运行
    • 用actions/cache缓存npm依赖,加快构建速度
    • 用jest-junit生成JUnit格式报告,方便GitHub展示测试结果
  3. 报告体验优化

    • 集成到PR评论:用actions/github-script在PR中自动评论覆盖率变化和报告链接
    • 使用专业工具:Codecov、Coveralls等工具自动处理报告存储、历史对比、告警,无需自行开发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 01:37:04