Skip to content

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: true

GitLab 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:
    - main

Jenkins

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 --coverage

3. 使用 Cobertura 格式

大多数 CI 系统原生支持 Cobertura 格式:

bash
anvil --coverage --coverage-format=cobertura

4. 保存覆盖率趋势

在 CI 中保存历史数据,跟踪覆盖率变化趋势。

5. 设置合理阈值

  • 新项目:从 50% 开始,逐步提高
  • 成熟项目:80% 或更高
  • 关键模块:90% 或更高

本页面内容遵循 Luna 软件源代码授权条款 (LSLA) 发布