diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index f7780a9db85..640aa85bb19 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -80,8 +80,31 @@ jobs: restore-keys: | parallel-runtime-postgres-${{ matrix.image }}- parallel-runtime-postgres- + - name: Clear previous coverage + if: matrix.image == 'postgres:17' + run: rm -rf coverage - name: Run tests + env: + COVERAGE: ${{ matrix.image == 'postgres:17' && 'true' || '' }} run: DB=postgres POSTGRES_CONNECTION_PREFIX="postgres://postgres:rootpassword@localhost:5432" RSPEC_PROFILE="${{ inputs.rspec_profile }}" bundle exec rake spec + - name: Report coverage + if: matrix.image == 'postgres:17' + run: | + pct=$(ruby -rjson -e 'puts JSON.parse(File.read("coverage/coverage.json"))["total"]["lines"]["percent"].round(2)') + echo "Total line coverage: ${pct}%" + echo "## Test coverage: ${pct}%" >> "$GITHUB_STEP_SUMMARY" + - name: Upload coverage report + if: matrix.image == 'postgres:17' + uses: actions/upload-artifact@v7 + with: + name: coverage-report + path: | + coverage/*.html + coverage/*.css + coverage/*.js + coverage/*.png + coverage/coverage.json + retention-days: 7 - name: Save parallel_rspec runtime logs if: always() && github.ref == 'refs/heads/main' uses: actions/cache/save@v6 diff --git a/.simplecov b/.simplecov new file mode 100644 index 00000000000..3a423823017 --- /dev/null +++ b/.simplecov @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Namespaced command_name + long merge_timeout so spec:all's three invocations merge, not overwrite. +SimpleCov.configure do + skip '/spec/' + skip '/errors/' + skip '/docs/' + + merging true + merge_timeout 3600 + + suite = ENV.fetch('COVERAGE_SUITE', 'default') + worker = ENV['TEST_ENV_NUMBER'].to_s + worker = '1' if worker.empty? + command_name "#{suite}-#{worker}" +end diff --git a/Gemfile b/Gemfile index a3151c8186f..ae74c619809 100644 --- a/Gemfile +++ b/Gemfile @@ -51,7 +51,6 @@ group :operations do end group :test do - gem 'codeclimate-test-reporter', '>= 1.0.8', require: false gem 'factory_bot', '~> 6.5' gem 'mock_redis' gem 'parallel_tests' @@ -70,6 +69,7 @@ group :test do gem 'rubocop-rspec', '~> 3.10' gem 'rubocop-rspec_rails' gem 'rubocop-sequel', '~> 0.4.1' + gem 'simplecov', '~> 1.0', require: false gem 'timecop' gem 'webmock', '> 2.3.1' gem 'webrick', '~> 1.9.2' diff --git a/Gemfile.lock b/Gemfile.lock index 8a5ac3ecb21..90e89da2f8a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -54,8 +54,6 @@ GEM clockwork (4.0.1) activesupport tzinfo - codeclimate-test-reporter (1.0.9) - simplecov (<= 0.13) coderay (1.1.3) commander (5.0.0) highline (~> 3.0.0) @@ -75,7 +73,6 @@ GEM logger diff-lcs (1.6.2) digest-xxhash (0.2.9) - docile (1.1.5) drb (2.2.3) erb (6.0.6) erubi (1.13.1) @@ -356,11 +353,7 @@ GEM pg (>= 0.18.0, != 1.2.0) sequel (>= 4.38.0) sexp_processor (4.17.5) - simplecov (0.13.0) - docile (~> 1.1.0) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.2) + simplecov (1.0.3) sinatra (4.2.1) logger (>= 1.6.0) mustermann (~> 3.0) @@ -453,7 +446,6 @@ DEPENDENCIES byebug cf-uaa-lib (~> 4.0.10) clockwork - codeclimate-test-reporter (>= 1.0.8) concurrent-ruby debug (~> 1.11) digest-xxhash @@ -503,6 +495,7 @@ DEPENDENCIES rubyzip (>= 1.3.0) sequel (~> 5.106) sequel_pg + simplecov (~> 1.0) sinatra (~> 4.2) sinatra-contrib solargraph diff --git a/README.md b/README.md index ca64ba13876..b4a8c4e0ce7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -[![Code Climate](https://api.codeclimate.com/v1/badges/aa47fb93c59ced5fcc4f/maintainability)](https://codeclimate.com/github/cloudfoundry/cloud_controller_ng) -[![Code Climate](https://api.codeclimate.com/v1/badges/aa47fb93c59ced5fcc4f/test_coverage)](https://codeclimate.com/github/cloudfoundry/cloud_controller_ng) +[![Maintainability](https://qlty.sh/gh/cloudfoundry/projects/cloud_controller_ng/maintainability.svg)](https://qlty.sh/gh/cloudfoundry/projects/cloud_controller_ng) [![slack.cloudfoundry.org](https://slack.cloudfoundry.org/badge.svg)](https://cloudfoundry.slack.com/messages/capi/) # Welcome to the Cloud Controller diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake index f8ea26c9e89..d11a9fae89d 100644 --- a/lib/tasks/spec.rake +++ b/lib/tasks/spec.rake @@ -4,11 +4,11 @@ task spec: 'spec:all' namespace :spec do task all: ['db:pick', 'db:parallel:recreate'] do if ARGV[1] - run_specs(ARGV[1]) + run_specs(ARGV[1], coverage_env('adhoc')) else - run_specs_parallel('spec') - run_migration_specs_parallel - run_specs('spec/isolated_specs') + run_specs_parallel('spec', coverage_env('main')) + run_migration_specs_parallel(coverage_env('migrations')) + run_specs('spec/isolated_specs', coverage_env('isolated')) end end @@ -70,6 +70,13 @@ namespace :spec do ENV['RSPEC_PROFILE'].to_s.empty? ? '' : "--profile #{ENV.fetch('RSPEC_PROFILE', nil)}" end + # Guard is required: ENV['COVERAGE'] == '' is truthy in Ruby. + def coverage_env(suite) + return '' unless ENV['COVERAGE'] && !ENV['COVERAGE'].empty? + + "COVERAGE=true COVERAGE_SUITE=#{suite} " + end + def run_failed_specs sh 'bundle exec rspec --only-failures --color --tty spec --require rspec/instafail --format RSpec::Instafail' end diff --git a/spec/spec_helper_helper.rb b/spec/spec_helper_helper.rb index e573a68c01c..99aa7e9dd81 100644 --- a/spec/spec_helper_helper.rb +++ b/spec/spec_helper_helper.rb @@ -10,11 +10,7 @@ def self.init if ENV['COVERAGE'] require 'simplecov' - SimpleCov.start do - add_filter '/spec/' - add_filter '/errors/' - add_filter '/docs/' - end + SimpleCov.start end ENV['PB_IGNORE_DEPRECATIONS'] = 'true' ENV['RAILS_ENV'] ||= 'test' @@ -98,7 +94,7 @@ def self.each_run rspec_config.include SpaceRestrictedResponseGenerators rspec_config.before(:all) do - WebMock.disable_net_connect!(allow: %w[codeclimate.com fake.bbs]) + WebMock.disable_net_connect!(allow: %w[fake.bbs]) end rspec_config.before(:all, type: :integration) do WebMock.allow_net_connect! @@ -109,7 +105,7 @@ def self.each_run skip 'Skipped due to NO_DB_MIGRATION env variable being set' if ENV['NO_DB_MIGRATION'] end rspec_config.after(:all, type: :integration) do - WebMock.disable_net_connect!(allow: %w[codeclimate.com fake.bbs]) + WebMock.disable_net_connect!(allow: %w[fake.bbs]) @uaa_server.stop end