diff --git a/config/feature_flags/development/expired_storage_check.yml b/config/feature_flags/development/expired_storage_check.yml new file mode 100644 index 0000000000000000000000000000000000000000..271cc951f1fb81338cd4239fd5430c3897124107 --- /dev/null +++ b/config/feature_flags/development/expired_storage_check.yml @@ -0,0 +1,8 @@ +--- +name: expired_storage_check +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121048 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/411919 +milestone: '16.1' +type: development +group: group::utilization +default_enabled: false diff --git a/ee/app/models/ee/namespace.rb b/ee/app/models/ee/namespace.rb index caaa65ef7a6b9611bd28cc6054055cdb10fbb016..0d3a84b38f9519367578b0f34a33c69663b92849 100644 --- a/ee/app/models/ee/namespace.rb +++ b/ee/app/models/ee/namespace.rb @@ -83,11 +83,17 @@ module Namespace where("EXISTS (?)", matcher) end - delegate :additional_purchased_storage_size, :additional_purchased_storage_size=, + delegate :eligible_additional_purchased_storage_size, :additional_purchased_storage_size=, :additional_purchased_storage_ends_on, :additional_purchased_storage_ends_on=, :temporary_storage_increase_ends_on, :temporary_storage_increase_ends_on=, to: :namespace_limit, allow_nil: true + # `eligible_additional_purchased_storage_size` uses a FF to start checking `additional_purchased_storage_ends_on` + # if the FF is enabled before returning `additional_purchased_storage_size` + # To minimize the footprint of the change, aliasing namespace.additional_purchased_storage_size + # to namespace.eligible_additional_purchased_storage_size + alias_method :additional_purchased_storage_size, :eligible_additional_purchased_storage_size + delegate :email, to: :owner, allow_nil: true, prefix: true # Opportunistically clear the +file_template_project_id+ if invalid diff --git a/ee/app/models/namespace_limit.rb b/ee/app/models/namespace_limit.rb index 3d1e630d0cae0cc81f8b9ed23b8ccc3d35c203dc..9b0560106c637cf5a1de43912a9adf5a10823375 100644 --- a/ee/app/models/namespace_limit.rb +++ b/ee/app/models/namespace_limit.rb @@ -26,6 +26,16 @@ def eligible_for_temporary_storage_increase? namespace.root_storage_size.usage_ratio >= MIN_REQURIED_STORAGE_USAGE_RATIO end + def eligible_additional_purchased_storage_size + if Feature.enabled?(:expired_storage_check, namespace) && + additional_purchased_storage_ends_on && + Date.today > additional_purchased_storage_ends_on + 0 + else + additional_purchased_storage_size + end + end + private def namespace_is_root_namespace diff --git a/ee/spec/models/ee/namespace_spec.rb b/ee/spec/models/ee/namespace_spec.rb index 3999051e2fee6572161e1c091ff5b12b12eb052f..65416e23ddc6d60a7cb062f6eeec9efd15a96167 100644 --- a/ee/spec/models/ee/namespace_spec.rb +++ b/ee/spec/models/ee/namespace_spec.rb @@ -25,7 +25,6 @@ it { is_expected.to delegate_method(:upgradable?).to(:gitlab_subscription) } it { is_expected.to delegate_method(:trial_extended_or_reactivated?).to(:gitlab_subscription) } it { is_expected.to delegate_method(:email).to(:owner).with_prefix.allow_nil } - it { is_expected.to delegate_method(:additional_purchased_storage_size).to(:namespace_limit) } it { is_expected.to delegate_method(:additional_purchased_storage_size=).to(:namespace_limit).with_arguments(:args) } it { is_expected.to delegate_method(:additional_purchased_storage_ends_on).to(:namespace_limit) } it { is_expected.to delegate_method(:additional_purchased_storage_ends_on=).to(:namespace_limit).with_arguments(:args) } @@ -1304,6 +1303,13 @@ end end + describe '#additional_purchased_storage_size' do + it 'calls namespace_limit#eligible_additional_purchased_storage_size' do + expect(namespace.namespace_limit).to receive(:eligible_additional_purchased_storage_size) + namespace.additional_purchased_storage_size + end + end + describe '#contains_locked_projects?' do using RSpec::Parameterized::TableSyntax diff --git a/ee/spec/models/namespace_limit_spec.rb b/ee/spec/models/namespace_limit_spec.rb index 6fcc2e468faeef9fa060c8fb1db820bbca651ab9..0c5722a71b6e54d116f4c0ea6f3c17b192334697 100644 --- a/ee/spec/models/namespace_limit_spec.rb +++ b/ee/spec/models/namespace_limit_spec.rb @@ -95,6 +95,63 @@ end end + describe '#eligible_additional_purchased_storage_size' do + subject { namespace_limit.eligible_additional_purchased_storage_size } + + before do + allow(namespace_limit).to receive(:additional_purchased_storage_size) + .and_return(10) + end + + context 'with expired_storage_check ff enabled' do + before do + stub_feature_flags(expired_storage_check: true) + end + + context 'with expired storage' do + before do + allow(namespace_limit).to receive(:additional_purchased_storage_ends_on) + .and_return(Date.yesterday) + end + + it { is_expected.to eq(0) } + end + + context 'with valid storage' do + before do + allow(namespace_limit).to receive(:additional_purchased_storage_ends_on) + .and_return(Date.tomorrow) + end + + it { is_expected.to eq(10) } + end + end + + context 'with expired_storage_check ff disabled' do + before do + stub_feature_flags(expired_storage_check: false) + end + + context 'with expired storage' do + before do + allow(namespace_limit).to receive(:additional_purchased_storage_ends_on) + .and_return(Date.yesterday) + end + + it { is_expected.to eq(10) } + end + + context 'with valid storage' do + before do + allow(namespace_limit).to receive(:additional_purchased_storage_ends_on) + .and_return(Date.tomorrow) + end + + it { is_expected.to eq(10) } + end + end + end + describe 'validations' do it { is_expected.to validate_presence_of(:namespace) }