Appearance
CI/CD 集成
在持续集成系统中使用 Anvil 代码覆盖率。
GitHub Actions
基础配置
yaml
name: Test with Coverage
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y gcc lcov
- name: Install Anvil
run: |
go build -o anvil ./cmd/anvil
sudo mv anvil /usr/local/bin/
- name: Build with coverage flags
run: make COVERAGE=1
- name: Run tests with coverage
run: anvil --coverage --coverage-format=lcov
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: coverage/coverage.info完整配置(含 HTML 报告)
yaml
name: Test with Coverage
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y gcc lcov
- name: Build with coverage flags
run: |
make clean
make COVERAGE=1
- name: Run tests with coverage
run: anvil --coverage --coverage-format=html --coverage-exclude="*/tests/*"
- name: Upload coverage report
uses: actions/upload-artifact@v3
with:
name: coverage-report
path: coverage/html/
- name: Upload to Codecov
uses: codecov/codecov-action@v3
with:
files: coverage/coverage.info
fail_ci_if_error: trueGitLab CI
yaml
stages:
- build
- test
- coverage
build:
stage: build
script:
- make clean
- make COVERAGE=1
artifacts:
paths:
- build/
test:
stage: test
script:
- anvil --coverage --coverage-format=lcov
artifacts:
paths:
- coverage/
reports:
coverage_report:
coverage_format: cobertura
path: coverage/coverage.xml
pages:
stage: coverage
script:
- anvil --coverage --coverage-format=html
- mv coverage/html public
artifacts:
paths:
- public
only:
- mainJenkins
Jenkinsfile
groovy
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'make clean'
sh 'make COVERAGE=1'
}
}
stage('Test') {
steps {
sh 'anvil --coverage --coverage-format=cobertura'
}
}
stage('Coverage Report') {
steps {
publishCoverage adapters: [coberturaAdapter('coverage/coverage.xml')]
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'coverage/html',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
}
post {
always {
archiveArtifacts artifacts: 'coverage/**/*'
}
}
}Makefile 配置
支持覆盖率编译的 Makefile:
makefile
CC = gcc
CFLAGS = -Wall -Wextra
ifdef COVERAGE
CFLAGS += -fprofile-arcs -ftest-coverage
LDFLAGS += -lgcov
endif
SOURCES := $(wildcard src/**/*.c)
OBJECTS := $(SOURCES:src/%.c=build/%.o)
all: $(OBJECTS)
build/%.o: src/%.c
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) -c $< -o $@ -Iinclude
clean:
rm -rf build coverage *.gcno *.gcda
.PHONY: all clean使用方式:
bash
# 普通构建
make
# 覆盖率构建
make COVERAGE=1覆盖率阈值
在 CI 中设置阈值
yaml
- name: Check coverage threshold
run: |
COVERAGE=$(lcov --summary coverage/coverage.info | grep "lines" | awk '{print $2}' | tr -d '%')
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "Coverage $COVERAGE% is below threshold 80%"
exit 1
fi
echo "Coverage $COVERAGE% meets threshold"Codecov 配置
创建 codecov.yml:
yaml
coverage:
precision: 2
round: down
range: "70...100"
status:
project:
default:
target: 80%
threshold: 2%
patch:
default:
target: 80%
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
ignore:
- "tests/**/*"
- "mocks/**/*"SonarQube 集成
yaml
- name: Run SonarQube analysis
run: |
anvil --coverage --coverage-format=lcov
sonar-scanner \
-Dsonar.projectKey=my-project \
-Dsonar.sources=src \
-Dsonar.tests=tests \
-Dsonar.coverageReportPaths=coverage/coverage.info最佳实践
1. 始终排除测试代码
yaml
anvil --coverage --coverage-exclude="*/tests/*,*/mocks/*"2. 在干净环境中运行
bash
make clean
make COVERAGE=1
anvil --coverage3. 使用 Cobertura 格式
大多数 CI 系统原生支持 Cobertura 格式:
bash
anvil --coverage --coverage-format=cobertura4. 保存覆盖率趋势
在 CI 中保存历史数据,跟踪覆盖率变化趋势。
5. 设置合理阈值
- 新项目:从 50% 开始,逐步提高
- 成熟项目:80% 或更高
- 关键模块:90% 或更高