Git钩子脚本如何检查测试覆盖率

wen 实用脚本 1

本文目录导读:

Git钩子脚本如何检查测试覆盖率

  1. 基础实现方法
  2. 更完整的脚本示例
  3. Python 版本的钩子脚本
  4. 只检查变更文件的覆盖率
  5. 安装钩子的脚本
  6. 配置文件和高级选项
  7. 使用建议

Git钩子脚本可以通过以下方式检查测试覆盖率:

基础实现方法

在 pre-commit 钩子中检查覆盖率

#!/bin/bash
# .git/hooks/pre-commit
# 运行测试并生成覆盖率报告
coverage run -m pytest
coverage report
# 提取总覆盖率百分比
COVERAGE=$(coverage report | grep "TOTAL" | awk '{print $NF}' | sed 's/%//')
# 设置覆盖率阈值
THRESHOLD=80
if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then
    echo "❌ 测试覆盖率不达标: ${COVERAGE}% < ${THRESHOLD}%"
    exit 1
fi
echo "✅ 测试覆盖率达标: ${COVERAGE}%"

更完整的脚本示例

#!/bin/bash
# .git/hooks/pre-commit
set -e
PROJECT_ROOT=$(git rev-parse --show-toplevel)
cd "$PROJECT_ROOT"
# 配置
MIN_COVERAGE=80
COVERAGE_FILE=".coverage"
REPORT_DIR="coverage_report"
echo "📊 开始检查测试覆盖率..."
# 运行测试并收集覆盖率
coverage run -m pytest tests/ -v 2>&1
# 检查测试是否通过
if [ $? -ne 0 ]; then
    echo "❌ 测试失败,请修复后再提交"
    exit 1
fi
# 生成覆盖率报告
coverage report -m > coverage_report.txt
# 解析覆盖率
COVERAGE_VALUE=$(coverage report | grep -E "^TOTAL" | awk '{print $NF}' | tr -d '%')
if [ -z "$COVERAGE_VALUE" ]; then
    echo "❌ 无法获取覆盖率信息"
    exit 1
fi
echo "当前覆盖率: ${COVERAGE_VALUE}%"
# 比较覆盖率
if (( $(echo "$COVERAGE_VALUE < $MIN_COVERAGE" | bc -l) )); then
    echo "❌ 覆盖率 ${COVERAGE_VALUE}% 低于阈值 ${MIN_COVERAGE}%"
    # 可选:生成HTML报告便于查看
    coverage html -d "$REPORT_DIR"
    echo "详细报告已生成: $REPORT_DIR/index.html"
    exit 1
fi
echo "✅ 覆盖率检查通过: ${COVERAGE_VALUE}%"
# 清理临时文件
rm -f coverage_report.txt

Python 版本的钩子脚本

#!/usr/bin/env python3
# .git/hooks/pre-commit
import re
import sys
import subprocess
import os
def check_coverage():
    """检查测试覆盖率"""
    # 设置覆盖率阈值
    THRESHOLD = 80
    # 运行测试并收集覆盖率
    try:
        result = subprocess.run(
            ["coverage", "run", "-m", "pytest", "tests/"],
            capture_output=True,
            text=True
        )
        if result.returncode != 0:
            print("❌ 测试失败")
            print(result.stdout)
            print(result.stderr)
            return False
        # 获取覆盖率报告
        result = subprocess.run(
            ["coverage", "report"],
            capture_output=True,
            text=True
        )
        # 解析覆盖率百分比
        match = re.search(r'TOTAL\s+\d+\s+\d+\s+(\d+)%', result.stdout)
        if match:
            coverage = float(match.group(1))
            print(f"当前覆盖率: {coverage}%")
            if coverage < THRESHOLD:
                print(f"❌ 覆盖率 {coverage}% 低于阈值 {THRESHOLD}%")
                return False
            print(f"✅ 覆盖率检查通过: {coverage}%")
            return True
        else:
            print("❌ 无法解析覆盖率信息")
            return False
    except Exception as e:
        print(f"❌ 检查覆盖时发生错误: {e}")
        return False
if __name__ == "__main__":
    if not check_coverage():
        sys.exit(1)
    sys.exit(0)

只检查变更文件的覆盖率

#!/bin/bash
# .git/hooks/pre-commit
# 获取本次变更的Python文件
CHANGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep "\.py$")
if [ -z "$CHANGED_FILES" ]; then
    echo "没有Python文件变更,跳过覆盖率检查"
    exit 0
fi
echo "变更的文件:"
echo "$CHANGED_FILES"
# 只运行涉及变更文件的测试
coverage run -m pytest tests/ -k "$(echo $CHANGED_FILES | tr '\n' '|')"
# 创建覆盖率报告
coverage report --include="$CHANGED_FILES"
COVERAGE=$(coverage report --include="$CHANGED_FILES" | grep -E "^TOTAL" | awk '{print $NF}' | sed 's/%//')
THRESHOLD=80
if [ -z "$COVERAGE" ]; then
    echo "⚠️ 无法获取变更文件的覆盖率信息"
elif (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then
    echo "❌ 变更文件覆盖率 ${COVERAGE}% 低于阈值 ${THRESHOLD}%"
    exit 1
fi
echo "✅ 覆盖率检查通过"

安装钩子的脚本

创建一个脚本来安装这些钩子:

#!/bin/bash
# setup-hooks.sh
HOOK_DIR=".git/hooks"
TEMPLATE_DIR="githooks"
# 创建钩子目录
mkdir -p "$HOOK_DIR"
# 复制pre-commit钩子
cp "$TEMPLATE_DIR/pre-commit" "$HOOK_DIR/pre-commit"
chmod +x "$HOOK_DIR/pre-commit"
echo "✅ Git钩子已安装"

配置文件和高级选项

.coveragerc 配置文件

[run]
source = src
omit = 
    */tests/*
    */test_*.py
    */setup.py
[report]
exclude_lines =
    pragma: no cover
    def __repr__
    def __str__
    if __name__ == .__main__.:
fail_under = 80
[html]
directory = coverage_report

高级覆盖率检查(包含分支覆盖率)

#!/bin/bash
# 检查分支覆盖率
coverage run --branch -m pytest tests/
# 生成详细报告
coverage report --show-missing --include="src/*"
# 获取分支覆盖率
BRANCH_COVERAGE=$(coverage report --show-missing | grep "TOTAL" | awk '{print $6}' | sed 's/%//')
LINE_COVERAGE=$(coverage report --show-missing | grep "TOTAL" | awk '{print $4}' | sed 's/%//')
echo "行覆盖率: ${LINE_COVERAGE}%"
echo "分支覆盖率: ${BRANCH_COVERAGE}%"
# 可以分别检查行覆盖率和分支覆盖率
if (( $(echo "$LINE_COVERAGE < 80" | bc -l) )); then
    echo "❌ 行覆盖率不达标"
    exit 1
fi
if (( $(echo "$BRANCH_COVERAGE < 70" | bc -l) )); then
    echo "❌ 分支覆盖率不达标"
    exit 1
fi

使用建议

  1. 选择合适的位置:建议使用 pre-commit 钩子,在提交前检查
  2. 设置合理的阈值:根据项目情况设置 70%-90% 的阈值
  3. 考虑性能:大型项目可以只检查变更的文件
  4. 跳过机制:允许特殊情况跳过检查(如紧急修复)
# 跳过钩子的方法
git commit -m "紧急修复" --no-verify
# 或
SKIP=coverage git commit -m "跳过覆盖率检查"

这样可以在保证代码质量的同时,不影响开发效率。

抱歉,评论功能暂时关闭!