diff options
Diffstat (limited to 'lib/gitlab/ci/badge')
-rw-r--r-- | lib/gitlab/ci/badge/base.rb | 23 | ||||
-rw-r--r-- | lib/gitlab/ci/badge/coverage/metadata.rb | 30 | ||||
-rw-r--r-- | lib/gitlab/ci/badge/coverage/report.rb | 75 | ||||
-rw-r--r-- | lib/gitlab/ci/badge/coverage/template.rb | 64 | ||||
-rw-r--r-- | lib/gitlab/ci/badge/metadata.rb | 42 | ||||
-rw-r--r-- | lib/gitlab/ci/badge/pipeline/metadata.rb | 29 | ||||
-rw-r--r-- | lib/gitlab/ci/badge/pipeline/status.rb | 48 | ||||
-rw-r--r-- | lib/gitlab/ci/badge/pipeline/template.rb | 61 | ||||
-rw-r--r-- | lib/gitlab/ci/badge/template.rb | 54 |
9 files changed, 426 insertions, 0 deletions
diff --git a/lib/gitlab/ci/badge/base.rb b/lib/gitlab/ci/badge/base.rb new file mode 100644 index 00000000000..c65f120753d --- /dev/null +++ b/lib/gitlab/ci/badge/base.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Gitlab::Ci + 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 diff --git a/lib/gitlab/ci/badge/coverage/metadata.rb b/lib/gitlab/ci/badge/coverage/metadata.rb new file mode 100644 index 00000000000..7654b6d6fc5 --- /dev/null +++ b/lib/gitlab/ci/badge/coverage/metadata.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Gitlab::Ci + 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_project_badges_url(@project, @ref, format: :svg) + end + + def link_url + project_commits_url(@project, @ref) + end + end + end + end +end diff --git a/lib/gitlab/ci/badge/coverage/report.rb b/lib/gitlab/ci/badge/coverage/report.rb new file mode 100644 index 00000000000..28863a0703b --- /dev/null +++ b/lib/gitlab/ci/badge/coverage/report.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module Gitlab::Ci + module Badge + module Coverage + ## + # Test coverage report badge + # + class Report < Badge::Base + attr_reader :project, :ref, :job, :customization + + def initialize(project, ref, opts: { job: nil }) + @project = project + @ref = ref + @job = opts[:job] + @customization = { + key_width: opts[:key_width].to_i, + key_text: opts[:key_text] + } + end + + def entity + 'coverage' + end + + def status + @coverage ||= raw_coverage + return unless @coverage + + @coverage.to_f.round(2) + end + + def metadata + @metadata ||= Coverage::Metadata.new(self) + end + + def template + @template ||= Coverage::Template.new(self) + end + + private + + def successful_pipeline + @successful_pipeline ||= @project.ci_pipelines.latest_successful_for_ref(@ref) + end + + def failed_pipeline + @failed_pipeline ||= @project.ci_pipelines.latest_failed_for_ref(@ref) + end + + def running_pipeline + @running_pipeline ||= @project.ci_pipelines.latest_running_for_ref(@ref) + end + + def raw_coverage + latest = + if @job.present? + builds = ::Ci::Build + .in_pipelines([successful_pipeline, running_pipeline, failed_pipeline]) + .latest + .success + .for_ref(@ref) + .by_name(@job) + + builds.max_by(&:created_at) + else + successful_pipeline + end + + latest&.coverage + end + end + end + end +end diff --git a/lib/gitlab/ci/badge/coverage/template.rb b/lib/gitlab/ci/badge/coverage/template.rb new file mode 100644 index 00000000000..7589fa5ff8b --- /dev/null +++ b/lib/gitlab/ci/badge/coverage/template.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Gitlab::Ci + 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' + }.freeze + + def initialize(badge) + @entity = badge.entity + @status = badge.status + @key_text = badge.customization.dig(:key_text) + @key_width = badge.customization.dig(:key_width) + end + + def key_text + if @key_text && @key_text.size <= MAX_KEY_TEXT_SIZE + @key_text + else + @entity.to_s + end + end + + def value_text + @status ? ("%.2f%%" % @status) : 'unknown' + end + + def key_width + if @key_width && @key_width.between?(1, MAX_KEY_WIDTH) + @key_width + else + 62 + end + end + + def value_width + @status ? 54 : 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 diff --git a/lib/gitlab/ci/badge/metadata.rb b/lib/gitlab/ci/badge/metadata.rb new file mode 100644 index 00000000000..eec9fedfaa9 --- /dev/null +++ b/lib/gitlab/ci/badge/metadata.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module Gitlab::Ci + module Badge + ## + # Abstract class for badge metadata + # + class Metadata + include Gitlab::Routing + 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 to_asciidoc + "image:#{image_url}[link=\"#{link_url}\",title=\"#{title}\"]" + end + + def title + raise NotImplementedError + end + + def image_url + raise NotImplementedError + end + + def link_url + raise NotImplementedError + end + end + end +end diff --git a/lib/gitlab/ci/badge/pipeline/metadata.rb b/lib/gitlab/ci/badge/pipeline/metadata.rb new file mode 100644 index 00000000000..2aa08476336 --- /dev/null +++ b/lib/gitlab/ci/badge/pipeline/metadata.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Gitlab::Ci + module Badge + module Pipeline + ## + # Class that describes pipeline badge metadata + # + class Metadata < Badge::Metadata + def initialize(badge) + @project = badge.project + @ref = badge.ref + end + + def title + 'pipeline status' + end + + def image_url + pipeline_project_badges_url(@project, @ref, format: :svg) + end + + def link_url + project_commits_url(@project, id: @ref) + end + end + end + end +end diff --git a/lib/gitlab/ci/badge/pipeline/status.rb b/lib/gitlab/ci/badge/pipeline/status.rb new file mode 100644 index 00000000000..a2ee2642872 --- /dev/null +++ b/lib/gitlab/ci/badge/pipeline/status.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Gitlab::Ci + module Badge + module Pipeline + ## + # Pipeline status badge + # + class Status < Badge::Base + attr_reader :project, :ref, :customization + + def initialize(project, ref, opts: {}) + @project = project + @ref = ref + @ignore_skipped = Gitlab::Utils.to_boolean(opts[:ignore_skipped], default: false) + @customization = { + key_width: opts[:key_width].to_i, + key_text: opts[:key_text] + } + + @sha = @project.commit(@ref).try(:sha) + end + + def entity + 'pipeline' + end + + # rubocop: disable CodeReuse/ActiveRecord + def status + pipelines = @project.ci_pipelines + .where(sha: @sha) + + relation = @ignore_skipped ? pipelines.without_statuses([:skipped]) : pipelines + relation.latest_status(@ref) || 'unknown' + end + # rubocop: enable CodeReuse/ActiveRecord + + def metadata + @metadata ||= Pipeline::Metadata.new(self) + end + + def template + @template ||= Pipeline::Template.new(self) + end + end + end + end +end diff --git a/lib/gitlab/ci/badge/pipeline/template.rb b/lib/gitlab/ci/badge/pipeline/template.rb new file mode 100644 index 00000000000..8430b01fc9a --- /dev/null +++ b/lib/gitlab/ci/badge/pipeline/template.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +module Gitlab::Ci + module Badge + module Pipeline + ## + # Class that represents a pipeline badge template. + # + # Template object will be passed to badge.svg.erb template. + # + class Template < Badge::Template + STATUS_RENAME = { 'success' => 'passed' }.freeze + STATUS_COLOR = { + success: '#4c1', + failed: '#e05d44', + running: '#dfb317', + pending: '#dfb317', + preparing: '#a7a7a7', + canceled: '#9f9f9f', + skipped: '#9f9f9f', + unknown: '#9f9f9f' + }.freeze + + def initialize(badge) + @entity = badge.entity + @status = badge.status + @key_text = badge.customization.dig(:key_text) + @key_width = badge.customization.dig(:key_width) + end + + def key_text + if @key_text && @key_text.size <= MAX_KEY_TEXT_SIZE + @key_text + else + @entity.to_s + end + end + + def value_text + STATUS_RENAME[@status.to_s] || @status.to_s + end + + def key_width + if @key_width && @key_width.between?(1, MAX_KEY_WIDTH) + @key_width + else + 62 + end + end + + def value_width + 54 + end + + def value_color + STATUS_COLOR[@status.to_sym] || STATUS_COLOR[:unknown] + end + end + end + end +end diff --git a/lib/gitlab/ci/badge/template.rb b/lib/gitlab/ci/badge/template.rb new file mode 100644 index 00000000000..0580dad72ba --- /dev/null +++ b/lib/gitlab/ci/badge/template.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +module Gitlab::Ci + module Badge + ## + # Abstract template class for badges + # + class Template + MAX_KEY_TEXT_SIZE = 64 + MAX_KEY_WIDTH = 512 + + 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 |