Commit 41abc03f authored by Kamil Trzciński's avatar Kamil Trzciński

Remove GroupedStatuses

parent 7152a5ee
...@@ -24,9 +24,11 @@ module Ci ...@@ -24,9 +24,11 @@ module Ci
def status def status
strong_memoize(:status) do strong_memoize(:status) do
if Feature.enabled?(:ci_composite_status, default_enabled: true) if Feature.enabled?(:ci_composite_status, default_enabled: true)
Gitlab::Ci::Status::GroupedStatuses all_statuses = @jobs.pluck(:status, :allow_failure)
.new(@jobs)
.one[:status] Gitlab::Ci::Status::Composite
.new(all_statuses, status_key: 0, allow_failure_key: 1)
.status
else else
CommitStatus.where(id: @jobs).legacy_status CommitStatus.where(id: @jobs).legacy_status
end end
......
...@@ -406,16 +406,21 @@ module Ci ...@@ -406,16 +406,21 @@ module Ci
end end
def legacy_stages_using_composite_status def legacy_stages_using_composite_status
stages = Gitlab::Ci::Status::GroupedStatuses stages = statuses.latest
.new(statuses.latest, :stage, :stage_idx) .group_by(&:stage_idx)
.group(:stage, :stage_idx) .sort_by(&:first)
.sort_by { |stage| stage[:stage_idx] }
stages.map do |stage_idx, jobs|
stage_name = jobs.first.stage
jobs_statuses = jobs.pluck(:status, :allow_failure)
composite_status = Gitlab::Ci::Status::Composite
.new(jobs_statuses, status_key: 0, allow_failure_key: 1)
stages.map do |stage|
Ci::LegacyStage.new(self, Ci::LegacyStage.new(self,
name: stage[:stage], name: stage_name,
status: stage[:status], status: composite_status.status,
warnings: stage[:warnings]) warnings: composite_status.warnings?)
end end
end end
...@@ -423,7 +428,7 @@ module Ci ...@@ -423,7 +428,7 @@ module Ci
if Feature.enabled?(:ci_composite_status, default_enabled: true) if Feature.enabled?(:ci_composite_status, default_enabled: true)
legacy_stages_using_composite_status legacy_stages_using_composite_status
else else
legacy_status_using_sql legacy_stages_using_sql
end end
end end
......
...@@ -61,9 +61,14 @@ module HasStatus ...@@ -61,9 +61,14 @@ module HasStatus
def slow_composite_status def slow_composite_status
if Feature.enabled?(:ci_composite_status, default_enabled: true) if Feature.enabled?(:ci_composite_status, default_enabled: true)
Gitlab::Ci::Status::GroupedStatuses columns = [:status]
.new(all) columns << :allow_failure if column_names.include?('allow_failure')
.one[:status]
all_statuses = all.pluck(*columns)
Gitlab::Ci::Status::Composite
.new(all_statuses, status_key: 0, allow_failure_key: 1)
.status
else else
legacy_status legacy_status
end end
......
...@@ -3,13 +3,18 @@ ...@@ -3,13 +3,18 @@
module Gitlab module Gitlab
module Ci module Ci
module Status module Status
class CompositeStatus class Composite
attr_reader :warnings attr_reader :warnings
def initialize(all_statuses) # This class accepts an array of arrays or array of hashes
# The `status_key` and `allow_failure_key` define an index
# or key in each entry
def initialize(all_statuses, status_key:, allow_failure_key:)
@count = 0 @count = 0
@warnings = 0 @warnings = 0
@status_set = Set.new @status_set = Set.new
@status_key = status_key
@allow_failure_key = allow_failure_key
build_status_set(all_statuses) build_status_set(all_statuses)
end end
...@@ -19,29 +24,29 @@ module Gitlab ...@@ -19,29 +24,29 @@ module Gitlab
when @count.zero? when @count.zero?
nil nil
when none? || only_of?(:skipped) when none? || only_of?(:skipped)
warnings? ? :success : :skipped warnings? ? 'success' : 'skipped'
when only_of?(:success, :skipped) when only_of?(:success, :skipped)
:success 'success'
when only_of?(:created) when only_of?(:created)
:created 'created'
when only_of?(:preparing) when only_of?(:preparing)
:preparing 'preparing'
when only_of?(:success, :skipped, :canceled) when only_of?(:success, :skipped, :canceled)
:canceled 'canceled'
when only_of?(:created, :skipped, :pending) when only_of?(:created, :skipped, :pending)
:pending 'pending'
when any_of?(:running, :pending) when any_of?(:running, :pending)
:running 'running'
when any_of?(:manual) when any_of?(:manual)
:manual 'manual'
when any_of?(:scheduled) when any_of?(:scheduled)
:scheduled 'scheduled'
when any_of?(:preparing) when any_of?(:preparing)
:preparing 'preparing'
when any_of?(:created) when any_of?(:created)
:running 'running'
else else
:failed 'failed'
end end
end end
...@@ -67,18 +72,23 @@ module Gitlab ...@@ -67,18 +72,23 @@ module Gitlab
def build_status_set(all_statuses) def build_status_set(all_statuses)
all_statuses.each do |status| all_statuses.each do |status|
@count += 1 @count += 1
if status[:allow_failure] @warnings += 1 if count_as_warning?(status)
if HasStatus::PASSED_WITH_WARNINGS_STATUSES.include?(status[:status]) next if exclude_from_calculation?(status)
@warnings += 1
end
if HasStatus::EXCLUDE_IGNORED_STATUSES.include?(status[:status]) @status_set.add(status[@status_key].to_sym)
next
end end
end end
@status_set.add(status[:status].to_sym) def count_as_warning?(status)
@allow_failure_key &&
status[@allow_failure_key] &&
HasStatus::PASSED_WITH_WARNINGS_STATUSES.include?(status[@status_key])
end end
def exclude_from_calculation?(status)
@allow_failure_key &&
status[@allow_failure_key] &&
HasStatus::EXCLUDE_IGNORED_STATUSES.include?(status[@status_key])
end end
end end
end end
......
# frozen_string_literal: true
module Gitlab
module Ci
module Status
class GroupedStatuses
def initialize(subject, *keys)
@subject = subject
@keys = keys
end
def one(**query)
validate_keys!(query.keys)
if item_hash = find_one(data_hash, query)
status_for_key(query, item_hash)
else
{}
end
end
def group(*keys)
validate_keys!(keys)
grouped_statuses(data_hash, keys)
end
private
def validate_keys!(keys)
missing_keys = @keys - keys
if missing_keys.present?
raise ArgumentError, "the keys '#{missing_keys.join(',')} are not subset of #{@keys.join(',')}"
end
end
def data_hash
@data_hash ||= hash_from_relation(@subject, @keys)
end
def hash_from_relation(subject, keys)
columns = keys.dup
columns << :status
# we request allow_failure when
# we don't have column_names, or such column does exist
columns << :allow_failure if !subject.respond_to?(:column_names) || subject.column_names.include?('allow_failure')
subject
.pluck(*columns) # rubocop: disable CodeReuse/ActiveRecord
.map { |attrs| columns.zip(attrs).to_h }
end
def find_one(subject, query)
subject.select do |attrs|
query.all? do |key, value|
attrs[key] == value
end
end.presence
end
def grouped_statuses(subject, keys)
subject
.group_by { |attrs| attrs.slice(*keys) }
.map { |key, all_attrs| status_for_key(key, all_attrs) }
end
def status_for_key(key, all_attrs)
composite_status = Gitlab::Ci::Status::CompositeStatus.new(all_attrs)
key.merge(
status: composite_status.status.to_s,
warnings: composite_status.warnings?
)
end
end
end
end
end
require 'spec_helper' require 'spec_helper'
describe Gitlab::Ci::Status::CompositeStatus do describe Gitlab::Ci::Status::Composite do
set(:pipeline) { create(:ci_pipeline) } set(:pipeline) { create(:ci_pipeline) }
let(:composite_status) { described_class.new(all_statuses) } let(:composite_status) do
described_class.new(
all_statuses.pluck(:status, :allow_failure),
status_key: 0,
allow_failure_key: 0
)
end
before(:all) do before(:all) do
@statuses = HasStatus::STATUSES_ENUM.map do |status, idx| @statuses = HasStatus::STATUSES_ENUM.map do |status, idx|
...@@ -16,11 +22,11 @@ describe Gitlab::Ci::Status::CompositeStatus do ...@@ -16,11 +22,11 @@ describe Gitlab::Ci::Status::CompositeStatus do
end end
describe '#status' do describe '#status' do
subject { composite_status.status.to_s } subject { composite_status.status }
shared_examples 'compares composite with SQL status' do shared_examples 'compares composite with SQL status' do
it 'returns exactly the same result' do it 'returns exactly the same result' do
is_expected.to eq(Ci::Build.where(id: all_statuses).legacy_status.to_s) is_expected.to eq(Ci::Build.where(id: all_statuses).legacy_status)
end end
end end
......
...@@ -22,6 +22,32 @@ describe Ci::Group do ...@@ -22,6 +22,32 @@ describe Ci::Group do
end end
end end
describe '#status' do
let(:jobs) do
[create(:ci_build, :failed)]
end
context 'when ci_composite_status is enabled' do
before do
stub_feature_flags(ci_composite_status: true)
end
it 'returns a failed status' do
expect(subject.status).to eq('failed')
end
end
context 'when ci_composite_status is disabled' do
before do
stub_feature_flags(ci_composite_status: false)
end
it 'returns a failed status' do
expect(subject.status).to eq('failed')
end
end
end
describe '#detailed_status' do describe '#detailed_status' do
context 'when there is only one item in the group' do context 'when there is only one item in the group' do
it 'calls the status from the object itself' do it 'calls the status from the object itself' do
......
...@@ -1136,8 +1136,19 @@ describe Ci::Pipeline, :mailer do ...@@ -1136,8 +1136,19 @@ describe Ci::Pipeline, :mailer do
end end
describe '#legacy_stages' do describe '#legacy_stages' do
using RSpec::Parameterized::TableSyntax
subject { pipeline.legacy_stages } subject { pipeline.legacy_stages }
where(:ci_composite_status) do
[false, true]
end
with_them do
before do
stub_feature_flags(ci_composite_status: ci_composite_status)
end
context 'stages list' do context 'stages list' do
it 'returns ordered list of stages' do it 'returns ordered list of stages' do
expect(subject.map(&:name)).to eq(%w[build test deploy]) expect(subject.map(&:name)).to eq(%w[build test deploy])
...@@ -1192,6 +1203,7 @@ describe Ci::Pipeline, :mailer do ...@@ -1192,6 +1203,7 @@ describe Ci::Pipeline, :mailer do
end end
end end
end end
end
describe '#stages_count' do describe '#stages_count' do
it 'returns a valid number of stages' do it 'returns a valid number of stages' do
......
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
require 'spec_helper' require 'spec_helper'
describe HasStatus do describe HasStatus do
describe '.legacy_status' do describe '.slow_composite_status' do
subject { CommitStatus.legacy_status } using RSpec::Parameterized::TableSyntax
subject { CommitStatus.slow_composite_status }
shared_examples 'build status summary' do shared_examples 'build status summary' do
context 'all successful' do context 'all successful' do
...@@ -166,6 +168,15 @@ describe HasStatus do ...@@ -166,6 +168,15 @@ describe HasStatus do
end end
end end
where(:ci_composite_status) do
[false, true]
end
with_them do
before do
stub_feature_flags(ci_composite_status: ci_composite_status)
end
context 'ci build statuses' do context 'ci build statuses' do
let(:type) { :ci_build } let(:type) { :ci_build }
...@@ -178,6 +189,7 @@ describe HasStatus do ...@@ -178,6 +189,7 @@ describe HasStatus do
it_behaves_like 'build status summary' it_behaves_like 'build status summary'
end end
end end
end
context 'for scope with one status' do context 'for scope with one status' do
shared_examples 'having a job' do |status| shared_examples 'having a job' do |status|
......
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