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
This commit is contained in:
commit
804fa43758
|
@ -1,6 +1,7 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.11.0 (unreleased)
|
||||
- Add test coverage report badge. !5708
|
||||
- Remove the http_parser.rb dependency by removing the tinder gem. !5758 (tbalthazar)
|
||||
- Ability to specify branches for Pivotal Tracker integration (Egor Lynko)
|
||||
- Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres)
|
||||
|
|
|
@ -4,11 +4,24 @@ class Projects::BadgesController < Projects::ApplicationController
|
|||
before_action :no_cache_headers, except: [:index]
|
||||
|
||||
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|
|
||||
format.html { render_404 }
|
||||
|
||||
format.svg do
|
||||
render 'badge', locals: { badge: badge.template }
|
||||
end
|
||||
|
|
|
@ -3,7 +3,13 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
|
|||
|
||||
def show
|
||||
@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
|
||||
|
||||
def update
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
.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
|
||||
·
|
||||
= 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 @@
|
|||
%hr
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-3.profile-settings-sidebar
|
||||
%h4.prepend-top-0
|
||||
Builds Badge
|
||||
.col-lg-9
|
||||
.prepend-top-10
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
%b Builds badge ·
|
||||
= @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)
|
||||
= render partial: 'badge', collection: @badges
|
||||
|
|
|
@ -869,7 +869,10 @@ Rails.application.routes.draw do
|
|||
resources :badges, only: [:index] do
|
||||
collection 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
|
||||
|
|
|
@ -32,6 +32,41 @@ project.
|
|||
|
||||
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
|
||||
[jobs]: yaml/README.md#jobs
|
||||
[stages]: yaml/README.md#stages
|
||||
|
|
|
@ -218,21 +218,13 @@ project's settings.
|
|||
For more information read the
|
||||
[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
|
||||
|
||||
Visit the [examples README][examples] to see a list of examples using GitLab
|
||||
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
|
||||
[blog-ci]: https://about.gitlab.com/2015/05/06/why-were-replacing-gitlab-ci-jobs-with-gitlab-ci-dot-yml/
|
||||
[examples]: ../examples/README.md
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
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
|
|
@ -1,30 +0,0 @@
|
|||
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
|
|
@ -1,25 +1,17 @@
|
|||
module Gitlab
|
||||
module Badge
|
||||
class Build
|
||||
module Build
|
||||
##
|
||||
# Class that describes build badge metadata
|
||||
#
|
||||
class Metadata
|
||||
include Gitlab::Application.routes.url_helpers
|
||||
include ActionView::Helpers::AssetTagHelper
|
||||
include ActionView::Helpers::UrlHelper
|
||||
|
||||
def initialize(project, ref)
|
||||
@project = project
|
||||
@ref = ref
|
||||
class Metadata < Badge::Metadata
|
||||
def initialize(badge)
|
||||
@project = badge.project
|
||||
@ref = badge.ref
|
||||
end
|
||||
|
||||
def to_html
|
||||
link_to(image_tag(image_url, alt: 'build status'), link_url)
|
||||
end
|
||||
|
||||
def to_markdown
|
||||
"[![build status](#{image_url})](#{link_url})"
|
||||
def title
|
||||
'build status'
|
||||
end
|
||||
|
||||
def image_url
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
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
|
|
@ -1,12 +1,12 @@
|
|||
module Gitlab
|
||||
module Badge
|
||||
class Build
|
||||
module Build
|
||||
##
|
||||
# Class that represents a build badge template.
|
||||
#
|
||||
# Template object will be passed to badge.svg.erb template.
|
||||
#
|
||||
class Template
|
||||
class Template < Badge::Template
|
||||
STATUS_COLOR = {
|
||||
success: '#4c1',
|
||||
failed: '#e05d44',
|
||||
|
@ -17,16 +17,17 @@ module Gitlab
|
|||
unknown: '#9f9f9f'
|
||||
}
|
||||
|
||||
def initialize(status)
|
||||
@status = status
|
||||
def initialize(badge)
|
||||
@entity = badge.entity
|
||||
@status = badge.status
|
||||
end
|
||||
|
||||
def key_text
|
||||
'build'
|
||||
@entity.to_s
|
||||
end
|
||||
|
||||
def value_text
|
||||
@status
|
||||
@status.to_s
|
||||
end
|
||||
|
||||
def key_width
|
||||
|
@ -37,25 +38,8 @@ module Gitlab
|
|||
54
|
||||
end
|
||||
|
||||
def key_color
|
||||
'#555'
|
||||
end
|
||||
|
||||
def value_color
|
||||
STATUS_COLOR[@status.to_sym] ||
|
||||
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
|
||||
STATUS_COLOR[@status.to_sym] || STATUS_COLOR[:unknown]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
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
|
|
@ -0,0 +1,56 @@
|
|||
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
|
|
@ -0,0 +1,52 @@
|
|||
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
|
|
@ -0,0 +1,36 @@
|
|||
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
|
|
@ -0,0 +1,49 @@
|
|||
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
|
|
@ -0,0 +1,73 @@
|
|||
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
|
|||
visit namespace_project_pipelines_settings_path(project.namespace, project)
|
||||
end
|
||||
|
||||
scenario 'user displays list of badges' do
|
||||
expect(page).to have_content 'build status'
|
||||
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='build status']")
|
||||
scenario 'user wants to see build status badge' do
|
||||
page.within('.build-status') do
|
||||
expect(page).to have_content 'build status'
|
||||
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='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
|
||||
|
||||
scenario 'user changes current ref on badges list page', js: true do
|
||||
first('.js-project-refs-dropdown').click
|
||||
scenario 'user wants to see coverage report badge' do
|
||||
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
|
||||
click_link 'improve/awesome'
|
||||
page.within('.highlight', match: :first) do
|
||||
expect(page).to have_content 'badges/master/coverage.svg'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
expect(page).to have_content 'badges/improve/awesome/build.svg'
|
||||
scenario 'user changes current ref of build status badge', js: true do
|
||||
page.within('.build-status') do
|
||||
first('.js-project-refs-dropdown').click
|
||||
|
||||
page.within '.project-refs-form' do
|
||||
click_link 'improve/awesome'
|
||||
end
|
||||
|
||||
expect(page).to have_content 'badges/improve/awesome/build.svg'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,37 +1,27 @@
|
|||
require 'spec_helper'
|
||||
require 'lib/gitlab/badge/shared/metadata'
|
||||
|
||||
describe Gitlab::Badge::Build::Metadata do
|
||||
let(:project) { create(:project) }
|
||||
let(:branch) { 'master' }
|
||||
let(:badge) { described_class.new(project, branch) }
|
||||
let(:badge) { double(project: create(:project), ref: 'feature') }
|
||||
let(:metadata) { described_class.new(badge) }
|
||||
|
||||
describe '#to_html' do
|
||||
let(:html) { Nokogiri::HTML.parse(badge.to_html) }
|
||||
let(:a_href) { html.at('a') }
|
||||
it_behaves_like 'badge metadata'
|
||||
|
||||
it 'points to link' do
|
||||
expect(a_href[:href]).to eq badge.link_url
|
||||
describe '#title' do
|
||||
it 'returns build status title' do
|
||||
expect(metadata.title).to eq 'build status'
|
||||
end
|
||||
|
||||
it 'contains clickable image' do
|
||||
expect(a_href.children.first.name).to eq 'img'
|
||||
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
|
||||
subject { badge.image_url }
|
||||
it { is_expected.to include "badges/#{branch}/build.svg" }
|
||||
it 'returns valid url' do
|
||||
expect(metadata.image_url).to include 'badges/feature/build.svg'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#link_url' do
|
||||
subject { badge.link_url }
|
||||
it { is_expected.to include "commits/#{branch}" }
|
||||
it 'returns valid link' do
|
||||
expect(metadata.link_url).to include 'commits/feature'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Badge::Build do
|
||||
describe Gitlab::Badge::Build::Status do
|
||||
let(:project) { create(:project) }
|
||||
let(:sha) { project.commit.sha }
|
||||
let(:branch) { 'master' }
|
||||
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
|
||||
it 'returns badge metadata' do
|
||||
expect(badge.metadata.image_url)
|
||||
|
@ -13,12 +25,6 @@ describe Gitlab::Badge::Build do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#key_text' do
|
||||
it 'always says build' do
|
||||
expect(badge.key_text).to eq 'build'
|
||||
end
|
||||
end
|
||||
|
||||
context 'build exists' do
|
||||
let!(:build) { create_build(project, sha, branch) }
|
||||
|
||||
|
@ -30,12 +36,6 @@ describe Gitlab::Badge::Build do
|
|||
expect(badge.status).to eq 'success'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#value_text' do
|
||||
it 'returns correct value text' do
|
||||
expect(badge.value_text).to eq 'success'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'build failed' do
|
||||
|
@ -46,12 +46,6 @@ describe Gitlab::Badge::Build do
|
|||
expect(badge.status).to eq 'failed'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#value_text' do
|
||||
it 'has correct value text' do
|
||||
expect(badge.value_text).to eq 'failed'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when outdated pipeline for given ref exists' do
|
||||
|
@ -87,12 +81,6 @@ describe Gitlab::Badge::Build do
|
|||
expect(badge.status).to eq 'unknown'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#value_text' do
|
||||
it 'has correct value text' do
|
||||
expect(badge.value_text).to eq 'unknown'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_build(project, sha, branch)
|
|
@ -1,8 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Badge::Build::Template do
|
||||
let(:status) { 'success' }
|
||||
let(:template) { described_class.new(status) }
|
||||
let(:badge) { double(entity: 'build', status: 'success') }
|
||||
let(:template) { described_class.new(badge) }
|
||||
|
||||
describe '#key_text' do
|
||||
it 'is always says build' do
|
||||
|
@ -34,15 +34,15 @@ describe Gitlab::Badge::Build::Template do
|
|||
|
||||
describe '#value_color' do
|
||||
context 'when status is success' do
|
||||
let(:status) { 'success' }
|
||||
|
||||
it 'has expected color' do
|
||||
expect(template.value_color).to eq '#4c1'
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
expect(template.value_color).to eq '#e05d44'
|
||||
|
@ -50,7 +50,9 @@ describe Gitlab::Badge::Build::Template do
|
|||
end
|
||||
|
||||
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
|
||||
expect(template.value_color).to eq '#dfb317'
|
||||
|
@ -58,7 +60,9 @@ describe Gitlab::Badge::Build::Template do
|
|||
end
|
||||
|
||||
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
|
||||
expect(template.value_color).to eq '#9f9f9f'
|
||||
|
@ -66,7 +70,9 @@ describe Gitlab::Badge::Build::Template do
|
|||
end
|
||||
|
||||
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
|
||||
expect(template.value_color).to eq '#9f9f9f'
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
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
|
|
@ -0,0 +1,93 @@
|
|||
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
|
|
@ -0,0 +1,130 @@
|
|||
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
|
|
@ -0,0 +1,21 @@
|
|||
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
|
Loading…
Reference in New Issue