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
2fcac2b2
Commit
2fcac2b2
authored
Mar 03, 2021
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab master
parents
f2182208
3ac72085
Changes
29
Show whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
600 additions
and
29 deletions
+600
-29
app/services/merge_requests/update_service.rb
app/services/merge_requests/update_service.rb
+11
-0
changelogs/unreleased/292824-track-mr-lock-changes.yml
changelogs/unreleased/292824-track-mr-lock-changes.yml
+5
-0
changelogs/unreleased/expose_project_container_registry_url.yml
...logs/unreleased/expose_project_container_registry_url.yml
+5
-0
config/feature_flags/development/usage_data_i_code_review_user_mr_discussion_locked.yml
...nt/usage_data_i_code_review_user_mr_discussion_locked.yml
+8
-0
config/feature_flags/development/usage_data_i_code_review_user_mr_discussion_unlocked.yml
.../usage_data_i_code_review_user_mr_discussion_unlocked.yml
+8
-0
config/metrics/counts_28d/20210301103859_i_code_review_user_mr_discussion_locked_monthly.yml
...03859_i_code_review_user_mr_discussion_locked_monthly.yml
+20
-0
config/metrics/counts_28d/20210301103925_i_code_review_user_mr_discussion_unlocked_monthly.yml
...925_i_code_review_user_mr_discussion_unlocked_monthly.yml
+20
-0
config/metrics/counts_7d/20210302105258_i_code_review_user_mr_discussion_unlocked_weekly.yml
...5258_i_code_review_user_mr_discussion_unlocked_weekly.yml
+20
-0
config/metrics/counts_7d/20210302105318_i_code_review_user_mr_discussion_locked_weekly.yml
...105318_i_code_review_user_mr_discussion_locked_weekly.yml
+20
-0
doc/api/projects.md
doc/api/projects.md
+13
-0
doc/development/usage_ping/dictionary.md
doc/development/usage_ping/dictionary.md
+80
-0
ee/app/assets/javascripts/oncall_schedules/components/rotations/components/add_edit_rotation_form.vue
...omponents/rotations/components/add_edit_rotation_form.vue
+26
-10
ee/app/assets/javascripts/oncall_schedules/components/rotations/components/add_edit_rotation_modal.vue
...mponents/rotations/components/add_edit_rotation_modal.vue
+30
-5
ee/app/assets/javascripts/oncall_schedules/graphql/fragments/oncall_schedule_rotation.fragment.graphql
...aphql/fragments/oncall_schedule_rotation.fragment.graphql
+1
-0
ee/app/assets/javascripts/security_configuration/components/app.vue
...ets/javascripts/security_configuration/components/app.vue
+7
-1
ee/spec/features/projects/security/user_views_security_configuration_spec.rb
...ojects/security/user_views_security_configuration_spec.rb
+57
-0
ee/spec/frontend/oncall_schedule/mocks/apollo_mock.js
ee/spec/frontend/oncall_schedule/mocks/apollo_mock.js
+4
-2
ee/spec/frontend/oncall_schedule/mocks/mock_rotation.json
ee/spec/frontend/oncall_schedule/mocks/mock_rotation.json
+4
-0
ee/spec/frontend/oncall_schedule/rotations/components/add_edit_rotation_form_spec.js
...edule/rotations/components/add_edit_rotation_form_spec.js
+4
-4
ee/spec/frontend/oncall_schedule/rotations/components/add_edit_rotation_modal_spec.js
...dule/rotations/components/add_edit_rotation_modal_spec.js
+147
-2
lib/api/entities/project.rb
lib/api/entities/project.rb
+2
-0
lib/gitlab/usage_data_counters/aggregated_metrics/code_review.yml
...ab/usage_data_counters/aggregated_metrics/code_review.yml
+6
-2
lib/gitlab/usage_data_counters/known_events/code_review_events.yml
...b/usage_data_counters/known_events/code_review_events.yml
+10
-0
lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
...ge_data_counters/merge_request_activity_unique_counter.rb
+10
-0
locale/gitlab.pot
locale/gitlab.pot
+3
-0
spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
...ta_counters/merge_request_activity_unique_counter_spec.rb
+16
-0
spec/requests/api/project_attributes.yml
spec/requests/api/project_attributes.yml
+1
-0
spec/requests/api/projects_spec.rb
spec/requests/api/projects_spec.rb
+9
-2
spec/services/merge_requests/update_service_spec.rb
spec/services/merge_requests/update_service_spec.rb
+53
-1
No files found.
app/services/merge_requests/update_service.rb
View file @
2fcac2b2
...
...
@@ -47,6 +47,7 @@ module MergeRequests
handle_draft_status_change
(
merge_request
,
changed_fields
)
track_title_and_desc_edits
(
changed_fields
)
track_discussion_lock_toggle
(
merge_request
,
changed_fields
)
notify_if_labels_added
(
merge_request
,
old_labels
)
notify_if_mentions_added
(
merge_request
,
old_mentioned_users
)
...
...
@@ -95,6 +96,16 @@ module MergeRequests
end
end
def
track_discussion_lock_toggle
(
merge_request
,
changed_fields
)
return
unless
changed_fields
.
include?
(
'discussion_locked'
)
if
merge_request
.
discussion_locked
merge_request_activity_counter
.
track_discussion_locked_action
(
user:
current_user
)
else
merge_request_activity_counter
.
track_discussion_unlocked_action
(
user:
current_user
)
end
end
def
notify_if_labels_added
(
merge_request
,
old_labels
)
added_labels
=
merge_request
.
labels
-
old_labels
...
...
changelogs/unreleased/292824-track-mr-lock-changes.yml
0 → 100644
View file @
2fcac2b2
---
title
:
Track usage pings when MR gets locked/unlocked
merge_request
:
55069
author
:
type
:
other
changelogs/unreleased/expose_project_container_registry_url.yml
0 → 100644
View file @
2fcac2b2
---
title
:
Expose container_registry_image_prefix to project API
merge_request
:
54090
author
:
Mathieu Parent
type
:
added
config/feature_flags/development/usage_data_i_code_review_user_mr_discussion_locked.yml
0 → 100644
View file @
2fcac2b2
---
name
:
usage_data_i_code_review_user_mr_discussion_locked
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
rollout_issue_url
:
milestone
:
'
13.10'
type
:
development
group
:
group::code review
default_enabled
:
true
config/feature_flags/development/usage_data_i_code_review_user_mr_discussion_unlocked.yml
0 → 100644
View file @
2fcac2b2
---
name
:
usage_data_i_code_review_user_mr_discussion_unlocked
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
rollout_issue_url
:
milestone
:
'
13.10'
type
:
development
group
:
group::code review
default_enabled
:
true
config/metrics/counts_28d/20210301103859_i_code_review_user_mr_discussion_locked_monthly.yml
0 → 100644
View file @
2fcac2b2
---
key_path
:
redis_hll_counters.code_review.i_code_review_user_mr_discussion_locked_monthly
description
:
Count of unique users per month who locked a MR
product_section
:
dev
product_stage
:
create
product_group
:
group::code review
product_category
:
code_review
value_type
:
number
status
:
implemented
milestone
:
"
13.10"
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
time_frame
:
28d
data_source
:
redis_hll
distribution
:
-
ce
-
ee
tier
:
-
free
-
premium
-
ultimate
config/metrics/counts_28d/20210301103925_i_code_review_user_mr_discussion_unlocked_monthly.yml
0 → 100644
View file @
2fcac2b2
---
key_path
:
redis_hll_counters.code_review.i_code_review_user_mr_discussion_unlocked_monthly
description
:
Count of unique users per month who unlocked a MR
product_section
:
dev
product_stage
:
create
product_group
:
group::code review
product_category
:
code_review
value_type
:
number
status
:
implemented
milestone
:
"
13.10"
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
time_frame
:
28d
data_source
:
redis_hll
distribution
:
-
ce
-
ee
tier
:
-
free
-
premium
-
ultimate
config/metrics/counts_7d/20210302105258_i_code_review_user_mr_discussion_unlocked_weekly.yml
0 → 100644
View file @
2fcac2b2
---
key_path
:
redis_hll_counters.code_review.i_code_review_user_mr_discussion_unlocked_weekly
description
:
Count of unique users per week who unlocked a MR
product_section
:
dev
product_stage
:
create
product_group
:
group::code review
product_category
:
code_review
value_type
:
number
status
:
implemented
milestone
:
"
13.10"
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
time_frame
:
7d
data_source
:
redis_hll
distribution
:
-
ce
-
ee
tier
:
-
free
-
premium
-
ultimate
config/metrics/counts_7d/20210302105318_i_code_review_user_mr_discussion_locked_weekly.yml
0 → 100644
View file @
2fcac2b2
---
key_path
:
redis_hll_counters.code_review.i_code_review_user_mr_discussion_locked_weekly
description
:
Count of unique users per week who locked a MR
product_section
:
dev
product_stage
:
create
product_group
:
group::code review
product_category
:
code_review
value_type
:
number
status
:
implemented
milestone
:
"
13.10"
introduced_by_url
:
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
time_frame
:
7d
data_source
:
redis_hll
distribution
:
-
ce
-
ee
tier
:
-
free
-
premium
-
ultimate
doc/api/projects.md
View file @
2fcac2b2
...
...
@@ -179,6 +179,7 @@ When the user is authenticated and `simple` is not set this returns something li
"packages_size"
:
0
,
"snippets_size"
:
0
},
"container_registry_image_prefix"
:
"registry.example.com/diaspora/diaspora-client"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -284,6 +285,7 @@ When the user is authenticated and `simple` is not set this returns something li
"packages_size"
:
0
,
"snippets_size"
:
0
},
"container_registry_image_prefix"
:
"registry.example.com/brightbox/puppet"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -439,6 +441,7 @@ GET /users/:user_id/projects
"packages_size"
:
0
,
"snippets_size"
:
0
},
"container_registry_image_prefix"
:
"registry.example.com/diaspora/diaspora-client"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -544,6 +547,7 @@ GET /users/:user_id/projects
"packages_size"
:
0
,
"snippets_size"
:
0
},
"container_registry_image_prefix"
:
"registry.example.com/brightbox/puppet"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -658,6 +662,7 @@ Example response:
"lfs_objects_size"
:
0
,
"job_artifacts_size"
:
0
},
"container_registry_image_prefix"
:
"registry.example.com/diaspora/diaspora-client"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -758,6 +763,7 @@ Example response:
"lfs_objects_size"
:
0
,
"job_artifacts_size"
:
0
},
"container_registry_image_prefix"
:
"registry.example.com/brightbox/puppet"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -921,6 +927,7 @@ GET /projects/:id
"packages_size"
:
0
,
"snippets_size"
:
0
},
"container_registry_image_prefix"
:
"registry.example.com/diaspora/diaspora-client"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -1373,6 +1380,7 @@ Example responses:
"merge_method"
:
"merge"
,
"autoclose_referenced_issues"
:
true
,
"suggestion_commit_message"
:
null
,
"container_registry_image_prefix"
:
"registry.example.com/diaspora/diaspora-project-site"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -1467,6 +1475,7 @@ Example response:
"merge_method"
:
"merge"
,
"autoclose_referenced_issues"
:
true
,
"suggestion_commit_message"
:
null
,
"container_registry_image_prefix"
:
"registry.example.com/diaspora/diaspora-project-site"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -1559,6 +1568,7 @@ Example response:
"merge_method"
:
"merge"
,
"autoclose_referenced_issues"
:
true
,
"suggestion_commit_message"
:
null
,
"container_registry_image_prefix"
:
"registry.example.com/diaspora/diaspora-project-site"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -1745,6 +1755,7 @@ Example response:
"merge_method"
:
"merge"
,
"autoclose_referenced_issues"
:
true
,
"suggestion_commit_message"
:
null
,
"container_registry_image_prefix"
:
"registry.example.com/diaspora/diaspora-project-site"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -1858,6 +1869,7 @@ Example response:
"merge_method"
:
"merge"
,
"autoclose_referenced_issues"
:
true
,
"suggestion_commit_message"
:
null
,
"container_registry_image_prefix"
:
"registry.example.com/diaspora/diaspora-project-site"
,
"_links"
:
{
"self"
:
"http://example.com/api/v4/projects"
,
"issues"
:
"http://example.com/api/v4/projects/1/issues"
,
...
...
@@ -2354,6 +2366,7 @@ Example response:
"avatar_url"
:
null
,
"web_url"
:
"https://gitlab.example.com/groups/cute-cats"
},
"container_registry_image_prefix"
:
"registry.example.com/cute-cats/hello-world"
,
"_links"
:
{
"self"
:
"https://gitlab.example.com/api/v4/projects/7"
,
"issues"
:
"https://gitlab.example.com/api/v4/projects/7/issues"
,
...
...
doc/development/usage_ping/dictionary.md
View file @
2fcac2b2
...
...
@@ -13384,6 +13384,86 @@ Count of unique users per week|month who merged a MR
|
`tier`
| |
|
`skip_validation`
| true |
## `redis_hll_counters.code_review.i_code_review_user_mr_discussion_locked_monthly`
Count of unique users per month who locked a MR
| field | value |
| --- | --- |
|
`key_path`
|
**`redis_hll_counters.code_review.i_code_review_user_mr_discussion_locked_monthly`**
|
|
`product_section`
| dev |
|
`product_stage`
| create |
|
`product_group`
|
`group::code review`
|
|
`product_category`
|
`code_review`
|
|
`value_type`
| number |
|
`status`
| implemented |
|
`milestone`
| 13.10 |
|
`introduced_by_url`
|
[
Introduced by
](
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
)
|
|
`time_frame`
| 28d |
|
`data_source`
| Redis_hll |
|
`distribution`
| ce, ee |
|
`tier`
| free, premium, ultimate |
## `redis_hll_counters.code_review.i_code_review_user_mr_discussion_locked_weekly`
Count of unique users per week who locked a MR
| field | value |
| --- | --- |
|
`key_path`
|
**`redis_hll_counters.code_review.i_code_review_user_mr_discussion_locked_weekly`**
|
|
`product_section`
| dev |
|
`product_stage`
| create |
|
`product_group`
|
`group::code review`
|
|
`product_category`
|
`code_review`
|
|
`value_type`
| number |
|
`status`
| implemented |
|
`milestone`
| 13.10 |
|
`introduced_by_url`
|
[
Introduced by
](
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
)
|
|
`time_frame`
| 7d |
|
`data_source`
| Redis_hll |
|
`distribution`
| ce, ee |
|
`tier`
| free, premium, ultimate |
## `redis_hll_counters.code_review.i_code_review_user_mr_discussion_unlocked_monthly`
Count of unique users per month who unlocked a MR
| field | value |
| --- | --- |
|
`key_path`
|
**`redis_hll_counters.code_review.i_code_review_user_mr_discussion_unlocked_monthly`**
|
|
`product_section`
| dev |
|
`product_stage`
| create |
|
`product_group`
|
`group::code review`
|
|
`product_category`
|
`code_review`
|
|
`value_type`
| number |
|
`status`
| implemented |
|
`milestone`
| 13.10 |
|
`introduced_by_url`
|
[
Introduced by
](
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
)
|
|
`time_frame`
| 28d |
|
`data_source`
| Redis_hll |
|
`distribution`
| ce, ee |
|
`tier`
| free, premium, ultimate |
## `redis_hll_counters.code_review.i_code_review_user_mr_discussion_unlocked_weekly`
Count of unique users per week who unlocked a MR
| field | value |
| --- | --- |
|
`key_path`
|
**`redis_hll_counters.code_review.i_code_review_user_mr_discussion_unlocked_weekly`**
|
|
`product_section`
| dev |
|
`product_stage`
| create |
|
`product_group`
|
`group::code review`
|
|
`product_category`
|
`code_review`
|
|
`value_type`
| number |
|
`status`
| implemented |
|
`milestone`
| 13.10 |
|
`introduced_by_url`
|
[
Introduced by
](
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55069
)
|
|
`time_frame`
| 7d |
|
`data_source`
| Redis_hll |
|
`distribution`
| ce, ee |
|
`tier`
| free, premium, ultimate |
## `redis_hll_counters.code_review.i_code_review_user_publish_review_monthly`
Missing description
...
...
ee/app/assets/javascripts/oncall_schedules/components/rotations/components/add_edit_rotation_form.vue
View file @
2fcac2b2
...
...
@@ -40,9 +40,10 @@ export const i18n = {
title
:
__
(
'
Starts on
'
),
error
:
s__
(
'
OnCallSchedules|Rotation start date cannot be empty
'
),
},
ends
On
:
{
ends
At
:
{
enableToggle
:
s__
(
'
OnCallSchedules|Enable end date
'
),
title
:
__
(
'
Ends on
'
),
error
:
s__
(
'
OnCallSchedules|Rotation end date/time must come after start date/time
'
),
},
restrictToTime
:
{
enableToggle
:
s__
(
'
OnCallSchedules|Restrict to time intervals
'
),
...
...
@@ -234,7 +235,7 @@ export default {
<div
class=
"gl-display-inline-block"
>
<gl-toggle
v-model=
"endDateEnabled"
:label=
"$options.i18n.fields.ends
On
.enableToggle"
:label=
"$options.i18n.fields.ends
At
.enableToggle"
label-position=
"left"
class=
"gl-mb-5"
/>
...
...
@@ -245,28 +246,43 @@ export default {
class=
"gl-border-gray-400 gl-bg-gray-10"
>
<gl-form-group
:label=
"$options.i18n.fields.ends
On
.title"
:label=
"$options.i18n.fields.ends
At
.title"
label-size=
"sm"
:invalid-feedback=
"$options.i18n.fields.endsOn.error"
:state=
"validationState.endsAt"
:invalid-feedback=
"$options.i18n.fields.endsAt.error"
class=
"gl-mb-0"
>
<div
class=
"gl-display-flex gl-align-items-center"
>
<gl-datepicker
class=
"gl-mr-3"
@
input=
"$emit('update-rotation-form', { type: 'endsOn.date', value: $event })"
@
input=
"$emit('update-rotation-form', { type: 'endsAt.date', value: $event })"
>
<
template
#default=
"{ formattedDate }"
>
<gl-form-input
class=
"gl-w-full"
:value=
"formattedDate"
:placeholder=
"__(`YYYY-MM-DD`)"
@
blur=
"
$emit('update-rotation-form',
{
type: 'endsAt.date',
value: $event.target.value,
})
"
/>
</
template
>
</gl-datepicker>
<span>
{{ __('at') }}
</span>
<gl-dropdown
data-testid=
"rotation-end-time"
:text=
"format24HourTimeStringFromInt(form.ends
On
.time)"
:text=
"format24HourTimeStringFromInt(form.ends
At
.time)"
class=
"gl-px-3"
>
<gl-dropdown-item
v-for=
"time in $options.HOURS_IN_DAY"
:key=
"time"
:is-checked=
"form.ends
On
.time === time"
:is-checked=
"form.ends
At
.time === time"
is-check-item
@
click=
"$emit('update-rotation-form', { type: 'ends
On
.time', value: time })"
@
click=
"$emit('update-rotation-form', { type: 'ends
At
.time', value: time })"
>
<span
class=
"gl-white-space-nowrap"
>
{{ format24HourTimeStringFromInt(time) }}
</span
...
...
@@ -294,7 +310,7 @@ export default {
<gl-form-group
:label=
"$options.i18n.fields.restrictToTime.title"
label-size=
"sm"
:invalid-feedback=
"$options.i18n.fields.ends
On
.error"
:invalid-feedback=
"$options.i18n.fields.ends
At
.error"
class=
"gl-mb-0"
>
<div
class=
"gl-display-flex gl-align-items-center"
>
...
...
ee/app/assets/javascripts/oncall_schedules/components/rotations/components/add_edit_rotation_modal.vue
View file @
2fcac2b2
...
...
@@ -78,7 +78,7 @@ export default {
date
:
null
,
time
:
0
,
},
ends
On
:
{
ends
At
:
{
date
:
null
,
time
:
0
,
},
...
...
@@ -92,6 +92,7 @@ export default {
name
:
true
,
participants
:
true
,
startsAt
:
true
,
endsAt
:
true
,
},
};
},
...
...
@@ -129,7 +130,8 @@ export default {
name
,
rotationLength
,
participants
,
startsAt
:
{
date
,
time
},
startsAt
:
{
date
:
startDate
,
time
:
startTime
},
endsAt
:
{
date
:
endDate
,
time
:
endTime
},
}
=
this
.
form
;
return
{
...
...
@@ -137,9 +139,15 @@ export default {
scheduleIid
:
this
.
schedule
.
iid
,
name
,
startsAt
:
{
date
:
formatDate
(
d
ate
,
'
yyyy-mm-dd
'
),
time
:
format24HourTimeStringFromInt
(
t
ime
),
date
:
formatDate
(
startD
ate
,
'
yyyy-mm-dd
'
),
time
:
format24HourTimeStringFromInt
(
startT
ime
),
},
endsAt
:
endDate
?
{
date
:
formatDate
(
endDate
,
'
yyyy-mm-dd
'
),
time
:
format24HourTimeStringFromInt
(
endTime
),
}
:
null
,
rotationLength
:
{
...
rotationLength
,
length
:
parseInt
(
rotationLength
.
length
,
10
),
...
...
@@ -150,6 +158,20 @@ export default {
title
()
{
return
this
.
isEditMode
?
this
.
$options
.
i18n
.
editRotation
:
this
.
$options
.
i18n
.
addRotation
;
},
isEndDateValid
()
{
const
startsAt
=
this
.
form
.
startsAt
.
date
?.
getTime
();
const
endsAt
=
this
.
form
.
endsAt
.
date
?.
getTime
();
if
(
!
startsAt
||
!
endsAt
)
{
// If start or end is not present, we consider the end date valid
return
true
;
}
else
if
(
startsAt
<
endsAt
)
{
return
true
;
}
else
if
(
startsAt
===
endsAt
)
{
return
this
.
form
.
startsAt
.
time
<
this
.
form
.
endsAt
.
time
;
}
return
false
;
},
},
methods
:
{
createRotation
()
{
...
...
@@ -244,8 +266,11 @@ export default {
this
.
validationState
.
name
=
isNameFieldValid
(
this
.
form
.
name
);
}
else
if
(
key
===
'
participants
'
)
{
this
.
validationState
.
participants
=
this
.
form
.
participants
.
length
>
0
;
}
else
if
(
key
===
'
startsAt.date
'
)
{
}
else
if
(
key
===
'
startsAt.date
'
||
key
===
'
startsAt.time
'
)
{
this
.
validationState
.
startsAt
=
Boolean
(
this
.
form
.
startsAt
.
date
);
this
.
validationState
.
endsAt
=
this
.
isEndDateValid
;
}
else
if
(
key
===
'
endsAt.date
'
||
key
===
'
endsAt.time
'
)
{
this
.
validationState
.
endsAt
=
this
.
isEndDateValid
;
}
},
},
...
...
ee/app/assets/javascripts/oncall_schedules/graphql/fragments/oncall_schedule_rotation.fragment.graphql
View file @
2fcac2b2
...
...
@@ -4,6 +4,7 @@ fragment OnCallRotation on IncidentManagementOncallRotation {
id
name
startsAt
endsAt
length
lengthUnit
participants
{
...
...
ee/app/assets/javascripts/security_configuration/components/app.vue
View file @
2fcac2b2
...
...
@@ -171,7 +171,13 @@ export default {
</gl-sprintf>
</gl-alert>
<gl-table
ref=
"securityControlTable"
:items=
"features"
:fields=
"fields"
stacked=
"md"
>
<gl-table
ref=
"securityControlTable"
:items=
"features"
:fields=
"fields"
stacked=
"md"
:tbody-tr-attr=
"{ 'data-testid': 'security-scanner-row' }"
>
<
template
#cell(feature)=
"{ item }"
>
<div
class=
"gl-text-gray-900"
>
{{
item
.
name
}}
</div>
<div>
...
...
ee/spec/features/projects/security/user_views_security_configuration_spec.rb
0 → 100644
View file @
2fcac2b2
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
'User sees Security Configuration table'
,
:js
do
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:repository
)
}
before_all
do
project
.
add_developer
(
user
)
end
before
do
sign_in
(
user
)
end
context
'with security_dashboard feature available'
do
before
do
stub_licensed_features
(
security_dashboard:
true
)
end
context
'with no SAST report'
do
it
'shows SAST is not enabled'
do
visit
(
project_security_configuration_path
(
project
))
within_sast_row
do
expect
(
page
).
to
have_text
(
'SAST'
)
expect
(
page
).
to
have_text
(
'Not enabled'
)
expect
(
page
).
to
have_css
(
'[data-testid="enableButton"]'
)
end
end
end
context
'with SAST report'
do
before
do
pipeline
=
create
(
:ci_pipeline
,
project:
project
)
create
(
:ci_build
,
:sast
,
pipeline:
pipeline
,
status:
'success'
)
end
it
'shows SAST is enabled'
do
visit
(
project_security_configuration_path
(
project
))
within_sast_row
do
expect
(
page
).
to
have_text
(
'SAST'
)
expect
(
page
).
to
have_text
(
'Enabled'
)
expect
(
page
).
to
have_css
(
'[data-testid="configureButton"]'
)
end
end
end
end
def
within_sast_row
within
'[data-testid="security-scanner-row"]:nth-of-type(1)'
do
yield
end
end
end
ee/spec/frontend/oncall_schedule/mocks/apollo_mock.js
View file @
2fcac2b2
...
...
@@ -138,7 +138,8 @@ export const createRotationResponse = {
oncallRotation
:
{
id
:
'
44
'
,
name
:
'
Test
'
,
startsAt
:
'
2020-12-17T12:00:00Z
'
,
startsAt
:
'
2020-12-20T12:00:00Z
'
,
endsAt
:
'
2021-03-17T12:00:00Z
'
,
length
:
5
,
lengthUnit
:
'
WEEKS
'
,
participants
:
{
...
...
@@ -171,7 +172,8 @@ export const createRotationResponseWithErrors = {
oncallRotation
:
{
id
:
'
44
'
,
name
:
'
Test
'
,
startsAt
:
'
2020-12-17T12:00:00Z
'
,
startsAt
:
'
2020-12-20T12:00:00Z
'
,
endsAt
:
'
2021-03-17T12:00:00Z
'
,
length
:
5
,
lengthUnit
:
'
WEEKS
'
,
participants
:
{
...
...
ee/spec/frontend/oncall_schedule/mocks/mock_rotation.json
View file @
2fcac2b2
...
...
@@ -2,6 +2,7 @@
"id"
:
"gid://gitlab/IncidentManagement::OncallRotation/2"
,
"name"
:
"Rotation 242"
,
"startsAt"
:
"2021-01-13T10:04:56.333Z"
,
"endsAt"
:
"2021-03-13T10:04:56.333Z"
,
"length"
:
1
,
"lengthUnit"
:
"WEEKS"
,
"participants"
:
{
...
...
@@ -54,6 +55,7 @@
"id"
:
"gid://gitlab/IncidentManagement::OncallRotation/55"
,
"name"
:
"Rotation 242"
,
"startsAt"
:
"2021-01-13T10:04:56.333Z"
,
"endsAt"
:
"2021-03-13T10:04:56.333Z"
,
"length"
:
1
,
"lengthUnit"
:
"WEEKS"
,
"participants"
:
{
...
...
@@ -102,6 +104,7 @@
"id"
:
"gid://gitlab/IncidentManagement::OncallRotation/3"
,
"name"
:
"Rotation 244"
,
"startsAt"
:
"2021-01-06T10:04:56.333Z"
,
"endsAt"
:
"2021-01-10T10:04:56.333Z"
,
"length"
:
1
,
"lengthUnit"
:
"WEEKS"
,
"participants"
:
{
...
...
@@ -150,6 +153,7 @@
"id"
:
"gid://gitlab/IncidentManagement::OncallRotation/5"
,
"name"
:
"Rotation 247"
,
"startsAt"
:
"2021-01-06T10:04:56.333Z"
,
"endsAt"
:
"2021-01-11T10:04:56.333Z"
,
"length"
:
1
,
"lengthUnit"
:
"WEEKS"
,
"participants"
:
{
...
...
ee/spec/frontend/oncall_schedule/rotations/components/add_edit_rotation_form_spec.js
View file @
2fcac2b2
...
...
@@ -40,7 +40,7 @@ describe('AddEditRotationForm', () => {
date
:
null
,
time
:
0
,
},
ends
On
:
{
ends
At
:
{
date
:
null
,
time
:
0
,
},
...
...
@@ -160,7 +160,7 @@ describe('AddEditRotationForm', () => {
await
wrapper
.
vm
.
$nextTick
();
const
emittedEvent
=
wrapper
.
emitted
(
'
update-rotation-form
'
);
expect
(
emittedEvent
).
toHaveLength
(
1
);
expect
(
emittedEvent
[
0
][
0
]).
toEqual
({
type
:
'
ends
On
.time
'
,
value
:
option
+
1
});
expect
(
emittedEvent
[
0
][
0
]).
toEqual
({
type
:
'
ends
At
.time
'
,
value
:
option
+
1
});
});
it
(
'
should add a checkmark to a selected end time
'
,
async
()
=>
{
...
...
@@ -168,7 +168,7 @@ describe('AddEditRotationForm', () => {
const
time
=
5
;
wrapper
.
setProps
({
form
:
{
ends
On
:
{
ends
At
:
{
time
,
},
startsAt
:
{
...
...
@@ -221,7 +221,7 @@ describe('AddEditRotationForm', () => {
wrapper
.
setProps
({
form
:
{
ends
On
:
{
ends
At
:
{
time
:
0
,
},
startsAt
:
{
...
...
ee/spec/frontend/oncall_schedule/rotations/components/add_edit_rotation_modal_spec.js
View file @
2fcac2b2
import
{
GlModal
,
GlAlert
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
AddEditRotationForm
from
'
ee/oncall_schedules/components/rotations/components/add_edit_rotation_form.vue
'
;
import
AddEditRotationModal
,
{
i18n
,
}
from
'
ee/oncall_schedules/components/rotations/components/add_edit_rotation_modal.vue
'
;
...
...
@@ -129,8 +130,9 @@ describe('AddEditRotationModal', () => {
wrapper
=
null
;
});
const
findModal
=
()
=>
wrapper
.
find
(
GlModal
);
const
findAlert
=
()
=>
wrapper
.
find
(
GlAlert
);
const
findModal
=
()
=>
wrapper
.
findComponent
(
GlModal
);
const
findAlert
=
()
=>
wrapper
.
findComponent
(
GlAlert
);
const
findForm
=
()
=>
wrapper
.
findComponent
(
AddEditRotationForm
);
it
(
'
renders rotation modal layout
'
,
()
=>
{
expect
(
wrapper
.
element
).
toMatchSnapshot
();
...
...
@@ -155,6 +157,149 @@ describe('AddEditRotationModal', () => {
expect
(
findAlert
().
exists
()).
toBe
(
true
);
expect
(
findAlert
().
text
()).
toContain
(
error
);
});
describe
(
'
Validation
'
,
()
=>
{
describe
(
'
name
'
,
()
=>
{
it
(
'
is valid when name is NOT empty
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
name
'
,
value
:
''
});
expect
(
form
.
props
(
'
validationState
'
).
name
).
toBe
(
false
);
});
it
(
'
is NOT valid when name is empty
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
name
'
,
value
:
'
Some value
'
});
expect
(
form
.
props
(
'
validationState
'
).
name
).
toBe
(
true
);
});
});
describe
(
'
participants
'
,
()
=>
{
it
(
'
is valid when participants array is NOT empty
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
participants
'
,
value
:
[
'
user1
'
,
'
user2
'
],
});
expect
(
form
.
props
(
'
validationState
'
).
participants
).
toBe
(
true
);
});
it
(
'
is NOT valid when participants array is empty
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
participants
'
,
value
:
[]
});
expect
(
form
.
props
(
'
validationState
'
).
participants
).
toBe
(
false
);
});
});
describe
(
'
startsAt date
'
,
()
=>
{
it
(
'
is valid when date is NOT empty
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
startsAt.date
'
,
value
:
new
Date
(
'
10/12/2021
'
),
});
expect
(
form
.
props
(
'
validationState
'
).
startsAt
).
toBe
(
true
);
});
it
(
'
is NOT valid when date is empty
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
startsAt.time
'
,
value
:
null
});
expect
(
form
.
props
(
'
validationState
'
).
startsAt
).
toBe
(
false
);
});
});
describe
(
'
endsAt date
'
,
()
=>
{
it
(
'
is valid when date is empty
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
endsAt.date
'
,
value
:
null
});
expect
(
form
.
props
(
'
validationState
'
).
endsAt
).
toBe
(
true
);
});
it
(
'
is valid when start date is smaller then end date
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
startsAt.date
'
,
value
:
new
Date
(
'
9/11/2021
'
),
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
endsAt.date
'
,
value
:
new
Date
(
'
10/11/2021
'
),
});
expect
(
form
.
props
(
'
validationState
'
).
endsAt
).
toBe
(
true
);
});
it
(
'
is invalid when start date is larger then end date
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
startsAt.date
'
,
value
:
new
Date
(
'
11/11/2021
'
),
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
endsAt.date
'
,
value
:
new
Date
(
'
10/11/2021
'
),
});
expect
(
form
.
props
(
'
validationState
'
).
endsAt
).
toBe
(
false
);
});
it
(
'
is valid when start and end dates are equal but time is smaller on start date
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
startsAt.date
'
,
value
:
new
Date
(
'
11/11/2021
'
),
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
startsAt.time
'
,
value
:
10
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
endsAt.date
'
,
value
:
new
Date
(
'
11/11/2021
'
),
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
endsAt.time
'
,
value
:
22
});
expect
(
form
.
props
(
'
validationState
'
).
endsAt
).
toBe
(
true
);
});
it
(
'
is invalid when start and end dates are equal but time is larger on start date
'
,
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
startsAt.date
'
,
value
:
new
Date
(
'
11/11/2021
'
),
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
startsAt.time
'
,
value
:
10
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
endsAt.date
'
,
value
:
new
Date
(
'
11/11/2021
'
),
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
endsAt.time
'
,
value
:
8
});
expect
(
form
.
props
(
'
validationState
'
).
endsAt
).
toBe
(
false
);
});
});
describe
(
'
Toggle primary button state
'
,
()
=>
{
it
(
'
should disable primary button when any of the fields is invalid
'
,
async
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
name
'
,
value
:
'
lalal
'
});
await
wrapper
.
vm
.
$nextTick
();
expect
(
findModal
().
props
(
'
actionPrimary
'
).
attributes
).
toEqual
(
expect
.
arrayContaining
([{
disabled
:
true
}]),
);
});
it
(
'
should enable primary button when all fields are valid
'
,
async
()
=>
{
const
form
=
findForm
();
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
name
'
,
value
:
'
Value
'
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
participants
'
,
value
:
[
1
,
2
,
3
]
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
startsAt.date
'
,
value
:
new
Date
(
'
11/10/2021
'
),
});
form
.
vm
.
$emit
(
'
update-rotation-form
'
,
{
type
:
'
endsAt.date
'
,
value
:
new
Date
(
'
12/10/2021
'
),
});
await
wrapper
.
vm
.
$nextTick
();
expect
(
findModal
().
props
(
'
actionPrimary
'
).
attributes
).
toEqual
(
expect
.
arrayContaining
([{
disabled
:
false
}]),
);
});
});
});
});
describe
(
'
with mocked Apollo client
'
,
()
=>
{
...
...
lib/api/entities/project.rb
View file @
2fcac2b2
...
...
@@ -5,6 +5,8 @@ module API
class
Project
<
BasicProjectDetails
include
::
API
::
Helpers
::
RelatedResourcesHelpers
expose
:container_registry_url
,
as: :container_registry_image_prefix
,
if:
->
(
_
,
_
)
{
Gitlab
.
config
.
registry
.
enabled
}
expose
:_links
do
expose
:self
do
|
project
|
expose_url
(
api_v4_projects_path
(
id:
project
.
id
))
...
...
lib/gitlab/usage_data_counters/aggregated_metrics/code_review.yml
View file @
2fcac2b2
...
...
@@ -42,7 +42,9 @@
'
i_code_review_user_approval_rule_edited'
,
'
i_code_review_user_vs_code_api_request'
,
'
i_code_review_user_toggled_task_item_status'
,
'
i_code_review_user_create_mr_from_issue'
'
i_code_review_user_create_mr_from_issue'
,
'
i_code_review_user_mr_discussion_locked'
,
'
i_code_review_user_mr_discussion_unlocked'
]
-
name
:
code_review_category_monthly_active_users
operator
:
OR
...
...
@@ -78,7 +80,9 @@
'
i_code_review_user_approval_rule_deleted'
,
'
i_code_review_user_approval_rule_edited'
,
'
i_code_review_user_toggled_task_item_status'
,
'
i_code_review_user_create_mr_from_issue'
'
i_code_review_user_create_mr_from_issue'
,
'
i_code_review_user_mr_discussion_locked'
,
'
i_code_review_user_mr_discussion_unlocked'
]
-
name
:
code_review_extension_category_monthly_active_users
operator
:
OR
...
...
lib/gitlab/usage_data_counters/known_events/code_review_events.yml
View file @
2fcac2b2
...
...
@@ -164,3 +164,13 @@
category
:
code_review
aggregation
:
weekly
feature_flag
:
usage_data_i_code_review_user_create_mr_from_issue
-
name
:
i_code_review_user_mr_discussion_locked
redis_slot
:
code_review
category
:
code_review
aggregation
:
weekly
feature_flag
:
usage_data_i_code_review_user_mr_discussion_locked
-
name
:
i_code_review_user_mr_discussion_unlocked
redis_slot
:
code_review
category
:
code_review
aggregation
:
weekly
feature_flag
:
usage_data_i_code_review_user_mr_discussion_unlocked
lib/gitlab/usage_data_counters/merge_request_activity_unique_counter.rb
View file @
2fcac2b2
...
...
@@ -35,6 +35,8 @@ module Gitlab
MR_EDIT_MR_TITLE_ACTION
=
'i_code_review_edit_mr_title'
MR_EDIT_MR_DESC_ACTION
=
'i_code_review_edit_mr_desc'
MR_CREATE_FROM_ISSUE_ACTION
=
'i_code_review_user_create_mr_from_issue'
MR_DISCUSSION_LOCKED_ACTION
=
'i_code_review_user_mr_discussion_locked'
MR_DISCUSSION_UNLOCKED_ACTION
=
'i_code_review_user_mr_discussion_unlocked'
class
<<
self
def
track_mr_diffs_action
(
merge_request
:)
...
...
@@ -153,6 +155,14 @@ module Gitlab
track_unique_action_by_user
(
MR_CREATE_FROM_ISSUE_ACTION
,
user
)
end
def
track_discussion_locked_action
(
user
:)
track_unique_action_by_user
(
MR_DISCUSSION_LOCKED_ACTION
,
user
)
end
def
track_discussion_unlocked_action
(
user
:)
track_unique_action_by_user
(
MR_DISCUSSION_UNLOCKED_ACTION
,
user
)
end
private
def
track_unique_action_by_merge_request
(
action
,
merge_request
)
...
...
locale/gitlab.pot
View file @
2fcac2b2
...
...
@@ -21028,6 +21028,9 @@ msgstr ""
msgid "OnCallSchedules|Restrict to time intervals"
msgstr ""
msgid "OnCallSchedules|Rotation end date/time must come after start date/time"
msgstr ""
msgid "OnCallSchedules|Rotation length"
msgstr ""
...
...
spec/lib/gitlab/usage_data_counters/merge_request_activity_unique_counter_spec.rb
View file @
2fcac2b2
...
...
@@ -284,4 +284,20 @@ RSpec.describe Gitlab::UsageDataCounters::MergeRequestActivityUniqueCounter, :cl
let
(
:action
)
{
described_class
::
MR_CREATE_FROM_ISSUE_ACTION
}
end
end
describe
'.track_discussion_locked_action'
do
subject
{
described_class
.
track_discussion_locked_action
(
user:
user
)
}
it_behaves_like
'a tracked merge request unique event'
do
let
(
:action
)
{
described_class
::
MR_DISCUSSION_LOCKED_ACTION
}
end
end
describe
'.track_discussion_unlocked_action'
do
subject
{
described_class
.
track_discussion_unlocked_action
(
user:
user
)
}
it_behaves_like
'a tracked merge request unique event'
do
let
(
:action
)
{
described_class
::
MR_DISCUSSION_UNLOCKED_ACTION
}
end
end
end
spec/requests/api/project_attributes.yml
View file @
2fcac2b2
...
...
@@ -56,6 +56,7 @@ itself: # project
-
can_create_merge_request_in
-
compliance_frameworks
-
container_expiration_policy
-
container_registry_image_prefix
-
default_branch
-
empty_repo
-
forks_count
...
...
spec/requests/api/projects_spec.rb
View file @
2fcac2b2
...
...
@@ -1540,6 +1540,10 @@ RSpec.describe API::Projects do
end
context
'when authenticated as an admin'
do
before
do
stub_container_registry_config
(
enabled:
true
,
host_port:
'registry.example.org:5000'
)
end
let
(
:project_attributes_file
)
{
'spec/requests/api/project_attributes.yml'
}
let
(
:project_attributes
)
{
YAML
.
load_file
(
project_attributes_file
)
}
...
...
@@ -1569,7 +1573,7 @@ RSpec.describe API::Projects do
keys
end
it
'returns a project by id'
do
it
'returns a project by id'
,
:aggregate_failures
do
project
project_member
group
=
create
(
:group
)
...
...
@@ -1587,6 +1591,7 @@ RSpec.describe API::Projects do
expect
(
json_response
[
'ssh_url_to_repo'
]).
to
be_present
expect
(
json_response
[
'http_url_to_repo'
]).
to
be_present
expect
(
json_response
[
'web_url'
]).
to
be_present
expect
(
json_response
[
'container_registry_image_prefix'
]).
to
eq
(
"registry.example.org:5000/
#{
project
.
full_path
}
"
)
expect
(
json_response
[
'owner'
]).
to
be_a
Hash
expect
(
json_response
[
'name'
]).
to
eq
(
project
.
name
)
expect
(
json_response
[
'path'
]).
to
be_present
...
...
@@ -1644,9 +1649,10 @@ RSpec.describe API::Projects do
before
do
project
project_member
stub_container_registry_config
(
enabled:
true
,
host_port:
'registry.example.org:5000'
)
end
it
'returns a project by id'
do
it
'returns a project by id'
,
:aggregate_failures
do
group
=
create
(
:group
)
link
=
create
(
:project_group_link
,
project:
project
,
group:
group
)
...
...
@@ -1662,6 +1668,7 @@ RSpec.describe API::Projects do
expect
(
json_response
[
'ssh_url_to_repo'
]).
to
be_present
expect
(
json_response
[
'http_url_to_repo'
]).
to
be_present
expect
(
json_response
[
'web_url'
]).
to
be_present
expect
(
json_response
[
'container_registry_image_prefix'
]).
to
eq
(
"registry.example.org:5000/
#{
project
.
full_path
}
"
)
expect
(
json_response
[
'owner'
]).
to
be_a
Hash
expect
(
json_response
[
'name'
]).
to
eq
(
project
.
name
)
expect
(
json_response
[
'path'
]).
to
be_present
...
...
spec/services/merge_requests/update_service_spec.rb
View file @
2fcac2b2
...
...
@@ -48,6 +48,8 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
context
'valid params'
do
let
(
:locked
)
{
true
}
let
(
:opts
)
do
{
title:
'New title'
,
...
...
@@ -58,7 +60,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
label_ids:
[
label
.
id
],
target_branch:
'target'
,
force_remove_source_branch:
'1'
,
discussion_locked:
true
discussion_locked:
locked
}
end
...
...
@@ -117,6 +119,56 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
MergeRequests
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
draft_merge_request
)
end
context
'when MR is locked'
do
context
'when locked again'
do
it
'does not track discussion locking'
do
expect
(
Gitlab
::
UsageDataCounters
::
MergeRequestActivityUniqueCounter
)
.
not_to
receive
(
:track_discussion_locked_action
)
opts
[
:discussion_locked
]
=
true
MergeRequests
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
merge_request
)
end
end
context
'when unlocked'
do
it
'tracks dicussion unlocking'
do
expect
(
Gitlab
::
UsageDataCounters
::
MergeRequestActivityUniqueCounter
)
.
to
receive
(
:track_discussion_unlocked_action
).
once
.
with
(
user:
user
)
opts
[
:discussion_locked
]
=
false
MergeRequests
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
merge_request
)
end
end
end
context
'when MR is unlocked'
do
let
(
:locked
)
{
false
}
context
'when unlocked again'
do
it
'does not track discussion unlocking'
do
expect
(
Gitlab
::
UsageDataCounters
::
MergeRequestActivityUniqueCounter
)
.
not_to
receive
(
:track_discussion_unlocked_action
)
opts
[
:discussion_locked
]
=
false
MergeRequests
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
merge_request
)
end
end
context
'when locked'
do
it
'tracks dicussion locking'
do
expect
(
Gitlab
::
UsageDataCounters
::
MergeRequestActivityUniqueCounter
)
.
to
receive
(
:track_discussion_locked_action
).
once
.
with
(
user:
user
)
opts
[
:discussion_locked
]
=
true
MergeRequests
::
UpdateService
.
new
(
project
,
user
,
opts
).
execute
(
merge_request
)
end
end
end
end
context
'updating milestone'
do
...
...
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