Commit e0a7b6d0 authored by Doug Stull's avatar Doug Stull Committed by Dmytro Zaporozhets

Redesign the runners minutes for enhanced messaging

- have a 30% notification
- have a 5% notification
- have a none left notification
parent 00605603
......@@ -10,6 +10,7 @@ import { __ } from '~/locale';
import PipelinesStore from '../../../../pipelines/stores/pipelines_store';
import pipelinesComponent from '../../../../pipelines/components/pipelines.vue';
import Translate from '../../../../vue_shared/translate';
import initVueAlerts from '../../../../vue_alerts';
Vue.use(Translate);
Vue.use(GlToast);
......@@ -55,3 +56,5 @@ document.addEventListener(
},
}),
);
document.addEventListener('DOMContentLoaded', initVueAlerts);
......@@ -12,8 +12,10 @@ import initReadMore from '~/read_more';
import leaveByUrl from '~/namespaces/leave_by_url';
import Star from '../../../star';
import notificationsDropdown from '../../../notifications_dropdown';
import initVueAlerts from '../../../vue_alerts';
document.addEventListener('DOMContentLoaded', () => {
initVueAlerts();
initReadMore();
new Star(); // eslint-disable-line no-new
notificationsDropdown();
......
......@@ -82,6 +82,14 @@
width: px-to-rem(16px);
}
.gl-shim-pb-3 {
padding-bottom: 8px;
}
.gl-shim-pt-5 {
padding-top: 16px;
}
.gl-text-purple { color: $purple; }
.gl-text-gray-800 { color: $gray-800; }
.gl-bg-purple-light { background-color: $purple-light; }
......
......@@ -3,20 +3,6 @@ module EE
module RunnersHelper
include ::Gitlab::Utils::StrongMemoize
def ci_usage_warning_message(namespace, project)
message = [ci_usage_base_message(namespace)]
return unless message.any?
if ::Gitlab.com? && can?(current_user, :admin_project, project)
message << purchase_shared_runner_minutes_link
elsif namespace.shared_runners_minutes_used?
message << s_('Pipelines|Pipelines will not run anymore on shared Runners.')
end
message.join(' ').html_safe
end
def show_buy_ci_minutes?(project, namespace)
return false unless experiment_enabled?(:ci_notification_dot) || experiment_enabled?(:buy_ci_minutes_version_a)
......@@ -35,22 +21,7 @@ module EE
strong_memoize(:show_out_of_ci_minutes_notification) do
next unless project&.persisted? || namespace&.persisted?
context = ::Ci::Minutes::Context.new(current_user, project, namespace)
::Ci::Minutes::Threshold.new(context).warning_reached?
end
end
def purchase_shared_runner_minutes_link
link = link_to(_("Click here"), EE::SUBSCRIPTIONS_PLANS_URL, target: '_blank', rel: 'noopener')
link + s_("Pipelines| to purchase more minutes.")
end
def ci_usage_base_message(namespace)
if namespace.shared_runners_minutes_used?
s_("Pipelines|%{namespace_name} has exceeded its pipeline minutes quota.") % { namespace_name: namespace.name }
elsif namespace.shared_runners_remaining_minutes_below_threshold?
s_("Pipelines|%{namespace_name} has less than %{notification_level}%% of CI minutes available.") % { namespace_name: namespace.name, notification_level: namespace.last_ci_minutes_usage_notification_level }
::Ci::Minutes::Notification.new(current_user, project, namespace).show?
end
end
end
......
......@@ -3,11 +3,12 @@
module Ci
module Minutes
class Context
attr_reader :namespace
delegate :shared_runners_remaining_minutes_below_threshold?,
:shared_runners_minutes_used?,
:shared_runners_minutes_limit_enabled?, to: :level
delegate :name, to: :namespace, prefix: true
delegate :last_ci_minutes_usage_notification_level,
:shared_runners_remaining_minutes_percent, to: :namespace
def initialize(user, project, namespace)
@user = user
......@@ -26,7 +27,7 @@ module Ci
private
attr_reader :project, :user, :level
attr_reader :project, :user, :level, :namespace
end
end
end
# frozen_string_literal: true
module Ci
module Minutes
class Notification
PERCENTAGES = {
warning: 30,
danger: 5,
exceeded: 0
}.freeze
def initialize(user, project, namespace)
@context = Ci::Minutes::Context.new(user, project, namespace)
@level = calculate_level if eligible_for_notifications?
end
def show?
level.present?
end
def text
contextual_map.dig(level, :text)
end
def style
contextual_map.dig(level, :style)
end
private
attr_reader :context, :level
def eligible_for_notifications?
context.shared_runners_minutes_limit_enabled? && context.can_see_status?
end
def calculate_level
percentage = context.shared_runners_remaining_minutes_percent.to_i
if percentage <= PERCENTAGES[:exceeded]
:exceeded
elsif percentage <= PERCENTAGES[:danger]
:danger
elsif percentage <= PERCENTAGES[:warning]
:warning
end
end
def contextual_map
{
warning: {
style: :warning,
text: threshold_message
},
danger: {
style: :danger,
text: threshold_message
},
exceeded: {
style: :danger,
text: exceeded_message
}
}
end
def exceeded_message
s_("Pipelines|Group %{namespace_name} has exceeded its pipeline minutes quota. " \
"Unless you buy additional pipeline minutes, no new jobs or pipelines in its projects will run.") %
{ namespace_name: context.namespace_name }
end
def threshold_message
s_("Pipelines|Group %{namespace_name} has %{percentage}%% or less Shared Runner Pipeline" \
" minutes remaining. Once it runs out, no new jobs or pipelines in its projects will run.") %
{
namespace_name: context.namespace_name,
percentage: PERCENTAGES[level]
}
end
end
end
end
# frozen_string_literal: true
module Ci
module Minutes
class Threshold
include ::Gitlab::Utils::StrongMemoize
def initialize(context)
@context = context
end
def warning_reached?
show_limit? && context.shared_runners_remaining_minutes_below_threshold?
end
def alert_reached?
show_limit? && context.shared_runners_minutes_used?
end
private
attr_reader :context
def show_limit?
strong_memoize(:show_limit) do
context.shared_runners_minutes_limit_enabled? && context.can_see_status?
end
end
end
end
end
- context = ::Ci::Minutes::Context.new(current_user, local_assigns.dig(:project), local_assigns.dig(:namespace))
- threshold = ::Ci::Minutes::Threshold.new(context)
- notification = ::Ci::Minutes::Notification.new(current_user, local_assigns.dig(:project), local_assigns.dig(:namespace))
- return unless notification.show?
- if threshold.warning_reached? || threshold.alert_reached?
%div{ class: ["pt-2", (classes if defined? classes)] }
.bs-callout.shared-runner-quota-message.d-none.d-sm-block.bs-callout-danger
%p
= ci_usage_warning_message(context.namespace, project)
= link_to _('Purchase more minutes'), ::EE::SUBSCRIPTIONS_MORE_MINUTES_URL, class: "btn btn-danger btn-inverted"
%div{ class: [(classes if defined? classes)] }
.shared-runner-quota-message.gl-shim-pt-5.gl-shim-pb-3
.js-vue-alert{ 'v-cloak': true, data: { variant: notification.style,
secondary_button_text: _('Buy more Pipeline minutes'),
secondary_button_link: ::EE::SUBSCRIPTIONS_MORE_MINUTES_URL,
dismissible: 'false' } }
= notification.text
---
title: Modify existing out of runner minutes banner to handle 3 different warning levels
merge_request: 30088
author:
type: changed
......@@ -11,6 +11,24 @@ describe 'CI shared runner limits' do
sign_in(user)
end
shared_examples 'threshold breached' do
before do
group.update(shared_runners_minutes_limit: 20)
end
it 'displays a warning message on pipelines page' do
visit project_pipelines_path(project)
expect_quota_exceeded_alert(message)
end
it 'displays a warning message on project homepage' do
visit project_path(project)
expect_quota_exceeded_alert(message)
end
end
context 'when project member' do
before do
group.add_developer(user)
......@@ -18,49 +36,62 @@ describe 'CI shared runner limits' do
context 'without limit' do
it 'does not display a warning message on project homepage' do
visit_project_home
visit project_path(project)
expect_no_quota_exceeded_alert
end
it 'does not display a warning message on pipelines page' do
visit_project_pipelines
visit project_pipelines_path(project)
expect_no_quota_exceeded_alert
end
end
context 'when limit is defined' do
before do
stub_const("EE::Namespace::CI_USAGE_ALERT_LEVELS", [30, 5])
end
context 'when usage has reached a notification level' do
before do
group.update(last_ci_minutes_usage_notification_level: 30, shared_runners_minutes_limit: 10)
allow_any_instance_of(EE::Namespace).to receive(:shared_runners_remaining_minutes).and_return(2)
context 'when usage has reached a warning level', :js do
it_behaves_like 'threshold breached' do
let(:message) do
"Group #{group.name} has 30% or less Shared Runner Pipeline minutes remaining. " \
"Once it runs out, no new jobs or pipelines in its projects will run."
end
before do
allow_any_instance_of(EE::Namespace).to receive(:shared_runners_remaining_minutes).and_return(4)
end
end
end
it 'displays a warning message on pipelines page' do
visit_project_pipelines
expect_quota_exceeded_alert("#{group.name} has less than 30% of CI minutes available.")
end
context 'when usage has reached a danger level', :js do
it_behaves_like 'threshold breached' do
let(:message) do
"Group #{group.name} has 5% or less Shared Runner Pipeline minutes remaining. " \
"Once it runs out, no new jobs or pipelines in its projects will run."
end
it 'displays a warning message on project homepage' do
visit_project_home
expect_quota_exceeded_alert("#{group.name} has less than 30% of CI minutes available.")
before do
allow_any_instance_of(EE::Namespace).to receive(:shared_runners_remaining_minutes).and_return(1)
end
end
end
context 'when limit is exceeded' do
context 'when limit is exceeded', :js do
let(:group) { create(:group, :with_used_build_minutes_limit) }
let(:message) do
"Group #{group.name} has exceeded its pipeline minutes quota. " \
"Unless you buy additional pipeline minutes, no new jobs or pipelines in its projects will run."
end
it 'displays a warning message on project homepage' do
visit_project_home
expect_quota_exceeded_alert("#{group.name} has exceeded its pipeline minutes quota.")
visit project_path(project)
expect_quota_exceeded_alert(message)
end
it 'displays a warning message on pipelines page' do
visit_project_pipelines
expect_quota_exceeded_alert("#{group.name} has exceeded its pipeline minutes quota.")
visit project_pipelines_path(project)
expect_quota_exceeded_alert(message)
end
end
......@@ -68,12 +99,14 @@ describe 'CI shared runner limits' do
let(:group) { create(:group, :with_not_used_build_minutes_limit) }
it 'does not display a warning message on project homepage' do
visit_project_home
visit project_path(project)
expect_no_quota_exceeded_alert
end
it 'does not display a warning message on pipelines page' do
visit_project_pipelines
visit project_pipelines_path(project)
expect_no_quota_exceeded_alert
end
end
......@@ -82,12 +115,14 @@ describe 'CI shared runner limits' do
let(:group) { create(:group, :with_build_minutes_limit) }
it 'does not display a warning message on project homepage' do
visit_project_home
visit project_path(project)
expect_no_quota_exceeded_alert
end
it 'does not display a warning message on pipelines page' do
visit_project_pipelines
visit project_pipelines_path(project)
expect_no_quota_exceeded_alert
end
end
......@@ -99,31 +134,27 @@ describe 'CI shared runner limits' do
context 'when limit is defined and limit is exceeded' do
it 'does not display a warning message on project homepage' do
visit_project_home
visit project_path(project)
expect_no_quota_exceeded_alert
end
it 'does not display a warning message on pipelines page' do
visit_project_pipelines
visit project_pipelines_path(project)
expect_no_quota_exceeded_alert
end
end
end
def visit_project_home
visit project_path(project)
end
def visit_project_pipelines
visit project_pipelines_path(project)
end
def expect_quota_exceeded_alert(message = nil)
expect(page).to have_selector('.shared-runner-quota-message', count: 1)
if message
element = page.find('.shared-runner-quota-message')
expect(element).to have_content(message)
page.within('.shared-runner-quota-message') do
expect(page).to have_content(message)
expect(page).to have_link 'Buy more Pipeline minutes'
end
end
end
......
......@@ -9,152 +9,15 @@ describe EE::RunnersHelper do
allow(helper).to receive(:current_user).and_return(user)
end
describe '.ci_usage_warning_message' do
let(:project) { create(:project, namespace: namespace) }
let(:minutes_used) { 0 }
let(:namespace) do
create(:group, shared_runners_minutes_limit: 100)
end
let!(:statistics) do
create(:namespace_statistics, namespace: namespace, shared_runners_seconds: minutes_used * 60)
end
before do
allow(::Gitlab).to receive(:com?).and_return(true)
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).with(user, :admin_project, project) { false }
stub_const("EE::Namespace::CI_USAGE_ALERT_LEVELS", [50])
end
subject { helper.ci_usage_warning_message(namespace, project) }
context 'when CI minutes quota is above the warning limits' do
let(:minutes_used) { 40 }
it 'returns nil' do
expect(subject).to be_nil
end
end
context 'when the last_ci_minutes_usage_notification_level field is set' do
before do
namespace.update_attribute(:last_ci_minutes_usage_notification_level, 50)
end
context 'when there are minutes used but remaining minutes percent is still below the notification threshold' do
let(:minutes_used) { 51 }
it 'returns the partial usage notification message' do
expect(subject).to match("#{namespace.name} has less than 50% of CI minutes available.")
end
end
context 'when limit is increased so there are now more remaining minutes percentage than the notification threshold' do
before do
namespace.update(shared_runners_minutes_limit: 200)
end
it 'returns nil' do
expect(subject).to be_nil
end
end
context 'when there are no more remaining minutes' do
let(:minutes_used) { 100 }
it 'returns the exceeded usage message' do
expect(subject).to match("#{namespace.name} has exceeded its pipeline minutes quota.")
end
end
end
context 'when current user is an owner' do
before do
allow(helper).to receive(:can?).with(user, :admin_project, project) { true }
end
context 'when base message is not present' do
before do
allow(helper).to receive(:ci_usage_base_message).with(namespace).and_return(nil)
end
it 'returns nil' do
expect(subject).to be_nil
end
end
context 'when usage has reached first level of notification' do
let(:minutes_used) { 50 }
before do
namespace.update_attribute(:last_ci_minutes_usage_notification_level, 50)
end
it 'shows the partial usage message' do
expect(subject).to match("#{namespace.name} has less than 50% of CI minutes available.")
expect(subject).to match('to purchase more minutes')
end
end
context 'when usage is above the quota' do
let(:minutes_used) { 120 }
it 'shows the total usage message' do
expect(subject).to match("#{namespace.name} has exceeded its pipeline minutes quota.")
expect(subject).to match('to purchase more minutes')
end
end
end
context 'when current user is not an owner' do
context 'when base message is not present' do
before do
allow(helper).to receive(:ci_usage_base_message).with(namespace).and_return(nil)
end
it 'returns nil' do
expect(subject).to be_nil
end
end
context 'when usage has reached first level of notification' do
let(:minutes_used) { 50 }
before do
namespace.update_attribute(:last_ci_minutes_usage_notification_level, 50)
end
it 'shows the partial usage message without the purchase link' do
expect(subject).to match("#{namespace.name} has less than 50% of CI minutes available.")
expect(subject).not_to match('to purchase more minutes')
end
end
context 'when usage is above the quota' do
let(:minutes_used) { 120 }
it 'shows the total usage message without the purchase link' do
expect(subject).to match("#{namespace.name} has exceeded its pipeline minutes quota.")
expect(subject).not_to match('to purchase more minutes')
end
end
end
end
shared_examples_for 'minutes notification' do
let_it_be(:namespace) { create(:namespace, owner: user) }
let_it_be(:project) { create(:project, namespace: namespace) }
let(:show_warning) { true }
let(:context_level) { project }
let(:context) { double('Ci::Minutes::Context', namespace: namespace) }
let(:threshold) { double('Ci::Minutes::Threshold', warning_reached?: show_warning) }
let(:threshold) { double('Ci::Minutes::Notification', show?: show_warning) }
before do
allow(::Ci::Minutes::Context).to receive(:new).and_return(context)
allow(::Ci::Minutes::Threshold).to receive(:new).and_return(threshold)
allow(::Ci::Minutes::Notification).to receive(:new).and_return(threshold)
end
context 'with a project and namespace' do
......@@ -188,7 +51,7 @@ describe EE::RunnersHelper do
context 'when show_ci_minutes_notification_dot? has been called before' do
it 'does not do all the notification and query work again' do
expect(threshold).not_to receive(:warning_reached?)
expect(threshold).not_to receive(:show?)
expect(project).to receive(:persisted?).once
helper.show_ci_minutes_notification_dot?(project, namespace)
......@@ -206,7 +69,7 @@ describe EE::RunnersHelper do
context 'when show_ci_minutes_notification_dot? has been called before' do
it 'does not do all the notification and query work again' do
expect(threshold).to receive(:warning_reached?).once
expect(threshold).to receive(:show?).once
expect(project).to receive(:persisted?).once
helper.show_ci_minutes_notification_dot?(project, namespace)
......
......@@ -13,21 +13,13 @@ describe Ci::Minutes::Context do
it { is_expected.to delegate_method(:shared_runners_remaining_minutes_below_threshold?).to(:level) }
it { is_expected.to delegate_method(:shared_runners_minutes_used?).to(:level) }
it { is_expected.to delegate_method(:shared_runners_minutes_limit_enabled?).to(:level) }
end
shared_examples 'captures root namespace' do
describe '#namespace' do
it 'assigns the namespace' do
expect(subject.namespace).to eq group
end
end
it { is_expected.to delegate_method(:name).to(:namespace).with_prefix }
it { is_expected.to delegate_method(:last_ci_minutes_usage_notification_level).to(:namespace) }
end
context 'when at project level' do
subject { described_class.new(user, project, nil) }
it_behaves_like 'captures root namespace'
describe '#can_see_status' do
context 'when eligible to see status' do
before do
......@@ -50,8 +42,6 @@ describe Ci::Minutes::Context do
context 'when at namespace level' do
subject { described_class.new(user, nil, group) }
it_behaves_like 'captures root namespace'
describe '#can_see_status' do
context 'when eligible to see status' do
before do
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
describe Ci::Minutes::Threshold do
describe Ci::Minutes::Notification do
let_it_be(:user) { create(:user) }
let(:shared_runners_enabled) { true }
let!(:project) { create(:project, :repository, namespace: group, shared_runners_enabled: shared_runners_enabled) }
......@@ -10,35 +10,12 @@ describe Ci::Minutes::Threshold do
let(:injected_group) { group }
let(:injected_project) { project }
shared_examples 'queries for warning being reached' do
shared_examples 'queries for notifications' do
context 'without limit' do
it { is_expected.to be_falsey }
end
context 'when limit is defined' do
context 'when usage has reached a notification level' do
before do
group.shared_runners_minutes_limit = 10
allow(group).to receive(:shared_runners_remaining_minutes).and_return(2)
end
context 'when over the limit' do
before do
group.last_ci_minutes_usage_notification_level = 30
end
it { is_expected.to be_truthy }
end
context 'when right at the limit for notification' do
before do
group.last_ci_minutes_usage_notification_level = 20
end
it { is_expected.to be_truthy }
end
end
context 'when limit not yet exceeded' do
let(:group) { create(:group, :with_not_used_build_minutes_limit) }
......@@ -50,20 +27,6 @@ describe Ci::Minutes::Threshold do
it { is_expected.to be_falsey }
end
end
end
shared_examples 'queries for alert being reached' do
context 'without limit' do
it { is_expected.to be_falsey }
end
context 'when limit is defined' do
context 'when usage has exceeded the limit' do
let(:group) { create(:group, :with_used_build_minutes_limit) }
it { is_expected.to be_truthy }
end
context 'when limit not yet exceeded' do
let(:group) { create(:group, :with_not_used_build_minutes_limit) }
......@@ -79,129 +42,128 @@ describe Ci::Minutes::Threshold do
end
end
shared_examples 'cannot see if warning reached' do
before do
group.last_ci_minutes_usage_notification_level = 30
group.shared_runners_minutes_limit = 10
allow(group).to receive(:shared_runners_remaining_minutes).and_return(2)
end
context 'when usage has not reached a warning level' do
it { is_expected.to be_falsey }
end
end
shared_examples 'cannot see if alert reached' do
let(:group) { create(:group, :with_used_build_minutes_limit) }
context 'when usage has reached an alert level' do
it { is_expected.to be_falsey }
end
end
shared_examples 'has notifications' do
context 'when usage has reached a notification level' do
before do
group.shared_runners_minutes_limit = 20
end
context 'when at project level' do
let(:context) { ::Ci::Minutes::Context.new(user, injected_project, nil) }
context 'when at the warning level' do
before do
allow(group).to receive(:shared_runners_remaining_minutes).and_return(4)
end
describe '#warning_reached?' do
subject do
threshold = described_class.new(context)
threshold.warning_reached?
it 'has warning notification' do
expect(subject.show?).to be_truthy
expect(subject.text).to match(/.*\shas 30% or less Shared Runner Pipeline minutes remaining/)
expect(subject.style).to eq :warning
end
end
context 'when eligible to see warnings' do
it_behaves_like 'queries for warning being reached' do
before do
group.add_developer(user)
end
context 'when at the danger level' do
before do
allow(group).to receive(:shared_runners_remaining_minutes).and_return(1)
end
end
context 'when not eligible to see warnings' do
it_behaves_like 'cannot see if warning reached'
it 'has danger notification' do
expect(subject.show?).to be_truthy
expect(subject.text).to match(/.*\shas 5% or less Shared Runner Pipeline minutes remaining/)
expect(subject.style).to eq :danger
end
end
end
describe '#alert_reached?' do
subject do
threshold = described_class.new(context)
threshold.alert_reached?
end
context 'when right at the limit for notification' do
before do
allow(group).to receive(:shared_runners_remaining_minutes).and_return(6)
end
context 'when eligible to see alerts' do
it_behaves_like 'queries for alert being reached' do
before do
group.add_developer(user)
end
it 'has warning notification' do
expect(subject.show?).to be_truthy
expect(subject.text).to match(/.*\shas 30% or less Shared Runner Pipeline minutes remaining/)
expect(subject.style).to eq :warning
end
end
context 'when not eligible to see alerts' do
it_behaves_like 'cannot see if alert reached'
context 'when usage has exceeded the limit' do
let(:group) { create(:group, :with_used_build_minutes_limit) }
it 'has exceeded notification' do
expect(subject.show?).to be_truthy
expect(subject.text).to match(/.*\shas exceeded its pipeline minutes quota/)
expect(subject.style).to eq :danger
end
end
end
end
context 'when at namespace level' do
let(:context) { ::Ci::Minutes::Context.new(user, nil, injected_group) }
shared_examples 'not eligible to see notifications' do
before do
group.shared_runners_minutes_limit = 10
allow(group).to receive(:shared_runners_remaining_minutes).and_return(2)
end
describe '#warning_reached?' do
subject do
threshold = described_class.new(context)
threshold.warning_reached?
context 'when not permitted to see notifications' do
it 'has no notifications set' do
expect(subject.show?).to be_falsey
expect(subject.text).to be_nil
expect(subject.style).to be_nil
end
end
end
context 'when eligible to see warnings' do
let!(:user_pipeline) { create(:ci_pipeline, user: user, project: project) }
context 'with a project that has runners enabled inside namespace' do
it_behaves_like 'queries for warning being reached'
context 'when at project level' do
describe '#show?' do
context 'when eligible to see notifications' do
before do
group.add_developer(user)
end
context 'with no projects that have runners enabled inside namespace' do
it_behaves_like 'cannot see if warning reached' do
let(:shared_runners_enabled) { false }
it_behaves_like 'queries for notifications' do
subject do
threshold = described_class.new(user, injected_project, nil)
threshold.show?
end
end
end
context 'when not eligible to see warnings' do
it_behaves_like 'cannot see if warning reached'
it_behaves_like 'has notifications' do
subject { described_class.new(user, injected_project, nil) }
end
end
end
describe '#alert_reached?' do
subject do
threshold = described_class.new(context)
threshold.alert_reached?
it_behaves_like 'not eligible to see notifications' do
subject { described_class.new(user, injected_project, nil) }
end
end
end
context 'when eligible to see warnings' do
context 'when at namespace level' do
describe '#show?' do
context 'when eligible to see notifications' do
let!(:user_pipeline) { create(:ci_pipeline, user: user, project: project) }
context 'with a project that has runners enabled inside namespace' do
it_behaves_like 'queries for alert being reached'
it_behaves_like 'queries for notifications' do
subject do
threshold = described_class.new(user, nil, injected_group)
threshold.show?
end
end
it_behaves_like 'has notifications' do
subject { described_class.new(user, nil, injected_group) }
end
end
context 'with no projects that have runners enabled inside namespace' do
it_behaves_like 'cannot see if alert reached' do
it_behaves_like 'not eligible to see notifications' do
let(:shared_runners_enabled) { false }
subject { described_class.new(user, nil, injected_group) }
end
end
end
context 'when not eligible to see warnings' do
it_behaves_like 'cannot see if warning reached'
end
end
context 'when we have already checked to see if we can show the limit' do
subject { described_class.new(context) }
it 'does not do all the verification work again' do
expect(context).to receive(:shared_runners_minutes_limit_enabled?).once
subject.warning_reached?
subject.alert_reached?
it_behaves_like 'not eligible to see notifications' do
subject { described_class.new(user, nil, injected_group) }
end
end
end
......
......@@ -3357,6 +3357,9 @@ msgstr ""
msgid "Buy GitLab Enterprise Edition"
msgstr ""
msgid "Buy more Pipeline minutes"
msgstr ""
msgid "By %{user_name}"
msgstr ""
......@@ -4152,9 +4155,6 @@ msgstr ""
msgid "Click any <strong>project name</strong> in the project list below to navigate to the project milestone."
msgstr ""
msgid "Click here"
msgstr ""
msgid "Click the <strong>Download</strong> button and wait for downloading to complete."
msgstr ""
......@@ -14923,15 +14923,6 @@ msgstr ""
msgid "Pipelines settings for '%{project_name}' were successfully updated."
msgstr ""
msgid "Pipelines| to purchase more minutes."
msgstr ""
msgid "Pipelines|%{namespace_name} has exceeded its pipeline minutes quota."
msgstr ""
msgid "Pipelines|%{namespace_name} has less than %{notification_level}%% of CI minutes available."
msgstr ""
msgid "Pipelines|API"
msgstr ""
......@@ -14953,10 +14944,13 @@ msgstr ""
msgid "Pipelines|Get started with Pipelines"
msgstr ""
msgid "Pipelines|Loading Pipelines"
msgid "Pipelines|Group %{namespace_name} has %{percentage}%% or less Shared Runner Pipeline minutes remaining. Once it runs out, no new jobs or pipelines in its projects will run."
msgstr ""
msgid "Pipelines|Pipelines will not run anymore on shared Runners."
msgid "Pipelines|Group %{namespace_name} has exceeded its pipeline minutes quota. Unless you buy additional pipeline minutes, no new jobs or pipelines in its projects will run."
msgstr ""
msgid "Pipelines|Loading Pipelines"
msgstr ""
msgid "Pipelines|Project cache successfully reset."
......
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