Commit 0be786d5 authored by charlie ablett's avatar charlie ablett

Merge branch '28317-coverage-limit-config' into 'master'

Added support for test coverage badge color configuration

See merge request gitlab-org/gitlab!69164
parents 8931be02 13ca69c7
...@@ -24,7 +24,10 @@ class Projects::BadgesController < Projects::ApplicationController ...@@ -24,7 +24,10 @@ class Projects::BadgesController < Projects::ApplicationController
.new(project, params[:ref], opts: { .new(project, params[:ref], opts: {
job: params[:job], job: params[:job],
key_text: params[:key_text], key_text: params[:key_text],
key_width: params[:key_width] key_width: params[:key_width],
min_good: params[:min_good],
min_acceptable: params[:min_acceptable],
min_medium: params[:min_medium]
}) })
render_badge coverage_report render_badge coverage_report
......
...@@ -358,6 +358,29 @@ in your `README.md`: ...@@ -358,6 +358,29 @@ in your `README.md`:
![coverage](https://gitlab.com/gitlab-org/gitlab/badges/main/coverage.svg?job=coverage) ![coverage](https://gitlab.com/gitlab-org/gitlab/badges/main/coverage.svg?job=coverage)
``` ```
#### Test coverage report badge colors and limits
The default colors and limits for the badge are as follows:
- 95 up to and including 100% - good (`#4c1`)
- 90 up to 95% - acceptable (`#a3c51c`)
- 75 up to 90% - medium (`#dfb317`)
- 0 up to 75% - low (`#e05d44`)
- no coverage - unknown (`#9f9f9f`)
NOTE:
*Up to* means up to, but not including, the upper bound.
You can overwrite the limits by using the following additional parameters ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/28317) in GitLab 14.4):
- `min_good` (default 95, can use any value between 3 and 100)
- `min_acceptable` (default 90, can use any value between 2 and min_good-1)
- `min_medium` (default 75, can use any value between 1 and min_acceptable-1)
If an invalid boundary is set, GitLab automatically adjusts it to be valid. For example,
if `min_good` is set `80`, and `min_acceptable` is set to `85` (too high), GitLab automatically
sets `min_acceptable` to `79` (`min_good` - `1`).
### Badge styles ### Badge styles
Pipeline badges can be rendered in different styles by adding the `style=style_name` parameter to the URL. Two styles are available: Pipeline badges can be rendered in different styles by adding the `style=style_name` parameter to the URL. Two styles are available:
......
...@@ -15,7 +15,10 @@ module Gitlab::Ci ...@@ -15,7 +15,10 @@ module Gitlab::Ci
@job = opts[:job] @job = opts[:job]
@customization = { @customization = {
key_width: opts[:key_width].to_i, key_width: opts[:key_width].to_i,
key_text: opts[:key_text] key_text: opts[:key_text],
min_good: opts[:min_good].to_i,
min_acceptable: opts[:min_acceptable].to_i,
min_medium: opts[:min_medium].to_i
} }
end end
......
...@@ -16,12 +16,20 @@ module Gitlab::Ci ...@@ -16,12 +16,20 @@ module Gitlab::Ci
low: '#e05d44', low: '#e05d44',
unknown: '#9f9f9f' unknown: '#9f9f9f'
}.freeze }.freeze
COVERAGE_MAX = 100
COVERAGE_MIN = 0
MIN_GOOD_DEFAULT = 95
MIN_ACCEPTABLE_DEFAULT = 90
MIN_MEDIUM_DEFAULT = 75
def initialize(badge) def initialize(badge)
@entity = badge.entity @entity = badge.entity
@status = badge.status @status = badge.status
@key_text = badge.customization.dig(:key_text) @key_text = badge.customization.dig(:key_text)
@key_width = badge.customization.dig(:key_width) @key_width = badge.customization.dig(:key_width)
@min_good = badge.customization.dig(:min_good)
@min_acceptable = badge.customization.dig(:min_acceptable)
@min_medium = badge.customization.dig(:min_medium)
end end
def value_text def value_text
...@@ -32,12 +40,36 @@ module Gitlab::Ci ...@@ -32,12 +40,36 @@ module Gitlab::Ci
@status ? 54 : 58 @status ? 54 : 58
end end
def min_good_value
if @min_good && @min_good.between?(3, COVERAGE_MAX)
@min_good
else
MIN_GOOD_DEFAULT
end
end
def min_acceptable_value
if @min_acceptable && @min_acceptable.between?(2, min_good_value - 1)
@min_acceptable
else
[MIN_ACCEPTABLE_DEFAULT, (min_good_value - 1)].min
end
end
def min_medium_value
if @min_medium && @min_medium.between?(1, min_acceptable_value - 1)
@min_medium
else
[MIN_MEDIUM_DEFAULT, (min_acceptable_value - 1)].min
end
end
def value_color def value_color
case @status case @status
when 95..100 then STATUS_COLOR[:good] when min_good_value..COVERAGE_MAX then STATUS_COLOR[:good]
when 90..95 then STATUS_COLOR[:acceptable] when min_acceptable_value..min_good_value then STATUS_COLOR[:acceptable]
when 75..90 then STATUS_COLOR[:medium] when min_medium_value..min_acceptable_value then STATUS_COLOR[:medium]
when 0..75 then STATUS_COLOR[:low] when COVERAGE_MIN..min_medium_value then STATUS_COLOR[:low]
else else
STATUS_COLOR[:unknown] STATUS_COLOR[:unknown]
end end
......
...@@ -12,6 +12,120 @@ RSpec.describe 'test coverage badge' do ...@@ -12,6 +12,120 @@ RSpec.describe 'test coverage badge' do
sign_in(user) sign_in(user)
end end
it 'user requests coverage badge image for pipeline with custom limits - 80% good' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 80, name: 'test:1')
end
show_test_coverage_badge(min_good: 75, min_acceptable: 50, min_medium: 25)
expect_coverage_badge_color(:good)
expect_coverage_badge('80.00%')
end
it 'user requests coverage badge image for pipeline with custom limits - 74% - bad config' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 74, name: 'test:1')
end
# User sets a minimum good value that is lower than min acceptable and min medium,
# in which case we force the min acceptable value to be min good -1 and min medium value to be min acceptable -1
show_test_coverage_badge(min_good: 75, min_acceptable: 76, min_medium: 77)
expect_coverage_badge_color(:acceptable)
expect_coverage_badge('74.00%')
end
it 'user requests coverage badge image for pipeline with custom limits - 73% - bad config' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 73, name: 'test:1')
end
# User sets a minimum good value that is lower than min acceptable and min medium,
# in which case we force the min acceptable value to be min good -1 and min medium value to be min acceptable -1
show_test_coverage_badge(min_good: 75, min_acceptable: 76, min_medium: 77)
expect_coverage_badge_color(:medium)
expect_coverage_badge('73.00%')
end
it 'user requests coverage badge image for pipeline with custom limits - 72% - partial config - low' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 72, name: 'test:1')
end
# User only sets good to 75 and leaves the others on the default settings,
# in which case we force the min acceptable value to be min good -1 and min medium value to be min acceptable -1
show_test_coverage_badge(min_good: 75)
expect_coverage_badge_color(:low)
expect_coverage_badge('72.00%')
end
it 'user requests coverage badge image for pipeline with custom limits - 72% - partial config - medium' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 72, name: 'test:1')
end
# User only sets good to 74 and leaves the others on the default settings,
# in which case we force the min acceptable value to be min good -1 and min medium value to be min acceptable -1
show_test_coverage_badge(min_good: 74)
expect_coverage_badge_color(:medium)
expect_coverage_badge('72.00%')
end
it 'user requests coverage badge image for pipeline with custom limits - 72% - partial config - medium v2' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 72, name: 'test:1')
end
# User only sets medium to 72 and leaves the others on the defaults good as 95 and acceptable as 90
show_test_coverage_badge(min_medium: 72)
expect_coverage_badge_color(:medium)
expect_coverage_badge('72.00%')
end
it 'user requests coverage badge image for pipeline with custom limits - 70% acceptable' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 70, name: 'test:1')
end
show_test_coverage_badge(min_good: 75, min_acceptable: 50, min_medium: 25)
expect_coverage_badge_color(:acceptable)
expect_coverage_badge('70.00%')
end
it 'user requests coverage badge image for pipeline with custom limits - 30% medium' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 30, name: 'test:1')
end
show_test_coverage_badge(min_good: 75, min_acceptable: 50, min_medium: 25)
expect_coverage_badge_color(:medium)
expect_coverage_badge('30.00%')
end
it 'user requests coverage badge image for pipeline with custom limits - 20% low' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 20, name: 'test:1')
end
show_test_coverage_badge(min_good: 75, min_acceptable: 50, min_medium: 25)
expect_coverage_badge_color(:low)
expect_coverage_badge('20.00%')
end
it 'user requests coverage badge image for pipeline with custom limits - nonsense values which use the defaults' do
create_pipeline do |pipeline|
create_build(pipeline, coverage: 92, name: 'test:1')
end
show_test_coverage_badge(min_good: "nonsense", min_acceptable: "rubbish", min_medium: "NaN")
expect_coverage_badge_color(:acceptable)
expect_coverage_badge('92.00%')
end
it 'user requests coverage badge image for pipeline' do it 'user requests coverage badge image for pipeline' do
create_pipeline do |pipeline| create_pipeline do |pipeline|
create_build(pipeline, coverage: 100, name: 'test:1') create_build(pipeline, coverage: 100, name: 'test:1')
...@@ -20,6 +134,7 @@ RSpec.describe 'test coverage badge' do ...@@ -20,6 +134,7 @@ RSpec.describe 'test coverage badge' do
show_test_coverage_badge show_test_coverage_badge
expect_coverage_badge_color(:good)
expect_coverage_badge('95.00%') expect_coverage_badge('95.00%')
end end
...@@ -32,6 +147,7 @@ RSpec.describe 'test coverage badge' do ...@@ -32,6 +147,7 @@ RSpec.describe 'test coverage badge' do
show_test_coverage_badge(job: 'coverage') show_test_coverage_badge(job: 'coverage')
expect_coverage_badge_color(:medium)
expect_coverage_badge('85.00%') expect_coverage_badge('85.00%')
end end
...@@ -73,8 +189,9 @@ RSpec.describe 'test coverage badge' do ...@@ -73,8 +189,9 @@ RSpec.describe 'test coverage badge' do
create(:ci_build, :success, opts) create(:ci_build, :success, opts)
end end
def show_test_coverage_badge(job: nil) def show_test_coverage_badge(job: nil, min_good: nil, min_acceptable: nil, min_medium: nil)
visit coverage_project_badges_path(project, ref: :master, job: job, format: :svg) visit coverage_project_badges_path(project, ref: :master, job: job, min_good: min_good,
min_acceptable: min_acceptable, min_medium: min_medium, format: :svg)
end end
def expect_coverage_badge(coverage) def expect_coverage_badge(coverage)
...@@ -82,4 +199,12 @@ RSpec.describe 'test coverage badge' do ...@@ -82,4 +199,12 @@ RSpec.describe 'test coverage badge' do
expect(page.response_headers['Content-Type']).to include('image/svg+xml') expect(page.response_headers['Content-Type']).to include('image/svg+xml')
expect(svg.at(%Q{text:contains("#{coverage}")})).to be_truthy expect(svg.at(%Q{text:contains("#{coverage}")})).to be_truthy
end end
def expect_coverage_badge_color(color)
svg = Nokogiri::HTML(page.body)
expect(page.response_headers['Content-Type']).to include('image/svg+xml')
badge_color = svg.xpath("//path[starts-with(@d, 'M62')]")[0].attributes['fill'].to_s
expected_badge_color = Gitlab::Ci::Badge::Coverage::Template::STATUS_COLOR[color]
expect(badge_color).to eq(expected_badge_color)
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment