PCCR - 완벽한 코드 커버리지 보고

Cover photo 조나단 쿠퍼


프로젝트에 완벽한 코드 커버리지가 있고 아무도, 심지어 당신도 그것에 대해 모른다면 비둘기가 울까요?

완벽을 달성할 수는 없지만 범위를 제한하면 달성할 수 있습니다. ;)

완벽한 코드 커버리지는 분기를 포함하여 100%를 의미합니다. 참고: 코드에 분기가 없을 때 가장 쉽게 달성할 수 있습니다!

완벽한 코드 커버리지 보고는 모든 사람에게 이에 대해 알리고, 배지를 달고, PR에 댓글을 남기는 것입니다.

거기에 어떻게 가나요?




나는 최근에 유니코드gem 문자 집합과 일치하는 표준 정규식을 제공하는 Gitmoji(예: Ruby 라이브러리)을 작성했습니다.

분기문이 없는 간단한 라이브러리는 완벽하게 커버리지를 얻기는 쉬웠지만 보고 완벽함을 얻기에는 약간 복잡했습니다...

내 예제에서는 내가 선택한 언어로 Ruby를 사용하지만 이것의 대부분, 특히 Github Actions Coverage Workflow는 모든 언어에 적용됩니다.


이익



README.md



오픈 소스 프로젝트에서 자기 홍보는 중요합니다.

README.md에는 이제 영광스러운 배지가 있습니다.



풀 리퀘스트 자동화



또한 프로젝트에 대한 PR은 CodeCoverageSummary Github Action에서 아래와 같은 주석을 받아야 합니다.




패키지
회선 속도
건강


gitmoji 정규식
100%


요약

100% (50/50)




도구



  • CodeClimate SASS

  • CodeCov SASS

  • Coveralls SASS

  • irongut/CodeCoverageSummary Github 작업

  • amancevice/setup-code-climate Github 작업

  • Coverage-related Gems 내가 사용하는 것:
  • gem "codecov", "~> 0.6" - 참고: codecov/codecov-action Github Action은 Ruby를 사용하지 않는 사람들을 위한 대안입니다. 예시를 남겼습니다in the coverage workflow
  • gem "simplecov", "~> 0.21", require: false
  • gem "simplecov-cobertura" Jenkins 또는 기타 도구에 대한 XML 형식 제공
  • gem 'simplecov-json' CodeClimate용 JSON 형식 제공
  • gem "simplecov-lcov", "~> 0.8", require: false lcov 형식 제공




  • 구현



    커버리지 워크플로



    이것은 모든 것을 하나로 묶는 고기와 감자입니다!

    name: Code Coverage
    
    env:
      CI_CODECOV: true
      COVER_ALL: true
    
    on:
      push:
        branches:
          - 'main'
          - '*-maintenance'
          - '*-dev'
          - '*-stable'
        tags:
          - '!*' # Do not execute on tags
      pull_request:
        branches:
          - '*'
      # Allow manually triggering the workflow.
      workflow_dispatch:
    
    # Cancels all previous workflow runs for the same branch that have not yet completed.
    concurrency:
      # The concurrency group contains the workflow name and the branch name.
      group: ${{ github.workflow }}-${{ github.ref }}
      cancel-in-progress: true
    
    jobs:
      test:
        name: Specs with Coverage - Ruby ${{ matrix.ruby }} ${{ matrix.name_extra || '' }}
        if: "!contains(github.event.commits[0].message, '[ci skip]') && !contains(github.event.commits[0].message, '[skip ci]')"
        strategy:
          fail-fast: false
          matrix:
            experimental: [false]
            rubygems:
              - latest
            bundler:
              - latest
            ruby:
              - "2.7"
    
        runs-on: ubuntu-latest
        continue-on-error: ${{ matrix.experimental || endsWith(matrix.ruby, 'head') }}
        steps:
          - uses: amancevice/setup-code-climate@v0
            name: CodeClimate Install
            if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
            with:
              cc_test_reporter_id: ${{ secrets.CC_TEST_REPORTER_ID }}
    
          - name: Checkout
            uses: actions/checkout@v3
    
          - name: Setup Ruby & Bundle
            uses: ruby/setup-ruby@v1
            with:
              ruby-version: ${{ matrix.ruby }}
              rubygems: ${{ matrix.rubygems }}
              bundler: ${{ matrix.bundler }}
              bundler-cache: true
    
          - name: CodeClimate Pre-build Notification
            run: cc-test-reporter before-build
            if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
          - name: Run tests
            run: bundle exec rake test
    
          - name: CodeClimate Post-build Notification
            run: cc-test-reporter after-build
            if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
          - name: Code Coverage Summary Report
            uses: irongut/[email protected]
            with:
              filename: ./coverage/coverage.xml
              badge: true
              fail_below_min: true
              format: markdown
              hide_branch_rate: true
              hide_complexity: true
              indicators: true
              output: both
              thresholds: '95 97'
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
          - name: Add Coverage PR Comment
            uses: marocchino/sticky-pull-request-comment@v2
            if: matrix.ruby == '2.7' && always()
            with:
              recreate: true
              path: code-coverage-results.md
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
          - name: Coveralls
            uses: coverallsapp/github-action@master
            if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
            with:
              github-token: ${{ secrets.GITHUB_TOKEN }}
            continue-on-error: ${{ matrix.experimental != 'false' }}
    
    #      Using the codecov gem instead.
    #      - name: CodeCov
    #        uses: codecov/codecov-action@v2
    #        if: matrix.ruby == '2.7' && github.event_name != 'pull_request' && always()
    #        with:
    #          files: ./coverage/coverage.xml
    #          flags: unittests
    #          name: codecov-upload
    #          fail_ci_if_error: true
    #        continue-on-error: ${{ matrix.experimental != 'false' }}
    


    심플코브



    상수 참고: 일부 상수는 아래에서 사용됩니다. RUN_COVERAGEALL_FORMATTERSspec/spec_helper.rb 구성이 로드되기 전에 실행되는 .simplecov 에 설정됩니다. 기타, 예. RUBY_ENGINE , RUBY_VERSION 은 표준 Ruby입니다.

    적용 범위를 확인하려면 코드를 로드하기 전에 require "simplecov" 해야 합니다.

    if RUN_COVERAGE
      require "simplecov" # Config file `.simplecov` is run immediately when simplecov loads
      require "codecov"
      require "simplecov-json"
      require "simplecov-lcov"
      require "simplecov-cobertura"
      # This will override any formatter set in .simplecov
      if ALL_FORMATTERS
        SimpleCov::Formatter::LcovFormatter.config do |c|
          c.report_with_single_file = true
          c.single_report_path = "coverage/lcov.info"
        end
    
        SimpleCov.formatters = [
          SimpleCov::Formatter::HTMLFormatter,
          SimpleCov::Formatter::CoberturaFormatter,
          SimpleCov::Formatter::LcovFormatter,
          SimpleCov::Formatter::JSONFormatter, # For CodeClimate
          SimpleCov::Formatter::Codecov # For CodeCov
        ]
      end
    end
    
    


    아래와 같이 .simplecov 구성으로 구성합니다.

    # frozen_string_literal: true
    
    # To get coverage
    # On Local, default (HTML) output, it just works, coverage is turned on:
    #   bundle exec rspec spec
    # On Local, all output formats:
    #   COVER_ALL=true bundle exec rspec spec
    #
    # On CI, all output formats, the ENV variables CI is always set,
    #   and COVER_ALL, and CI_CODECOV, are set in the coverage.yml workflow only,
    #   so coverage only runs in that workflow, and outputs all formats.
    #
    
    if RUN_COVERAGE
      SimpleCov.start do
        enable_coverage :branch
        primary_coverage :branch
        add_filter "test"
        track_files "**/*.rb"
    
        if ALL_FORMATTERS
          command_name "#{ENV["GITHUB_WORKFLOW"]} Job #{ENV["GITHUB_RUN_ID"]}:#{ENV["GITHUB_RUN_NUMBER"]}"
        else
          formatter SimpleCov::Formatter::HTMLFormatter
        end
    
        minimum_coverage(100)
      end
    else
      puts "Not running coverage on #{RUBY_ENGINE} #{RUBY_VERSION}"
    end
    



    최종 결과



    Github Actions Run

    RSpec 대신 MiniTest를 사용하고 (아직) 100% 테스트 커버리지가 없는 oauth gem을 포함하여 다른 gem에서 이 패턴을 다시 구현했습니다. 대부분의 구현은 동일합니다.

    좋은 웹페이지 즐겨찾기