Commit 3df3912b authored by James Fargher's avatar James Fargher

Merge branch 'extract-ci-minutes-limit-class' into 'master'

Extract CI::Minutes::Limit class

See merge request gitlab-org/gitlab!73344
parents b378ddef 4fc752f8
# frozen_string_literal: true
# This class is responsible for dealing with the CI minutes limits set at root namespace level.
module Ci
module Minutes
class Limit
include Gitlab::Utils::StrongMemoize
def initialize(namespace)
@namespace = namespace
end
def enabled?
namespace.root? && !unlimited?
end
def total
monthly + purchased
end
def monthly
strong_memoize(:monthly) do
(namespace.shared_runners_minutes_limit || ::Gitlab::CurrentSettings.shared_runners_minutes).to_i
end
end
def purchased
strong_memoize(:purchased) do
namespace.extra_shared_runners_minutes_limit.to_i
end
end
def any_purchased?
purchased > 0
end
private
attr_reader :namespace
def unlimited?
total == 0
end
end
end
end
......@@ -9,34 +9,29 @@ module Ci
class Quota
include Gitlab::Utils::StrongMemoize
attr_reader :namespace
attr_reader :namespace, :limit
def initialize(namespace)
@namespace = namespace
@limit = ::Ci::Minutes::Limit.new(namespace)
end
def enabled?
namespace_root? && !namespace_unlimited_minutes?
limit.enabled?
end
def minutes_used_up?
enabled? && total_minutes_used >= total_minutes
enabled? && total_minutes_used >= limit.total
end
def percent_total_minutes_remaining
return 0 if total_minutes == 0
return 0 unless limit.enabled?
100 * total_minutes_remaining.to_i / total_minutes
100 * total_minutes_remaining.to_i / limit.total
end
def current_balance
total_minutes.to_i - total_minutes_used
end
def total_minutes
strong_memoize(:total_minutes) do
monthly_minutes + purchased_minutes
end
limit.total - total_minutes_used
end
def total_minutes_used
......@@ -59,33 +54,11 @@ module Ci
end
end
def purchased_minutes
strong_memoize(:purchased_minutes) do
namespace.extra_shared_runners_minutes_limit.to_i
end
end
def namespace_root?
strong_memoize(:namespace_root) do
namespace.root?
end
end
def namespace_unlimited_minutes?
total_minutes.to_i == 0
end
def monthly_minutes
strong_memoize(:monthly_minutes) do
(namespace.shared_runners_minutes_limit || ::Gitlab::CurrentSettings.shared_runners_minutes).to_i
end
end
# === private to view ===
def monthly_minutes_used_up?
return false unless enabled?
monthly_minutes_used >= monthly_minutes
monthly_minutes_used >= limit.monthly
end
def monthly_minutes_used
......@@ -95,13 +68,13 @@ module Ci
def purchased_minutes_used_up?
return false unless enabled?
any_minutes_purchased? && purchased_minutes_used >= purchased_minutes
limit.any_purchased? && purchased_minutes_used >= limit.purchased
end
def purchased_minutes_used
return 0 if no_minutes_purchased? || monthly_minutes_available?
return 0 if !limit.any_purchased? || monthly_minutes_available?
total_minutes_used - monthly_minutes
total_minutes_used - limit.monthly
end
private
......@@ -111,15 +84,7 @@ module Ci
end
def monthly_minutes_available?
total_minutes_used <= monthly_minutes
end
def no_minutes_purchased?
purchased_minutes == 0
end
def any_minutes_purchased?
purchased_minutes > 0
total_minutes_used <= limit.monthly
end
def total_minutes_remaining
......
......@@ -16,30 +16,30 @@ module Ci
def monthly_percent_used
return 0 unless quota.enabled?
return 0 if quota.monthly_minutes == 0
return 0 if quota.limit.monthly == 0
100 * quota.monthly_minutes_used.to_i / quota.monthly_minutes
100 * quota.monthly_minutes_used.to_i / quota.limit.monthly
end
# Status of any purchased minutes used.
def purchased_minutes_report
status = quota.purchased_minutes_used_up? ? :over_quota : :under_quota
Report.new(quota.purchased_minutes_used, quota.purchased_minutes, status)
Report.new(quota.purchased_minutes_used, quota.limit.purchased, status)
end
def purchased_percent_used
return 0 unless quota.enabled?
return 0 if quota.purchased_minutes == 0
return 0 unless quota.limit.any_purchased?
100 * quota.purchased_minutes_used.to_i / quota.purchased_minutes
100 * quota.purchased_minutes_used.to_i / quota.limit.purchased
end
def display_minutes_available_data?
display_shared_runners_data? && !quota.namespace_unlimited_minutes?
display_shared_runners_data? && quota.limit.enabled?
end
def display_shared_runners_data?
quota.namespace_root? && any_project_enabled?
quota.namespace.root? && any_project_enabled?
end
def any_project_enabled?
......@@ -60,7 +60,7 @@ module Ci
return _('Not supported') unless display_shared_runners_data?
if display_minutes_available_data?
quota.monthly_minutes
quota.limit.monthly
else
_('Unlimited')
end
......
......@@ -12,7 +12,7 @@ module EE
end
expose :limit do |runner|
project.ci_minutes_quota.total_minutes
project.ci_minutes_quota.limit.total
end
end
end
......
......@@ -5,7 +5,7 @@
- if project.shared_runners_enabled?
Enabled
- if project.shared_runners_minutes_limit_enabled?
- limit = project.ci_minutes_quota.total_minutes
- limit = project.ci_minutes_quota.limit.total
(Limited to #{limit} pipeline minutes per month)
- else
(Unlimited pipeline minutes)
......
......@@ -49,12 +49,12 @@ RSpec.describe EE::NamespacesHelper do
context "when ci minutes quota is not enabled" do
before do
allow(quota).to receive(:namespace_unlimited_minutes?).and_return(true)
user_group.update!(shared_runners_minutes_limit: 0)
end
context 'and the namespace is eligible for unlimited' do
before do
allow(quota).to receive(:namespace_root?).and_return(true)
allow(user_group).to receive(:root?).and_return(true)
allow(user_group).to receive(:any_project_with_shared_runners_enabled?).and_return(true)
end
......@@ -65,7 +65,7 @@ RSpec.describe EE::NamespacesHelper do
context 'and the namespace is not eligible for unlimited' do
before do
allow(quota).to receive(:namespace_root?).and_return(false)
allow(user_group).to receive(:root?).and_return(false)
end
it 'returns Not supported for the limit section' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::Minutes::Limit do
using RSpec::Parameterized::TableSyntax
let_it_be_with_reload(:namespace) { create(:namespace) }
let_it_be_with_reload(:another_group) { create(:group) }
let(:limit) { described_class.new(namespace) }
let(:namespace_monthly_limit) { 400 }
let(:application_monthly_limit) { 400 }
let(:purchased_minutes) { 0 }
before do
namespace.shared_runners_minutes_limit = namespace_monthly_limit
namespace.extra_shared_runners_minutes_limit = purchased_minutes
allow(::Gitlab::CurrentSettings).to receive(:shared_runners_minutes).and_return(application_monthly_limit)
end
describe '#enabled?' do
subject { limit.enabled? }
where(:namespace_monthly_limit, :application_monthly_limit, :purchased_minutes, :result) do
0 | 100 | 0 | false
0 | 100 | 10 | true
nil | 100 | 10 | true
nil | 100 | 0 | true
20 | 100 | 0 | true
nil | nil | 0 | false
nil | 0 | 0 | false
end
with_them do
it { is_expected.to eq(result) }
context 'when namespace is not root' do
before do
namespace.parent = another_group
end
it { is_expected.to eq(false) }
end
end
end
describe '#total' do
subject { limit.total }
where(:namespace_monthly_limit, :application_monthly_limit, :purchased_minutes, :result) do
20 | 100 | 30 | 50
nil | 100 | 30 | 130
20 | 100 | 0 | 20
0 | 0 | 30 | 30
nil | 0 | 30 | 30
end
with_them do
it { is_expected.to eq(result) }
end
end
describe '#monthly' do
subject { limit.monthly}
where(:namespace_monthly_limit, :application_monthly_limit, :result) do
20 | 100 | 20
nil | 100 | 100
100 | nil | 100
0 | 100 | 0
nil | nil | 0
end
with_them do
it { is_expected.to eq(result) }
end
end
describe '#purchased and #any_purchased?' do
where(:purchased_minutes, :purchased, :any_purchased) do
nil | 0 | false
0 | 0 | false
10 | 10 | true
end
with_them do
it do
expect(limit.purchased).to eq(purchased)
expect(limit.any_purchased?).to eq(any_purchased)
end
end
end
end
......@@ -91,28 +91,6 @@ RSpec.describe Ci::Minutes::Quota do
end
end
describe '#total_minutes' do
subject { quota.total_minutes }
where(:namespace_monthly_limit, :application_monthly_limit, :purchased_minutes, :result) do
20 | 100 | 30 | 50
nil | 100 | 30 | 130
20 | 100 | 0 | 20
0 | 0 | 30 | 30
nil | 0 | 30 | 30
end
with_them do
before do
namespace.shared_runners_minutes_limit = namespace_monthly_limit
allow(::Gitlab::CurrentSettings).to receive(:shared_runners_minutes).and_return(application_monthly_limit)
allow(namespace).to receive(:extra_shared_runners_minutes_limit).and_return(purchased_minutes)
end
it { is_expected.to eq(result) }
end
end
describe '#total_minutes_used' do
subject { quota.total_minutes_used }
......
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