Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
95d0aec5
Commit
95d0aec5
authored
Apr 01, 2020
by
Doug Stull
Committed by
Ash McKenzie
Apr 01, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add logic for notification dot
- needed for experiment
parent
6fb6be1a
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
375 additions
and
37 deletions
+375
-37
app/helpers/nav_helper.rb
app/helpers/nav_helper.rb
+0
-4
app/views/layouts/header/_default.html.haml
app/views/layouts/header/_default.html.haml
+1
-2
ee/app/helpers/ee/runners_helper.rb
ee/app/helpers/ee/runners_helper.rb
+8
-0
ee/app/services/ci/minutes_notification_service.rb
ee/app/services/ci/minutes_notification_service.rb
+78
-0
ee/app/views/layouts/header/_user_notification_dot.html.haml
ee/app/views/layouts/header/_user_notification_dot.html.haml
+3
-0
ee/app/views/shared/_shared_runners_minutes_limit.html.haml
ee/app/views/shared/_shared_runners_minutes_limit.html.haml
+4
-9
ee/spec/features/ci_shared_runner_warnings_spec.rb
ee/spec/features/ci_shared_runner_warnings_spec.rb
+6
-1
ee/spec/helpers/ee/runners_helper_spec.rb
ee/spec/helpers/ee/runners_helper_spec.rb
+64
-1
ee/spec/services/ci/minutes_notification_service_spec.rb
ee/spec/services/ci/minutes_notification_service_spec.rb
+211
-0
spec/helpers/nav_helper_spec.rb
spec/helpers/nav_helper_spec.rb
+0
-20
No files found.
app/helpers/nav_helper.rb
View file @
95d0aec5
...
@@ -65,10 +65,6 @@ module NavHelper
...
@@ -65,10 +65,6 @@ module NavHelper
%w(groups#issues labels#index milestones#index boards#index boards#show)
%w(groups#issues labels#index milestones#index boards#index boards#show)
end
end
def
show_user_notification_dot?
experiment_enabled?
(
:ci_notification_dot
)
end
private
private
def
get_header_links
def
get_header_links
...
...
app/views/layouts/header/_default.html.haml
View file @
95d0aec5
...
@@ -68,8 +68,7 @@
...
@@ -68,8 +68,7 @@
%li
.nav-item.header-user.dropdown
{
data:
{
track_label:
"profile_dropdown"
,
track_event:
"click_dropdown"
,
track_value:
""
,
qa_selector:
'user_menu'
},
class:
(
'mr-0'
if
has_impersonation_link
)
}
%li
.nav-item.header-user.dropdown
{
data:
{
track_label:
"profile_dropdown"
,
track_event:
"click_dropdown"
,
track_value:
""
,
qa_selector:
'user_menu'
},
class:
(
'mr-0'
if
has_impersonation_link
)
}
=
link_to
current_user
,
class:
user_dropdown_class
,
data:
{
toggle:
"dropdown"
}
do
=
link_to
current_user
,
class:
user_dropdown_class
,
data:
{
toggle:
"dropdown"
}
do
=
image_tag
avatar_icon_for_user
(
current_user
,
23
),
width:
23
,
height:
23
,
class:
"header-user-avatar qa-user-avatar"
=
image_tag
avatar_icon_for_user
(
current_user
,
23
),
width:
23
,
height:
23
,
class:
"header-user-avatar qa-user-avatar"
-
if
show_user_notification_dot?
=
render_if_exists
'layouts/header/user_notification_dot'
,
project:
project
,
namespace:
group
%span
.header-user-notification-dot.rounded-circle.position-relative
=
sprite_icon
(
'angle-down'
,
css_class:
'caret-down'
)
=
sprite_icon
(
'angle-down'
,
css_class:
'caret-down'
)
.dropdown-menu.dropdown-menu-right
.dropdown-menu.dropdown-menu-right
=
render
'layouts/header/current_user_dropdown'
=
render
'layouts/header/current_user_dropdown'
...
...
ee/app/helpers/ee/runners_helper.rb
View file @
95d0aec5
...
@@ -19,6 +19,14 @@ module EE
...
@@ -19,6 +19,14 @@ module EE
experiment_enabled?
(
:buy_ci_minutes_version_a
)
experiment_enabled?
(
:buy_ci_minutes_version_a
)
end
end
def
show_user_notification_dot?
(
project
,
namespace
)
return
false
unless
experiment_enabled?
(
:ci_notification_dot
)
return
false
unless
project
&
.
persisted?
||
namespace
&
.
persisted?
::
Ci
::
MinutesNotificationService
.
call
(
current_user
,
project
,
namespace
).
show_notification?
&&
current_user
.
pipelines
.
any?
end
private
private
def
purchase_shared_runner_minutes_link
def
purchase_shared_runner_minutes_link
...
...
ee/app/services/ci/minutes_notification_service.rb
0 → 100644
View file @
95d0aec5
# frozen_string_literal: true
module
Ci
class
MinutesNotificationService
include
Gitlab
::
Allowable
attr_reader
:namespace
def
self
.
call
(
*
args
)
new
(
*
args
).
call
end
def
initialize
(
current_user
,
project
,
namespace
)
@current_user
=
current_user
@project
=
project
@namespace
=
namespace
end
def
call
calculate
self
end
def
show_notification?
can_see_limit_reached?
&&
namespace
.
shared_runners_remaining_minutes_below_threshold?
end
def
show_alert?
can_see_limit_reached?
&&
below_threshold?
end
def
scope
level
.
full_path
end
private
attr_reader
:project
,
:can_see_status
,
:has_limit
,
:current_user
,
:level
def
calculate
if
at_namespace_level?
calculate_from_namespace_level
else
calculate_from_project_level
end
@has_limit
=
level
.
shared_runners_minutes_limit_enabled?
end
def
at_namespace_level?
namespace
&&
!
project
end
def
calculate_from_namespace_level
@level
=
namespace
@can_see_status
=
true
end
def
calculate_from_project_level
@level
=
project
@namespace
=
project
.
shared_runners_limit_namespace
@can_see_status
=
can?
(
current_user
,
:create_pipeline
,
project
)
end
def
can_see_limit_reached?
has_limit
&&
can_see_status
end
def
below_threshold?
namespace
.
shared_runners_minutes_used?
||
namespace
.
shared_runners_remaining_minutes_below_threshold?
end
end
end
ee/app/views/layouts/header/_user_notification_dot.html.haml
0 → 100644
View file @
95d0aec5
-
return
unless
show_user_notification_dot?
(
project
,
namespace
)
%span
.header-user-notification-dot.rounded-circle.position-relative
ee/app/views/shared/_shared_runners_minutes_limit.html.haml
View file @
95d0aec5
-
project
=
local_assigns
.
fetch
(
:project
,
nil
)
-
notification_service
=
::
Ci
::
MinutesNotificationService
.
call
(
current_user
,
local_assigns
.
dig
(
:project
),
local_assigns
.
dig
(
:namespace
))
-
namespace
=
local_assigns
.
fetch
(
:namespace
,
project
&&
project
.
shared_runners_limit_namespace
)
-
scope
=
(
project
||
namespace
).
full_path
-
has_limit
=
(
project
||
namespace
).
shared_runners_minutes_limit_enabled?
-
can_see_status
=
project
.
nil?
||
can?
(
current_user
,
:create_pipeline
,
project
)
-
ci_warning_message
=
ci_usage_warning_message
(
namespace
,
project
)
-
if
has_limit
&&
can_see_status
&&
ci_warning_message
.
presen
t?
-
if
notification_service
.
show_aler
t?
%div
{
class:
[
"pt-2"
,
(
classes
if
defined?
classes
)]
}
%div
{
class:
[
"pt-2"
,
(
classes
if
defined?
classes
)]
}
.bs-callout.shared-runner-quota-message.d-none.d-sm-block.bs-callout-danger
{
data:
{
scope:
scope
}
}
.bs-callout.shared-runner-quota-message.d-none.d-sm-block.bs-callout-danger
{
data:
{
scope:
notification_service
.
scope
}
}
%p
%p
=
ci_
warning_message
=
ci_
usage_warning_message
(
notification_service
.
namespace
,
project
)
=
link_to
_
(
'Purchase more minutes'
),
::
EE
::
SUBSCRIPTIONS_MORE_MINUTES_URL
,
class:
"btn btn-danger btn-inverted"
=
link_to
_
(
'Purchase more minutes'
),
::
EE
::
SUBSCRIPTIONS_MORE_MINUTES_URL
,
class:
"btn btn-danger btn-inverted"
ee/spec/features/ci_shared_runner_warnings_spec.rb
View file @
95d0aec5
...
@@ -120,7 +120,12 @@ describe 'CI shared runner limits' do
...
@@ -120,7 +120,12 @@ describe 'CI shared runner limits' do
def
expect_quota_exceeded_alert
(
message
=
nil
)
def
expect_quota_exceeded_alert
(
message
=
nil
)
expect
(
page
).
to
have_selector
(
'.shared-runner-quota-message'
,
count:
1
)
expect
(
page
).
to
have_selector
(
'.shared-runner-quota-message'
,
count:
1
)
expect
(
page
.
find
(
'.shared-runner-quota-message'
)).
to
have_content
(
message
)
unless
message
.
nil?
if
message
element
=
page
.
find
(
'.shared-runner-quota-message'
)
expect
(
element
).
to
have_content
(
message
)
expect
(
element
[
'data-scope'
]).
to
eq
(
project
.
full_path
)
end
end
end
def
expect_no_quota_exceeded_alert
def
expect_no_quota_exceeded_alert
...
...
ee/spec/helpers/ee/runners_helper_spec.rb
View file @
95d0aec5
...
@@ -3,10 +3,11 @@
...
@@ -3,10 +3,11 @@
require
"spec_helper"
require
"spec_helper"
describe
EE
::
RunnersHelper
do
describe
EE
::
RunnersHelper
do
let_it_be
(
:user
)
{
create
(
:user
)
}
describe
'.ci_usage_warning_message'
do
describe
'.ci_usage_warning_message'
do
let
(
:project
)
{
create
(
:project
,
namespace:
namespace
)
}
let
(
:project
)
{
create
(
:project
,
namespace:
namespace
)
}
let
(
:minutes_used
)
{
0
}
let
(
:minutes_used
)
{
0
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:namespace
)
do
let
(
:namespace
)
do
create
(
:group
,
shared_runners_minutes_limit:
100
)
create
(
:group
,
shared_runners_minutes_limit:
100
)
...
@@ -158,4 +159,66 @@ describe EE::RunnersHelper do
...
@@ -158,4 +159,66 @@ describe EE::RunnersHelper do
it
{
is_expected
.
to
be_truthy
}
it
{
is_expected
.
to
be_truthy
}
end
end
end
end
describe
'.show_user_notification_dot?'
do
let
(
:experiment_status
)
{
true
}
let
(
:ci_minutes_show
)
{
true
}
let!
(
:user_pipelines
)
{
create
(
:ci_pipeline
,
user:
user
,
project:
nil
)
}
subject
{
helper
.
show_user_notification_dot?
(
project
,
namespace
)
}
before
do
allow
(
helper
).
to
receive
(
:current_user
).
and_return
(
user
)
allow
(
helper
).
to
receive
(
:experiment_enabled?
).
with
(
:ci_notification_dot
).
and_return
(
experiment_status
)
allow
(
::
Ci
::
MinutesNotificationService
).
to
receive_message_chain
(
:call
,
:show_notification?
).
and_return
(
ci_minutes_show
)
end
context
'with a project and namespace'
do
let_it_be
(
:project
)
{
create
(
:project
)
}
let_it_be
(
:namespace
)
{
create
(
:namespace
)
}
context
'when experiment is disabled'
do
let
(
:experiment_status
)
{
false
}
it
{
is_expected
.
to
be_falsey
}
end
context
'when experiment is enabled with user pipelines'
do
it
{
is_expected
.
to
be_truthy
}
context
'without a project'
do
let
(
:project
)
{
build
(
:project
)
}
it
{
is_expected
.
to
be_truthy
}
end
context
'without a namespace'
do
let
(
:namespace
)
{
build
(
:namespace
)
}
it
{
is_expected
.
to
be_truthy
}
end
context
'with neither a project nor a namespace'
do
let
(
:project
)
{
build
(
:project
)
}
let
(
:namespace
)
{
build
(
:namespace
)
}
it
{
is_expected
.
to
be_falsey
}
end
context
'when show notification is falsey'
do
let
(
:ci_minutes_show
)
{
false
}
it
{
is_expected
.
to
be_falsey
}
end
context
'without user pipelines'
do
before
do
user
.
pipelines
.
clear
end
it
{
is_expected
.
to
be_falsey
}
end
end
end
end
end
end
ee/spec/services/ci/minutes_notification_service_spec.rb
0 → 100644
View file @
95d0aec5
# frozen_string_literal: true
require
'spec_helper'
describe
Ci
::
MinutesNotificationService
do
describe
'.call'
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
)
}
let_it_be
(
:group
)
{
create
(
:group
)
}
let
(
:namespace
)
{
group
}
let
(
:prj
)
{
project
}
subject
{
described_class
.
call
(
user
,
prj
,
namespace
)
}
shared_examples
'showing notification'
do
context
'without limit'
do
it
'returns falsey'
do
expect
(
subject
.
show_notification?
).
to
be_falsey
end
end
context
'when limit is defined'
do
context
'when usage has reached a notification level'
do
before
do
group
.
last_ci_minutes_usage_notification_level
=
30
group
.
shared_runners_minutes_limit
=
10
allow_any_instance_of
(
EE
::
Namespace
).
to
receive
(
:shared_runners_remaining_minutes
).
and_return
(
2
)
end
it
'returns truthy'
do
expect
(
subject
.
show_notification?
).
to
be_truthy
end
end
context
'when limit not yet exceeded'
do
let
(
:group
)
{
create
(
:group
,
:with_not_used_build_minutes_limit
)
}
it
'returns falsey'
do
expect
(
subject
.
show_notification?
).
to
be_falsey
end
end
context
'when minutes are not yet set'
do
let
(
:group
)
{
create
(
:group
,
:with_build_minutes_limit
)
}
it
'returns falsey'
do
expect
(
subject
.
show_notification?
).
to
be_falsey
end
end
end
end
shared_examples
'showing alert'
do
context
'without limit'
do
it
'returns falsey'
do
expect
(
subject
.
show_notification?
).
to
be_falsey
end
end
context
'when limit is defined'
do
context
'when usage has reached a notification level'
do
before
do
group
.
last_ci_minutes_usage_notification_level
=
30
group
.
shared_runners_minutes_limit
=
10
allow_any_instance_of
(
EE
::
Namespace
).
to
receive
(
:shared_runners_remaining_minutes
).
and_return
(
2
)
end
it
'returns truthy'
do
expect
(
subject
.
show_notification?
).
to
be_truthy
end
end
context
'when usage has exceeded the limit'
do
let
(
:group
)
{
create
(
:group
,
:with_used_build_minutes_limit
)
}
it
'returns truthy'
do
expect
(
subject
.
show_notification?
).
to
be_truthy
end
end
context
'when limit not yet exceeded'
do
let
(
:group
)
{
create
(
:group
,
:with_not_used_build_minutes_limit
)
}
it
'returns falsey'
do
expect
(
subject
.
show_notification?
).
to
be_falsey
end
end
context
'when minutes are not yet set'
do
let
(
:group
)
{
create
(
:group
,
:with_build_minutes_limit
)
}
it
'returns falsey'
do
expect
(
subject
.
show_notification?
).
to
be_falsey
end
end
end
end
shared_examples
'scoping'
do
describe
'#scope'
do
it
'shows full path'
do
expect
(
subject
.
scope
).
to
eq
level
.
full_path
end
end
end
shared_examples
'show notification project constraints'
do
before
do
group
.
last_ci_minutes_usage_notification_level
=
30
group
.
shared_runners_minutes_limit
=
10
allow_any_instance_of
(
EE
::
Namespace
).
to
receive
(
:shared_runners_remaining_minutes
).
and_return
(
2
)
end
context
'when usage has reached a notification level'
do
it
'returns falsey'
do
expect
(
subject
.
show_notification?
).
to
be_falsey
end
end
end
shared_examples
'show alert project constraints'
do
let
(
:group
)
{
create
(
:group
,
:with_used_build_minutes_limit
)
}
context
'when usage has reached a notification level'
do
it
'returns falsey'
do
expect
(
subject
.
show_alert?
).
to
be_falsey
end
end
end
shared_examples
'class level items'
do
it
'assigns the namespace'
do
expect
(
subject
.
namespace
).
to
eq
group
end
end
context
'when at project level'
do
let
(
:namespace
)
{
nil
}
let
(
:prj
)
{
project
}
it_behaves_like
'class level items'
describe
'#show_notification?'
do
context
'when project member'
do
it_behaves_like
'showing notification'
do
before
do
group
.
add_developer
(
user
)
end
end
end
context
'when not a project member'
do
it_behaves_like
'show notification project constraints'
end
end
describe
'#show_alert?'
do
context
'when project member'
do
it_behaves_like
'showing alert'
do
before
do
group
.
add_developer
(
user
)
end
end
end
context
'when not a project member'
do
it_behaves_like
'show alert project constraints'
end
end
it_behaves_like
'scoping'
do
let
(
:level
)
{
project
}
end
end
context
'when at namespace level'
do
let
(
:prj
)
{
nil
}
it_behaves_like
'class level items'
describe
'#show_notification?'
do
context
'with a project that has runners enabled inside namespace'
do
it_behaves_like
'showing notification'
end
context
'with no projects that have runners enabled inside namespace'
do
it_behaves_like
'show notification project constraints'
do
let
(
:shared_runners_enabled
)
{
false
}
end
end
end
describe
'#show_alert?'
do
context
'with a project that has runners enabled inside namespace'
do
it_behaves_like
'showing alert'
end
context
'with no projects that have runners enabled inside namespace'
do
it_behaves_like
'show alert project constraints'
do
let
(
:shared_runners_enabled
)
{
false
}
end
end
end
it_behaves_like
'scoping'
do
let
(
:level
)
{
group
}
end
end
end
end
spec/helpers/nav_helper_spec.rb
View file @
95d0aec5
...
@@ -117,24 +117,4 @@ describe NavHelper, :do_not_mock_admin_mode do
...
@@ -117,24 +117,4 @@ describe NavHelper, :do_not_mock_admin_mode do
it
{
is_expected
.
to
all
(
be_a
(
String
))
}
it
{
is_expected
.
to
all
(
be_a
(
String
))
}
end
end
describe
'.show_user_notification_dot?'
do
subject
{
helper
.
show_user_notification_dot?
}
context
'when experiment is disabled'
do
before
do
allow
(
helper
).
to
receive
(
:experiment_enabled?
).
with
(
:ci_notification_dot
).
and_return
(
false
)
end
it
{
is_expected
.
to
be_falsey
}
end
context
'when experiment is enabled'
do
before
do
allow
(
helper
).
to
receive
(
:experiment_enabled?
).
with
(
:ci_notification_dot
).
and_return
(
true
)
end
it
{
is_expected
.
to
be_truthy
}
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment