Commit 804fa437 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'feature/test-coverage-badge' into 'master'

Add test coverage badge

## What does this MR do?

This MR adds a test coverage badge.

Test coverage badge will be a SVG image you can embed in README.md or on your website that will be created dynamically by GitLab, to show information about how much of the code is being covered by tests. In addition to coverage-regexp feature we currently have, this feature will make it possible to use the coverage data obtained from the build log. We will support both - pipeline coverage, or test coverage for particular job in the pipeline. 

![coverage_badges](/uploads/dfa307339eb58c8138e551b42c0d8756/coverage_badges.png)

![coverage_badge](/uploads/30406e4bdcf979b2900ffe8996728c97/coverage_badge.png)

## What are the relevant issue numbers?

Closes #3714

## Screenshots (if relevant)

## Does this MR meet the acceptance criteria?

- [x] [CHANGELOG](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG) entry added
- [x] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)
- [ ] ~~API support added~~
- Tests
  - [x] Added for this feature/bug
  - [x] All builds are passing
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] Branch has no merge conflicts with `master` (if you do - rebase it please)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)

See merge request !5708
parents 9618abcb 48c4c8f0
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.11.0 (unreleased) v 8.11.0 (unreleased)
- Add test coverage report badge. !5708
- Remove the http_parser.rb dependency by removing the tinder gem. !5758 (tbalthazar) - Remove the http_parser.rb dependency by removing the tinder gem. !5758 (tbalthazar)
- Ability to specify branches for Pivotal Tracker integration (Egor Lynko) - Ability to specify branches for Pivotal Tracker integration (Egor Lynko)
- Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres) - Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres)
......
...@@ -4,11 +4,24 @@ class Projects::BadgesController < Projects::ApplicationController ...@@ -4,11 +4,24 @@ class Projects::BadgesController < Projects::ApplicationController
before_action :no_cache_headers, except: [:index] before_action :no_cache_headers, except: [:index]
def build def build
badge = Gitlab::Badge::Build.new(project, params[:ref]) build_status = Gitlab::Badge::Build::Status
.new(project, params[:ref])
render_badge build_status
end
def coverage
coverage_report = Gitlab::Badge::Coverage::Report
.new(project, params[:ref], params[:job])
render_badge coverage_report
end
private
def render_badge(badge)
respond_to do |format| respond_to do |format|
format.html { render_404 } format.html { render_404 }
format.svg do format.svg do
render 'badge', locals: { badge: badge.template } render 'badge', locals: { badge: badge.template }
end end
......
...@@ -3,7 +3,13 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController ...@@ -3,7 +3,13 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
def show def show
@ref = params[:ref] || @project.default_branch || 'master' @ref = params[:ref] || @project.default_branch || 'master'
@build_badge = Gitlab::Badge::Build.new(@project, @ref).metadata
@badges = [Gitlab::Badge::Build::Status,
Gitlab::Badge::Coverage::Report]
@badges.map! do |badge|
badge.new(@project, @ref).metadata
end
end end
def update def update
......
.row{ class: badge.title.gsub(' ', '-') }
.col-lg-3.profile-settings-sidebar
%h4.prepend-top-0
= badge.title.capitalize
.col-lg-9
.prepend-top-10
.panel.panel-default
.panel-heading
%b
= badge.title.capitalize
&middot;
= badge.to_html
.pull-right
= render 'shared/ref_switcher', destination: 'badges', align_right: true
.panel-body
.row
.col-md-2.text-center
Markdown
.col-md-10.code.js-syntax-highlight
= highlight('.md', badge.to_markdown)
.row
%hr
.row
.col-md-2.text-center
HTML
.col-md-10.code.js-syntax-highlight
= highlight('.html', badge.to_html)
...@@ -77,27 +77,4 @@ ...@@ -77,27 +77,4 @@
%hr %hr
.row.prepend-top-default .row.prepend-top-default
.col-lg-3.profile-settings-sidebar = render partial: 'badge', collection: @badges
%h4.prepend-top-0
Builds Badge
.col-lg-9
.prepend-top-10
.panel.panel-default
.panel-heading
%b Builds badge &middot;
= @build_badge.to_html
.pull-right
= render 'shared/ref_switcher', destination: 'badges', align_right: true
.panel-body
.row
.col-md-2.text-center
Markdown
.col-md-10.code.js-syntax-highlight
= highlight('.md', @build_badge.to_markdown)
.row
%hr
.row
.col-md-2.text-center
HTML
.col-md-10.code.js-syntax-highlight
= highlight('.html', @build_badge.to_html)
...@@ -869,7 +869,10 @@ Rails.application.routes.draw do ...@@ -869,7 +869,10 @@ Rails.application.routes.draw do
resources :badges, only: [:index] do resources :badges, only: [:index] do
collection do collection do
scope '*ref', constraints: { ref: Gitlab::Regex.git_reference_regex } do scope '*ref', constraints: { ref: Gitlab::Regex.git_reference_regex } do
get :build, constraints: { format: /svg/ } constraints format: /svg/ do
get :build
get :coverage
end
end end
end end
end end
......
...@@ -32,6 +32,41 @@ project. ...@@ -32,6 +32,41 @@ project.
Clicking on a pipeline will show the builds that were run for that pipeline. Clicking on a pipeline will show the builds that were run for that pipeline.
## Badges
There are build status and test coverage report badges available.
Go to pipeline settings to see available badges and code you can use to embed
badges in the `README.md` or your website.
### Build status badge
You can access a build status badge image using following link:
```
http://example.gitlab.com/namespace/project/badges/branch/build.svg
```
### Test coverage report badge
GitLab makes it possible to define the regular expression for coverage report,
that each build log will be matched against. This means that each build in the
pipeline can have the test coverage percentage value defined.
You can access test coverage badge using following link:
```
http://example.gitlab.com/namespace/project/badges/branch/coverage.svg
```
If you would like to get the coverage report from the specific job, you can add
a `job=coverage_job_name` parameter to the URL. For example, it is possible to
use following Markdown code to embed the est coverage report into `README.md`:
```markdown
![coverage](http://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)
```
[builds]: #builds [builds]: #builds
[jobs]: yaml/README.md#jobs [jobs]: yaml/README.md#jobs
[stages]: yaml/README.md#stages [stages]: yaml/README.md#stages
......
...@@ -218,21 +218,13 @@ project's settings. ...@@ -218,21 +218,13 @@ project's settings.
For more information read the For more information read the
[Builds emails service documentation](../../project_services/builds_emails.md). [Builds emails service documentation](../../project_services/builds_emails.md).
## Builds badge
You can access a builds badge image using following link:
```
http://example.gitlab.com/namespace/project/badges/branch/build.svg
```
Awesome! You started using CI in GitLab!
## Examples ## Examples
Visit the [examples README][examples] to see a list of examples using GitLab Visit the [examples README][examples] to see a list of examples using GitLab
CI with various languages. CI with various languages.
Awesome! You started using CI in GitLab!
[runner-install]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/tree/master#install-gitlab-runner [runner-install]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/tree/master#install-gitlab-runner
[blog-ci]: https://about.gitlab.com/2015/05/06/why-were-replacing-gitlab-ci-jobs-with-gitlab-ci-dot-yml/ [blog-ci]: https://about.gitlab.com/2015/05/06/why-were-replacing-gitlab-ci-jobs-with-gitlab-ci-dot-yml/
[examples]: ../examples/README.md [examples]: ../examples/README.md
......
module Gitlab
module Badge
class Base
def entity
raise NotImplementedError
end
def status
raise NotImplementedError
end
def metadata
raise NotImplementedError
end
def template
raise NotImplementedError
end
end
end
end
module Gitlab
module Badge
##
# Build badge
#
class Build
delegate :key_text, :value_text, to: :template
def initialize(project, ref)
@project = project
@ref = ref
@sha = @project.commit(@ref).try(:sha)
end
def status
@project.pipelines
.where(sha: @sha, ref: @ref)
.status || 'unknown'
end
def metadata
@metadata ||= Build::Metadata.new(@project, @ref)
end
def template
@template ||= Build::Template.new(status)
end
end
end
end
module Gitlab module Gitlab
module Badge module Badge
class Build module Build
## ##
# Class that describes build badge metadata # Class that describes build badge metadata
# #
class Metadata class Metadata < Badge::Metadata
include Gitlab::Application.routes.url_helpers def initialize(badge)
include ActionView::Helpers::AssetTagHelper @project = badge.project
include ActionView::Helpers::UrlHelper @ref = badge.ref
def initialize(project, ref)
@project = project
@ref = ref
end
def to_html
link_to(image_tag(image_url, alt: 'build status'), link_url)
end end
def to_markdown def title
"[![build status](#{image_url})](#{link_url})" 'build status'
end end
def image_url def image_url
......
module Gitlab
module Badge
module Build
##
# Build status badge
#
class Status < Badge::Base
attr_reader :project, :ref
def initialize(project, ref)
@project = project
@ref = ref
@sha = @project.commit(@ref).try(:sha)
end
def entity
'build'
end
def status
@project.pipelines
.where(sha: @sha, ref: @ref)
.status || 'unknown'
end
def metadata
@metadata ||= Build::Metadata.new(self)
end
def template
@template ||= Build::Template.new(self)
end
end
end
end
end
module Gitlab module Gitlab
module Badge module Badge
class Build module Build
## ##
# Class that represents a build badge template. # Class that represents a build badge template.
# #
# Template object will be passed to badge.svg.erb template. # Template object will be passed to badge.svg.erb template.
# #
class Template class Template < Badge::Template
STATUS_COLOR = { STATUS_COLOR = {
success: '#4c1', success: '#4c1',
failed: '#e05d44', failed: '#e05d44',
...@@ -17,16 +17,17 @@ module Gitlab ...@@ -17,16 +17,17 @@ module Gitlab
unknown: '#9f9f9f' unknown: '#9f9f9f'
} }
def initialize(status) def initialize(badge)
@status = status @entity = badge.entity
@status = badge.status
end end
def key_text def key_text
'build' @entity.to_s
end end
def value_text def value_text
@status @status.to_s
end end
def key_width def key_width
...@@ -37,25 +38,8 @@ module Gitlab ...@@ -37,25 +38,8 @@ module Gitlab
54 54
end end
def key_color
'#555'
end
def value_color def value_color
STATUS_COLOR[@status.to_sym] || STATUS_COLOR[@status.to_sym] || STATUS_COLOR[:unknown]
STATUS_COLOR[:unknown]
end
def key_text_anchor
key_width / 2
end
def value_text_anchor
key_width + (value_width / 2)
end
def width
key_width + value_width
end end
end end
end end
......
module Gitlab
module Badge
module Coverage
##
# Class that describes coverage badge metadata
#
class Metadata < Badge::Metadata
def initialize(badge)
@project = badge.project
@ref = badge.ref
@job = badge.job
end
def title
'coverage report'
end
def image_url
coverage_namespace_project_badges_url(@project.namespace,
@project, @ref,
format: :svg)
end
def link_url
namespace_project_commits_url(@project.namespace, @project, id: @ref)
end
end
end
end
end
module Gitlab
module Badge
module Coverage
##
# Test coverage report badge
#
class Report < Badge::Base
attr_reader :project, :ref, :job
def initialize(project, ref, job = nil)
@project = project
@ref = ref
@job = job
@pipeline = @project.pipelines
.where(ref: @ref)
.where(sha: @project.commit(@ref).try(:sha))
.first
end
def entity
'coverage'
end
def status
@coverage ||= raw_coverage
return unless @coverage
@coverage.to_i
end
def metadata
@metadata ||= Coverage::Metadata.new(self)
end
def template
@template ||= Coverage::Template.new(self)
end
private
def raw_coverage
return unless @pipeline
if @job.blank?
@pipeline.coverage
else
@pipeline.builds
.find_by(name: @job)
.try(:coverage)
end
end
end
end
end
end
module Gitlab
module Badge
module Coverage
##
# Class that represents a coverage badge template.
#
# Template object will be passed to badge.svg.erb template.
#
class Template < Badge::Template
STATUS_COLOR = {
good: '#4c1',
acceptable: '#a3c51c',
medium: '#dfb317',
low: '#e05d44',
unknown: '#9f9f9f'
}
def initialize(badge)
@entity = badge.entity
@status = badge.status
end
def key_text
@entity.to_s
end
def value_text
@status ? "#{@status}%" : 'unknown'
end
def key_width
62
end
def value_width
@status ? 36 : 58
end
def value_color
case @status
when 95..100 then STATUS_COLOR[:good]
when 90..95 then STATUS_COLOR[:acceptable]
when 75..90 then STATUS_COLOR[:medium]
when 0..75 then STATUS_COLOR[:low]
else
STATUS_COLOR[:unknown]
end
end
end
end
end
end
module Gitlab
module Badge
##
# Abstract class for badge metadata
#
class Metadata
include Gitlab::Application.routes.url_helpers
include ActionView::Helpers::AssetTagHelper
include ActionView::Helpers::UrlHelper
def initialize(badge)
@badge = badge
end
def to_html
link_to(image_tag(image_url, alt: title), link_url)
end
def to_markdown
"[![#{title}](#{image_url})](#{link_url})"
end
def title
raise NotImplementedError
end
def image_url
raise NotImplementedError
end
def link_url
raise NotImplementedError
end
end
end
end
module Gitlab
module Badge
##
# Abstract template class for badges
#
class Template
def initialize(badge)
@entity = badge.entity
@status = badge.status
end
def key_text
raise NotImplementedError
end
def value_text
raise NotImplementedError
end
def key_width
raise NotImplementedError
end
def value_width
raise NotImplementedError
end
def value_color
raise NotImplementedError
end
def key_color
'#555'
end
def key_text_anchor
key_width / 2
end
def value_text_anchor
key_width + (value_width / 2)
end
def width
key_width + value_width
end
end
end
end
require 'spec_helper'
feature 'test coverage badge' do
given!(:user) { create(:user) }
given!(:project) { create(:project, :private) }
given!(:pipeline) do
create(:ci_pipeline, project: project,
ref: 'master',
sha: project.commit.id)
end
context 'when user has access to view badge' do
background do
project.team << [user, :developer]
login_as(user)
end
scenario 'user requests coverage badge image for pipeline' do
create_job(coverage: 100, name: 'test:1')
create_job(coverage: 90, name: 'test:2')
show_test_coverage_badge
expect_coverage_badge('95%')
end
scenario 'user requests coverage badge for specific job' do
create_job(coverage: 50, name: 'test:1')
create_job(coverage: 50, name: 'test:2')
create_job(coverage: 85, name: 'coverage')
show_test_coverage_badge(job: 'coverage')
expect_coverage_badge('85%')
end
scenario 'user requests coverage badge for pipeline without coverage' do
create_job(coverage: nil, name: 'test')
show_test_coverage_badge
expect_coverage_badge('unknown')
end
end
context 'when user does not have access to view badge' do
background { login_as(user) }
scenario 'user requests test coverage badge image' do
show_test_coverage_badge
expect(page).to have_http_status(404)
end
end
def create_job(coverage:, name:)
create(:ci_build, name: name,
coverage: coverage,
pipeline: pipeline)
end
def show_test_coverage_badge(job: nil)
visit coverage_namespace_project_badges_path(
project.namespace, project, ref: :master, job: job, format: :svg)
end
def expect_coverage_badge(coverage)
svg = Nokogiri::XML.parse(page.body)
expect(page.response_headers['Content-Type']).to include('image/svg+xml')
expect(svg.at(%Q{text:contains("#{coverage}")})).to be_truthy
end
end
...@@ -9,25 +9,43 @@ feature 'list of badges' do ...@@ -9,25 +9,43 @@ feature 'list of badges' do
visit namespace_project_pipelines_settings_path(project.namespace, project) visit namespace_project_pipelines_settings_path(project.namespace, project)
end end
scenario 'user displays list of badges' do scenario 'user wants to see build status badge' do
expect(page).to have_content 'build status' page.within('.build-status') do
expect(page).to have_content 'Markdown' expect(page).to have_content 'build status'
expect(page).to have_content 'HTML' expect(page).to have_content 'Markdown'
expect(page).to have_css('.highlight', count: 2) expect(page).to have_content 'HTML'
expect(page).to have_xpath("//img[@alt='build status']") expect(page).to have_css('.highlight', count: 2)
expect(page).to have_xpath("//img[@alt='build status']")
page.within('.highlight', match: :first) do
expect(page).to have_content 'badges/master/build.svg' page.within('.highlight', match: :first) do
expect(page).to have_content 'badges/master/build.svg'
end
end end
end end
scenario 'user changes current ref on badges list page', js: true do scenario 'user wants to see coverage report badge' do
first('.js-project-refs-dropdown').click page.within('.coverage-report') do
expect(page).to have_content 'coverage report'
expect(page).to have_content 'Markdown'
expect(page).to have_content 'HTML'
expect(page).to have_css('.highlight', count: 2)
expect(page).to have_xpath("//img[@alt='coverage report']")
page.within '.project-refs-form' do page.within('.highlight', match: :first) do
click_link 'improve/awesome' expect(page).to have_content 'badges/master/coverage.svg'
end
end end
end
scenario 'user changes current ref of build status badge', js: true do
page.within('.build-status') do
first('.js-project-refs-dropdown').click
expect(page).to have_content 'badges/improve/awesome/build.svg' page.within '.project-refs-form' do
click_link 'improve/awesome'
end
expect(page).to have_content 'badges/improve/awesome/build.svg'
end
end end
end end
require 'spec_helper' require 'spec_helper'
require 'lib/gitlab/badge/shared/metadata'
describe Gitlab::Badge::Build::Metadata do describe Gitlab::Badge::Build::Metadata do
let(:project) { create(:project) } let(:badge) { double(project: create(:project), ref: 'feature') }
let(:branch) { 'master' } let(:metadata) { described_class.new(badge) }
let(:badge) { described_class.new(project, branch) }
describe '#to_html' do it_behaves_like 'badge metadata'
let(:html) { Nokogiri::HTML.parse(badge.to_html) }
let(:a_href) { html.at('a') }
it 'points to link' do describe '#title' do
expect(a_href[:href]).to eq badge.link_url it 'returns build status title' do
end expect(metadata.title).to eq 'build status'
it 'contains clickable image' do
expect(a_href.children.first.name).to eq 'img'
end end
end end
describe '#to_markdown' do
subject { badge.to_markdown }
it { is_expected.to include badge.image_url }
it { is_expected.to include badge.link_url }
end
describe '#image_url' do describe '#image_url' do
subject { badge.image_url } it 'returns valid url' do
it { is_expected.to include "badges/#{branch}/build.svg" } expect(metadata.image_url).to include 'badges/feature/build.svg'
end
end end
describe '#link_url' do describe '#link_url' do
subject { badge.link_url } it 'returns valid link' do
it { is_expected.to include "commits/#{branch}" } expect(metadata.link_url).to include 'commits/feature'
end
end end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Badge::Build do describe Gitlab::Badge::Build::Status do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:sha) { project.commit.sha } let(:sha) { project.commit.sha }
let(:branch) { 'master' } let(:branch) { 'master' }
let(:badge) { described_class.new(project, branch) } let(:badge) { described_class.new(project, branch) }
describe '#entity' do
it 'always says build' do
expect(badge.entity).to eq 'build'
end
end
describe '#template' do
it 'returns badge template' do
expect(badge.template.key_text).to eq 'build'
end
end
describe '#metadata' do describe '#metadata' do
it 'returns badge metadata' do it 'returns badge metadata' do
expect(badge.metadata.image_url) expect(badge.metadata.image_url)
...@@ -13,12 +25,6 @@ describe Gitlab::Badge::Build do ...@@ -13,12 +25,6 @@ describe Gitlab::Badge::Build do
end end
end end
describe '#key_text' do
it 'always says build' do
expect(badge.key_text).to eq 'build'
end
end
context 'build exists' do context 'build exists' do
let!(:build) { create_build(project, sha, branch) } let!(:build) { create_build(project, sha, branch) }
...@@ -30,12 +36,6 @@ describe Gitlab::Badge::Build do ...@@ -30,12 +36,6 @@ describe Gitlab::Badge::Build do
expect(badge.status).to eq 'success' expect(badge.status).to eq 'success'
end end
end end
describe '#value_text' do
it 'returns correct value text' do
expect(badge.value_text).to eq 'success'
end
end
end end
context 'build failed' do context 'build failed' do
...@@ -46,12 +46,6 @@ describe Gitlab::Badge::Build do ...@@ -46,12 +46,6 @@ describe Gitlab::Badge::Build do
expect(badge.status).to eq 'failed' expect(badge.status).to eq 'failed'
end end
end end
describe '#value_text' do
it 'has correct value text' do
expect(badge.value_text).to eq 'failed'
end
end
end end
context 'when outdated pipeline for given ref exists' do context 'when outdated pipeline for given ref exists' do
...@@ -87,12 +81,6 @@ describe Gitlab::Badge::Build do ...@@ -87,12 +81,6 @@ describe Gitlab::Badge::Build do
expect(badge.status).to eq 'unknown' expect(badge.status).to eq 'unknown'
end end
end end
describe '#value_text' do
it 'has correct value text' do
expect(badge.value_text).to eq 'unknown'
end
end
end end
def create_build(project, sha, branch) def create_build(project, sha, branch)
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Badge::Build::Template do describe Gitlab::Badge::Build::Template do
let(:status) { 'success' } let(:badge) { double(entity: 'build', status: 'success') }
let(:template) { described_class.new(status) } let(:template) { described_class.new(badge) }
describe '#key_text' do describe '#key_text' do
it 'is always says build' do it 'is always says build' do
...@@ -34,15 +34,15 @@ describe Gitlab::Badge::Build::Template do ...@@ -34,15 +34,15 @@ describe Gitlab::Badge::Build::Template do
describe '#value_color' do describe '#value_color' do
context 'when status is success' do context 'when status is success' do
let(:status) { 'success' }
it 'has expected color' do it 'has expected color' do
expect(template.value_color).to eq '#4c1' expect(template.value_color).to eq '#4c1'
end end
end end
context 'when status is failed' do context 'when status is failed' do
let(:status) { 'failed' } before do
allow(badge).to receive(:status).and_return('failed')
end
it 'has expected color' do it 'has expected color' do
expect(template.value_color).to eq '#e05d44' expect(template.value_color).to eq '#e05d44'
...@@ -50,7 +50,9 @@ describe Gitlab::Badge::Build::Template do ...@@ -50,7 +50,9 @@ describe Gitlab::Badge::Build::Template do
end end
context 'when status is running' do context 'when status is running' do
let(:status) { 'running' } before do
allow(badge).to receive(:status).and_return('running')
end
it 'has expected color' do it 'has expected color' do
expect(template.value_color).to eq '#dfb317' expect(template.value_color).to eq '#dfb317'
...@@ -58,7 +60,9 @@ describe Gitlab::Badge::Build::Template do ...@@ -58,7 +60,9 @@ describe Gitlab::Badge::Build::Template do
end end
context 'when status is unknown' do context 'when status is unknown' do
let(:status) { 'unknown' } before do
allow(badge).to receive(:status).and_return('unknown')
end
it 'has expected color' do it 'has expected color' do
expect(template.value_color).to eq '#9f9f9f' expect(template.value_color).to eq '#9f9f9f'
...@@ -66,7 +70,9 @@ describe Gitlab::Badge::Build::Template do ...@@ -66,7 +70,9 @@ describe Gitlab::Badge::Build::Template do
end end
context 'when status does not match any known statuses' do context 'when status does not match any known statuses' do
let(:status) { 'invalid status' } before do
allow(badge).to receive(:status).and_return('invalid')
end
it 'has expected color' do it 'has expected color' do
expect(template.value_color).to eq '#9f9f9f' expect(template.value_color).to eq '#9f9f9f'
......
require 'spec_helper'
require 'lib/gitlab/badge/shared/metadata'
describe Gitlab::Badge::Coverage::Metadata do
let(:badge) do
double(project: create(:project), ref: 'feature', job: 'test')
end
let(:metadata) { described_class.new(badge) }
it_behaves_like 'badge metadata'
describe '#title' do
it 'returns coverage report title' do
expect(metadata.title).to eq 'coverage report'
end
end
describe '#image_url' do
it 'returns valid url' do
expect(metadata.image_url).to include 'badges/feature/coverage.svg'
end
end
describe '#link_url' do
it 'returns valid link' do
expect(metadata.link_url).to include 'commits/feature'
end
end
end
require 'spec_helper'
describe Gitlab::Badge::Coverage::Report do
let(:project) { create(:project) }
let(:job_name) { nil }
let(:badge) do
described_class.new(project, 'master', job_name)
end
describe '#entity' do
it 'describes a coverage' do
expect(badge.entity).to eq 'coverage'
end
end
describe '#metadata' do
it 'returns correct metadata' do
expect(badge.metadata.image_url).to include 'coverage.svg'
end
end
describe '#template' do
it 'returns correct template' do
expect(badge.template.key_text).to eq 'coverage'
end
end
shared_examples 'unknown coverage report' do
context 'particular job specified' do
let(:job_name) { '' }
it 'returns nil' do
expect(badge.status).to be_nil
end
end
context 'particular job not specified' do
let(:job_name) { nil }
it 'returns nil' do
expect(badge.status).to be_nil
end
end
end
context 'pipeline exists' do
let!(:pipeline) do
create(:ci_pipeline, project: project,
sha: project.commit.id,
ref: 'master')
end
context 'builds exist' do
before do
create(:ci_build, name: 'first', pipeline: pipeline, coverage: 40)
create(:ci_build, pipeline: pipeline, coverage: 60)
end
context 'particular job specified' do
let(:job_name) { 'first' }
it 'returns coverage for the particular job' do
expect(badge.status).to eq 40
end
end
context 'particular job not specified' do
let(:job_name) { '' }
it 'returns arithemetic mean for the pipeline' do
expect(badge.status).to eq 50
end
end
end
context 'builds do not exist' do
it_behaves_like 'unknown coverage report'
context 'particular job specified' do
let(:job_name) { 'nonexistent' }
it 'retruns nil' do
expect(badge.status).to be_nil
end
end
end
end
context 'pipeline does not exist' do
it_behaves_like 'unknown coverage report'
end
end
require 'spec_helper'
describe Gitlab::Badge::Coverage::Template do
let(:badge) { double(entity: 'coverage', status: 90) }
let(:template) { described_class.new(badge) }
describe '#key_text' do
it 'is always says coverage' do
expect(template.key_text).to eq 'coverage'
end
end
describe '#value_text' do
context 'when coverage is known' do
it 'returns coverage percentage' do
expect(template.value_text).to eq '90%'
end
end
context 'when coverage is unknown' do
before do
allow(badge).to receive(:status).and_return(nil)
end
it 'returns string that says coverage is unknown' do
expect(template.value_text).to eq 'unknown'
end
end
end
describe '#key_width' do
it 'has a fixed key width' do
expect(template.key_width).to eq 62
end
end
describe '#value_width' do
context 'when coverage is known' do
it 'is narrower when coverage is known' do
expect(template.value_width).to eq 36
end
end
context 'when coverage is unknown' do
before do
allow(badge).to receive(:status).and_return(nil)
end
it 'is wider when coverage is unknown to fit text' do
expect(template.value_width).to eq 58
end
end
end
describe '#key_color' do
it 'always has the same color' do
expect(template.key_color).to eq '#555'
end
end
describe '#value_color' do
context 'when coverage is good' do
before do
allow(badge).to receive(:status).and_return(98)
end
it 'is green' do
expect(template.value_color).to eq '#4c1'
end
end
context 'when coverage is acceptable' do
before do
allow(badge).to receive(:status).and_return(90)
end
it 'is green-orange' do
expect(template.value_color).to eq '#a3c51c'
end
end
context 'when coverage is medium' do
before do
allow(badge).to receive(:status).and_return(75)
end
it 'is orange-yellow' do
expect(template.value_color).to eq '#dfb317'
end
end
context 'when coverage is low' do
before do
allow(badge).to receive(:status).and_return(50)
end
it 'is red' do
expect(template.value_color).to eq '#e05d44'
end
end
context 'when coverage is unknown' do
before do
allow(badge).to receive(:status).and_return(nil)
end
it 'is grey' do
expect(template.value_color).to eq '#9f9f9f'
end
end
end
describe '#width' do
context 'when coverage is known' do
it 'returns the key width plus value width' do
expect(template.width).to eq 98
end
end
context 'when coverage is unknown' do
before do
allow(badge).to receive(:status).and_return(nil)
end
it 'returns key width plus wider value width' do
expect(template.width).to eq 120
end
end
end
end
shared_examples 'badge metadata' do
describe '#to_html' do
let(:html) { Nokogiri::HTML.parse(metadata.to_html) }
let(:a_href) { html.at('a') }
it 'points to link' do
expect(a_href[:href]).to eq metadata.link_url
end
it 'contains clickable image' do
expect(a_href.children.first.name).to eq 'img'
end
end
describe '#to_markdown' do
subject { metadata.to_markdown }
it { is_expected.to include metadata.image_url }
it { is_expected.to include metadata.link_url }
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