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
edfe463a
Commit
edfe463a
authored
Dec 14, 2020
by
Heinrich Lee Yu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Handle showing of iteration lists in boards
Also handles moving of issues to / from an iteration list
parent
2503be2f
Changes
20
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
282 additions
and
47 deletions
+282
-47
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+5
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+14
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+1
-0
ee/app/graphql/ee/types/board_list_type.rb
ee/app/graphql/ee/types/board_list_type.rb
+6
-0
ee/app/models/ee/list.rb
ee/app/models/ee/list.rb
+5
-1
ee/app/models/license.rb
ee/app/models/license.rb
+1
-0
ee/app/services/ee/boards/issues/list_service.rb
ee/app/services/ee/boards/issues/list_service.rb
+27
-0
ee/app/services/ee/boards/issues/move_service.rb
ee/app/services/ee/boards/issues/move_service.rb
+14
-5
ee/app/services/ee/boards/lists/create_service.rb
ee/app/services/ee/boards/lists/create_service.rb
+1
-10
ee/app/services/ee/boards/lists/list_service.rb
ee/app/services/ee/boards/lists/list_service.rb
+5
-6
ee/spec/controllers/boards/lists_controller_spec.rb
ee/spec/controllers/boards/lists_controller_spec.rb
+2
-2
ee/spec/factories/lists.rb
ee/spec/factories/lists.rb
+6
-1
ee/spec/graphql/ee/mutations/boards/lists/create_spec.rb
ee/spec/graphql/ee/mutations/boards/lists/create_spec.rb
+2
-2
ee/spec/graphql/ee/types/board_list_type_spec.rb
ee/spec/graphql/ee/types/board_list_type_spec.rb
+1
-1
ee/spec/models/ee/list_spec.rb
ee/spec/models/ee/list_spec.rb
+1
-1
ee/spec/services/ee/boards/issues/list_service_spec.rb
ee/spec/services/ee/boards/issues/list_service_spec.rb
+44
-2
ee/spec/services/ee/boards/issues/move_service_spec.rb
ee/spec/services/ee/boards/issues/move_service_spec.rb
+92
-2
ee/spec/services/ee/boards/lists/create_service_spec.rb
ee/spec/services/ee/boards/lists/create_service_spec.rb
+2
-2
ee/spec/services/ee/boards/lists/list_service_spec.rb
ee/spec/services/ee/boards/lists/list_service_spec.rb
+51
-10
ee/spec/support/shared_examples/requests/api/iteration_board_list_shared_examples.rb
...ples/requests/api/iteration_board_list_shared_examples.rb
+2
-2
No files found.
doc/api/graphql/reference/gitlab_schema.graphql
View file @
edfe463a
...
@@ -2029,6 +2029,11 @@ type BoardList {
...
@@ -2029,6 +2029,11 @@ type BoardList {
"""
"""
issuesCount
:
Int
issuesCount
:
Int
"""
Iteration
of
the
list
"""
iteration
:
Iteration
"""
"""
Label
of
the
list
Label
of
the
list
"""
"""
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
edfe463a
...
@@ -5351,6 +5351,20 @@
...
@@ -5351,6 +5351,20 @@
"isDeprecated": false,
"isDeprecated": false,
"deprecationReason": null
"deprecationReason": null
},
},
{
"name": "iteration",
"description": "Iteration of the list",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "Iteration",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
{
"name": "label",
"name": "label",
"description": "Label of the list",
"description": "Label of the list",
doc/api/graphql/reference/index.md
View file @
edfe463a
...
@@ -325,6 +325,7 @@ Represents a list for an issue board.
...
@@ -325,6 +325,7 @@ Represents a list for an issue board.
|
`id`
| ID! | ID (global ID) of the list |
|
`id`
| ID! | ID (global ID) of the list |
|
`issues`
| IssueConnection | Board issues |
|
`issues`
| IssueConnection | Board issues |
|
`issuesCount`
| Int | Count of issues in the list |
|
`issuesCount`
| Int | Count of issues in the list |
|
`iteration`
| Iteration | Iteration of the list |
|
`label`
| Label | Label of the list |
|
`label`
| Label | Label of the list |
|
`limitMetric`
| ListLimitMetric | The current limit metric for the list |
|
`limitMetric`
| ListLimitMetric | The current limit metric for the list |
|
`listType`
| String! | Type of the list |
|
`listType`
| String! | Type of the list |
...
...
ee/app/graphql/ee/types/board_list_type.rb
View file @
edfe463a
...
@@ -8,6 +8,8 @@ module EE
...
@@ -8,6 +8,8 @@ module EE
prepended
do
prepended
do
field
:milestone
,
::
Types
::
MilestoneType
,
null:
true
,
field
:milestone
,
::
Types
::
MilestoneType
,
null:
true
,
description:
'Milestone of the list'
description:
'Milestone of the list'
field
:iteration
,
::
Types
::
IterationType
,
null:
true
,
description:
'Iteration of the list'
field
:max_issue_count
,
GraphQL
::
INT_TYPE
,
null:
true
,
field
:max_issue_count
,
GraphQL
::
INT_TYPE
,
null:
true
,
description:
'Maximum number of issues in the list'
description:
'Maximum number of issues in the list'
field
:max_issue_weight
,
GraphQL
::
INT_TYPE
,
null:
true
,
field
:max_issue_weight
,
GraphQL
::
INT_TYPE
,
null:
true
,
...
@@ -23,6 +25,10 @@ module EE
...
@@ -23,6 +25,10 @@ module EE
::
Gitlab
::
Graphql
::
Loaders
::
BatchModelLoader
.
new
(
::
Milestone
,
object
.
milestone_id
).
find
::
Gitlab
::
Graphql
::
Loaders
::
BatchModelLoader
.
new
(
::
Milestone
,
object
.
milestone_id
).
find
end
end
def
iteration
::
Gitlab
::
Graphql
::
Loaders
::
BatchModelLoader
.
new
(
::
Iteration
,
object
.
iteration_id
).
find
end
def
assignee
def
assignee
object
.
assignee?
?
object
.
user
:
nil
object
.
assignee?
?
object
.
user
:
nil
end
end
...
...
ee/app/models/ee/list.rb
View file @
edfe463a
...
@@ -8,6 +8,10 @@ module EE
...
@@ -8,6 +8,10 @@ module EE
LIMIT_METRIC_TYPES
=
%w[all_metrics issue_count issue_weights]
.
freeze
LIMIT_METRIC_TYPES
=
%w[all_metrics issue_count issue_weights]
.
freeze
# When adding a new licensed type, make sure to also add
# it on license.rb with the pattern "board_<list_type>_lists"
LICENSED_LIST_TYPES
=
%i[assignee milestone iteration]
.
freeze
# ActiveSupport::Concern does not prepend the ClassMethods,
# ActiveSupport::Concern does not prepend the ClassMethods,
# so we cannot call `super` if we use it.
# so we cannot call `super` if we use it.
def
self
.
prepended
(
base
)
def
self
.
prepended
(
base
)
...
@@ -42,7 +46,7 @@ module EE
...
@@ -42,7 +46,7 @@ module EE
unless:
->
{
board
&
.
resource_parent
&
.
feature_available?
(
:board_milestone_lists
)
}
unless:
->
{
board
&
.
resource_parent
&
.
feature_available?
(
:board_milestone_lists
)
}
base
.
validates
:list_type
,
base
.
validates
:list_type
,
exclusion:
{
in:
%w[iteration]
,
message:
->
(
_object
,
_data
)
{
_
(
'Iteration lists not available with your current license'
)
}
},
exclusion:
{
in:
%w[iteration]
,
message:
->
(
_object
,
_data
)
{
_
(
'Iteration lists not available with your current license'
)
}
},
unless:
->
{
board
&
.
resource_parent
&
.
feature_available?
(
:
iteration
s
)
}
unless:
->
{
board
&
.
resource_parent
&
.
feature_available?
(
:
board_iteration_list
s
)
}
base
.
scope
:without_types
,
->
(
list_types
)
{
where
.
not
(
list_type:
list_types
)
}
base
.
scope
:without_types
,
->
(
list_types
)
{
where
.
not
(
list_type:
list_types
)
}
end
end
...
...
ee/app/models/license.rb
View file @
edfe463a
...
@@ -14,6 +14,7 @@ class License < ApplicationRecord
...
@@ -14,6 +14,7 @@ class License < ApplicationRecord
EES_FEATURES
=
%i[
EES_FEATURES
=
%i[
audit_events
audit_events
blocked_issues
blocked_issues
board_iteration_lists
code_owners
code_owners
code_review_analytics
code_review_analytics
contribution_analytics
contribution_analytics
...
...
ee/app/services/ee/boards/issues/list_service.rb
View file @
edfe463a
...
@@ -13,6 +13,7 @@ module EE
...
@@ -13,6 +13,7 @@ module EE
unless
list
&
.
movable?
||
list
&
.
closed?
unless
list
&
.
movable?
||
list
&
.
closed?
issues
=
without_assignees_from_lists
(
issues
)
issues
=
without_assignees_from_lists
(
issues
)
issues
=
without_milestones_from_lists
(
issues
)
issues
=
without_milestones_from_lists
(
issues
)
issues
=
without_iterations_from_lists
(
issues
)
end
end
case
list
&
.
list_type
case
list
&
.
list_type
...
@@ -20,6 +21,8 @@ module EE
...
@@ -20,6 +21,8 @@ module EE
with_assignee
(
super
)
with_assignee
(
super
)
when
'milestone'
when
'milestone'
with_milestone
(
super
)
with_milestone
(
super
)
when
'iteration'
with_iteration
(
super
)
else
else
super
super
end
end
...
@@ -58,6 +61,18 @@ module EE
...
@@ -58,6 +61,18 @@ module EE
end
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def
all_iteration_lists
# Note that the names are very similar but these are different.
# One is a license name and the other is a feature flag
if
parent
.
feature_available?
(
:board_iteration_lists
)
&&
::
Feature
.
enabled?
(
:iteration_board_lists
,
parent
)
board
.
lists
.
iteration
.
where
.
not
(
iteration_id:
nil
)
else
::
List
.
none
end
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def
without_assignees_from_lists
(
issues
)
def
without_assignees_from_lists
(
issues
)
return
issues
if
all_assignee_lists
.
empty?
return
issues
if
all_assignee_lists
.
empty?
...
@@ -85,6 +100,14 @@ module EE
...
@@ -85,6 +100,14 @@ module EE
end
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def
without_iterations_from_lists
(
issues
)
return
issues
if
all_iteration_lists
.
empty?
issues
.
not_in_iterations
(
all_iteration_lists
.
select
(
:iteration_id
))
end
# rubocop: enable CodeReuse/ActiveRecord
def
with_assignee
(
issues
)
def
with_assignee
(
issues
)
issues
.
assigned_to
(
list
.
user
)
issues
.
assigned_to
(
list
.
user
)
end
end
...
@@ -95,6 +118,10 @@ module EE
...
@@ -95,6 +118,10 @@ module EE
end
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: enable CodeReuse/ActiveRecord
def
with_iteration
(
issues
)
issues
.
in_iterations
(
list
.
iteration_id
)
end
# Prevent filtering by milestone stubs
# Prevent filtering by milestone stubs
# like Milestone::Upcoming, Milestone::Started etc
# like Milestone::Upcoming, Milestone::Started etc
def
has_valid_milestone?
def
has_valid_milestone?
...
...
ee/app/services/ee/boards/issues/move_service.rb
View file @
edfe463a
...
@@ -34,19 +34,28 @@ module EE
...
@@ -34,19 +34,28 @@ module EE
assignee_ids
=
assignee_ids
(
issue
)
assignee_ids
=
assignee_ids
(
issue
)
milestone_id
=
milestone_id
(
issue
)
milestone_id
=
milestone_id
(
issue
)
{
movement_args
=
{
assignee_ids:
assignee_ids
,
assignee_ids:
assignee_ids
,
milestone_id:
milestone_id
milestone_id:
milestone_id
}
}
movement_args
[
:sprint_id
]
=
iteration_id
(
issue
)
if
::
Feature
.
enabled?
(
:iteration_board_lists
,
parent
)
movement_args
end
end
def
milestone_id
(
issue
)
def
milestone_id
(
issue
)
# We want to nullify the issue milestone.
return
if
moving_to_list
.
backlog?
&&
moving_from_list
.
milestone?
return
if
moving_to_list
.
backlog?
&&
moving_from_list
.
milestone?
return
moving_to_list
.
milestone_id
if
moving_to_list
.
milestone?
issue
.
milestone_id
end
def
iteration_id
(
issue
)
return
if
moving_to_list
.
backlog?
&&
moving_from_list
.
iteration?
return
moving_to_list
.
iteration_id
if
moving_to_list
.
iteration?
# Moving to a list which is not a 'milestone list' will keep
issue
.
sprint_id
# the already existent milestone.
[
issue
.
milestone_id
,
moving_to_list
.
milestone_id
].
compact
.
last
end
end
def
assignee_ids
(
issue
)
def
assignee_ids
(
issue
)
...
...
ee/app/services/ee/boards/lists/create_service.rb
View file @
edfe463a
...
@@ -19,16 +19,7 @@ module EE
...
@@ -19,16 +19,7 @@ module EE
private
private
def
valid_license?
(
parent
)
def
valid_license?
(
parent
)
license_name
=
case
type
List
::
LICENSED_LIST_TYPES
.
exclude?
(
type
)
||
parent
.
feature_available?
(
:"board_
#{
type
}
_lists"
)
when
:assignee
:board_assignee_lists
when
:milestone
:board_milestone_lists
when
:iteration
:iterations
end
license_name
.
nil?
||
parent
.
feature_available?
(
license_name
)
end
end
def
license_validation_error
def
license_validation_error
...
...
ee/app/services/ee/boards/lists/list_service.rb
View file @
edfe463a
...
@@ -6,10 +6,6 @@ module EE
...
@@ -6,10 +6,6 @@ module EE
module
ListService
module
ListService
extend
::
Gitlab
::
Utils
::
Override
extend
::
Gitlab
::
Utils
::
Override
# When adding a new licensed type, make sure to also add
# it on license.rb with the pattern "board_<list_type>_lists"
LICENSED_LIST_TYPES
=
%i[assignee milestone]
.
freeze
override
:execute
override
:execute
def
execute
(
board
,
create_default_lists:
true
)
def
execute
(
board
,
create_default_lists:
true
)
list_types
=
unavailable_list_types_for
(
board
)
list_types
=
unavailable_list_types_for
(
board
)
...
@@ -20,7 +16,10 @@ module EE
...
@@ -20,7 +16,10 @@ module EE
private
private
def
unavailable_list_types_for
(
board
)
def
unavailable_list_types_for
(
board
)
(
hidden_lists_for
(
board
)
+
unlicensed_lists_for
(
board
)).
uniq
list_types
=
hidden_lists_for
(
board
)
+
unlicensed_lists_for
(
board
)
list_types
<<
::
List
.
list_types
[
:iteration
]
if
::
Feature
.
disabled?
(
:iteration_board_lists
,
board
.
resource_parent
)
list_types
.
uniq
end
end
def
hidden_lists_for
(
board
)
def
hidden_lists_for
(
board
)
...
@@ -35,7 +34,7 @@ module EE
...
@@ -35,7 +34,7 @@ module EE
def
unlicensed_lists_for
(
board
)
def
unlicensed_lists_for
(
board
)
parent
=
board
.
resource_parent
parent
=
board
.
resource_parent
LICENSED_LIST_TYPES
.
each_with_object
([])
do
|
list_type
,
lists
|
L
ist
::
L
ICENSED_LIST_TYPES
.
each_with_object
([])
do
|
list_type
,
lists
|
list_type_key
=
::
List
.
list_types
[
list_type
]
list_type_key
=
::
List
.
list_types
[
list_type
]
lists
<<
list_type_key
unless
parent
&
.
feature_available?
(
:"board_
#{
list_type
}
_lists"
)
lists
<<
list_type_key
unless
parent
&
.
feature_available?
(
:"board_
#{
list_type
}
_lists"
)
end
end
...
...
ee/spec/controllers/boards/lists_controller_spec.rb
View file @
edfe463a
...
@@ -79,7 +79,7 @@ RSpec.describe Boards::ListsController do
...
@@ -79,7 +79,7 @@ RSpec.describe Boards::ListsController do
context
'when license is available'
do
context
'when license is available'
do
before
do
before
do
stub_licensed_features
(
iteration
s:
true
)
stub_licensed_features
(
board_iteration_list
s:
true
)
end
end
it
'returns a successful 200 response'
do
it
'returns a successful 200 response'
do
...
@@ -92,7 +92,7 @@ RSpec.describe Boards::ListsController do
...
@@ -92,7 +92,7 @@ RSpec.describe Boards::ListsController do
context
'when license is unavailable'
do
context
'when license is unavailable'
do
before
do
before
do
stub_licensed_features
(
iteration
s:
false
)
stub_licensed_features
(
board_iteration_list
s:
false
)
end
end
it
'returns an error'
do
it
'returns an error'
do
...
...
ee/spec/factories/lists.rb
View file @
edfe463a
...
@@ -10,7 +10,12 @@ FactoryBot.define do
...
@@ -10,7 +10,12 @@ FactoryBot.define do
factory
:milestone_list
,
parent: :list
do
factory
:milestone_list
,
parent: :list
do
list_type
{
:milestone
}
list_type
{
:milestone
}
label
{
nil
}
label
{
nil
}
user
{
nil
}
milestone
milestone
end
end
factory
:iteration_list
,
parent: :list
do
list_type
{
:iteration
}
label
{
nil
}
iteration
end
end
end
ee/spec/graphql/ee/mutations/boards/lists/create_spec.rb
View file @
edfe463a
...
@@ -21,7 +21,7 @@ RSpec.describe Mutations::Boards::Lists::Create do
...
@@ -21,7 +21,7 @@ RSpec.describe Mutations::Boards::Lists::Create do
end
end
before
do
before
do
stub_licensed_features
(
board_assignee_lists:
true
,
board_milestone_lists:
true
,
iteration
s:
true
)
stub_licensed_features
(
board_assignee_lists:
true
,
board_milestone_lists:
true
,
board_iteration_list
s:
true
)
end
end
subject
{
mutation
.
resolve
(
board_id:
board
.
to_global_id
.
to_s
,
**
list_create_params
)
}
subject
{
mutation
.
resolve
(
board_id:
board
.
to_global_id
.
to_s
,
**
list_create_params
)
}
...
@@ -108,7 +108,7 @@ RSpec.describe Mutations::Boards::Lists::Create do
...
@@ -108,7 +108,7 @@ RSpec.describe Mutations::Boards::Lists::Create do
context
'when feature unavailable'
do
context
'when feature unavailable'
do
it
'returns an error'
do
it
'returns an error'
do
stub_licensed_features
(
iteration
s:
false
)
stub_licensed_features
(
board_iteration_list
s:
false
)
expect
(
subject
[
:errors
]).
to
include
'Iteration lists not available with your current license'
expect
(
subject
[
:errors
]).
to
include
'Iteration lists not available with your current license'
end
end
...
...
ee/spec/graphql/ee/types/board_list_type_spec.rb
View file @
edfe463a
...
@@ -4,7 +4,7 @@ require 'spec_helper'
...
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec
.
describe
GitlabSchema
.
types
[
'BoardList'
]
do
RSpec
.
describe
GitlabSchema
.
types
[
'BoardList'
]
do
it
'has specific fields'
do
it
'has specific fields'
do
expected_fields
=
%w[milestone max_issue_count max_issue_weight assignee total_weight]
expected_fields
=
%w[milestone
iteration
max_issue_count max_issue_weight assignee total_weight]
expect
(
described_class
).
to
include_graphql_fields
(
*
expected_fields
)
expect
(
described_class
).
to
include_graphql_fields
(
*
expected_fields
)
end
end
...
...
ee/spec/models/ee/list_spec.rb
View file @
edfe463a
...
@@ -88,7 +88,7 @@ RSpec.describe List do
...
@@ -88,7 +88,7 @@ RSpec.describe List do
it
{
is_expected
.
to
validate_presence_of
(
:iteration
)
}
it
{
is_expected
.
to
validate_presence_of
(
:iteration
)
}
it
'is invalid when feature is not available'
do
it
'is invalid when feature is not available'
do
stub_licensed_features
(
iteration
s:
false
)
stub_licensed_features
(
board_iteration_list
s:
false
)
expect
(
subject
).
to
be_invalid
expect
(
subject
).
to
be_invalid
expect
(
subject
.
errors
[
:list_type
])
expect
(
subject
.
errors
[
:list_type
])
...
...
ee/spec/services/ee/boards/issues/list_service_spec.rb
View file @
edfe463a
...
@@ -22,6 +22,7 @@ RSpec.describe Boards::Issues::ListService, services: true do
...
@@ -22,6 +22,7 @@ RSpec.describe Boards::Issues::ListService, services: true do
let_it_be
(
:p3
)
{
create
(
:group_label
,
title:
'P3'
,
group:
group
)
}
let_it_be
(
:p3
)
{
create
(
:group_label
,
title:
'P3'
,
group:
group
)
}
let_it_be
(
:milestone
)
{
create
(
:milestone
,
group:
group
)
}
let_it_be
(
:milestone
)
{
create
(
:milestone
,
group:
group
)
}
let_it_be
(
:iteration
)
{
create
(
:iteration
,
group:
group
)
}
let_it_be
(
:opened_issue1
)
{
create
(
:labeled_issue
,
project:
project
,
milestone:
m1
,
weight:
9
,
title:
'Issue 1'
,
labels:
[
bug
])
}
let_it_be
(
:opened_issue1
)
{
create
(
:labeled_issue
,
project:
project
,
milestone:
m1
,
weight:
9
,
title:
'Issue 1'
,
labels:
[
bug
])
}
let_it_be
(
:opened_issue2
)
{
create
(
:labeled_issue
,
project:
project
,
milestone:
m2
,
weight:
1
,
title:
'Issue 2'
,
labels:
[
p2
])
}
let_it_be
(
:opened_issue2
)
{
create
(
:labeled_issue
,
project:
project
,
milestone:
m2
,
weight:
1
,
title:
'Issue 2'
,
labels:
[
p2
])
}
...
@@ -42,15 +43,16 @@ RSpec.describe Boards::Issues::ListService, services: true do
...
@@ -42,15 +43,16 @@ RSpec.describe Boards::Issues::ListService, services: true do
let
(
:parent
)
{
group
}
let
(
:parent
)
{
group
}
before
do
before
do
stub_licensed_features
(
board_assignee_lists:
true
,
board_milestone_lists:
true
)
stub_licensed_features
(
board_assignee_lists:
true
,
board_milestone_lists:
true
,
board_iteration_lists:
true
)
parent
.
add_developer
(
user
)
parent
.
add_developer
(
user
)
opened_issue3
.
assignees
.
push
(
user_list
.
user
)
opened_issue3
.
assignees
.
push
(
user_list
.
user
)
end
end
context
'with assignee, milestone and label lists present'
do
context
'with assignee, milestone
, iteration
and label lists present'
do
let!
(
:user_list
)
{
create
(
:user_list
,
board:
board
,
position:
2
)
}
let!
(
:user_list
)
{
create
(
:user_list
,
board:
board
,
position:
2
)
}
let!
(
:milestone_list
)
{
create
(
:milestone_list
,
board:
board
,
position:
3
,
milestone:
milestone
)
}
let!
(
:milestone_list
)
{
create
(
:milestone_list
,
board:
board
,
position:
3
,
milestone:
milestone
)
}
let!
(
:iteration_list
)
{
create
(
:iteration_list
,
board:
board
,
position:
4
,
iteration:
iteration
)
}
let!
(
:backlog
)
{
create
(
:backlog_list
,
board:
board
)
}
let!
(
:backlog
)
{
create
(
:backlog_list
,
board:
board
)
}
let!
(
:list1
)
{
create
(
:list
,
board:
board
,
label:
development
,
position:
0
)
}
let!
(
:list1
)
{
create
(
:list
,
board:
board
,
label:
development
,
position:
0
)
}
let!
(
:list2
)
{
create
(
:list
,
board:
board
,
label:
testing
,
position:
1
)
}
let!
(
:list2
)
{
create
(
:list
,
board:
board
,
label:
testing
,
position:
1
)
}
...
@@ -80,6 +82,46 @@ RSpec.describe Boards::Issues::ListService, services: true do
...
@@ -80,6 +82,46 @@ RSpec.describe Boards::Issues::ListService, services: true do
end
end
end
end
context
'iteration lists'
do
let!
(
:iteration_issue
)
{
create
(
:labeled_issue
,
project:
project
,
iteration:
iteration
,
labels:
[
p3
])
}
let
(
:params
)
{
{
board_id:
board
.
id
,
id:
iteration_list
.
id
}
}
subject
(
:issues
)
{
described_class
.
new
(
parent
.
class
.
find
(
parent
.
id
),
user
,
params
).
execute
}
it
'returns issues from iteration persisted in the list'
do
expect
(
issues
).
to
contain_exactly
(
iteration_issue
)
end
context
'backlog list'
do
let
(
:params
)
{
{
board_id:
board
.
id
,
id:
backlog
.
id
}
}
it
'excludes issues in the iteration list'
do
expect
(
issues
).
not_to
include
(
iteration_issue
)
end
context
'when feature is disabled'
do
before
do
stub_licensed_features
(
board_iteration_lists:
false
)
end
it
'includes issues in the iteration list'
do
expect
(
issues
).
to
include
(
iteration_issue
)
end
end
context
'when feature flag is disabled'
do
before
do
stub_feature_flags
(
iteration_board_lists:
false
)
end
it
'includes issues in the iteration list'
do
expect
(
issues
).
to
include
(
iteration_issue
)
end
end
end
end
describe
'#metadata'
do
describe
'#metadata'
do
it
'returns issues count and weight for list'
do
it
'returns issues count and weight for list'
do
params
=
{
board_id:
board
.
id
,
id:
backlog
.
id
}
params
=
{
board_id:
board
.
id
,
id:
backlog
.
id
}
...
...
ee/spec/services/ee/boards/issues/move_service_spec.rb
View file @
edfe463a
...
@@ -103,6 +103,87 @@ RSpec.describe Boards::Issues::MoveService, services: true do
...
@@ -103,6 +103,87 @@ RSpec.describe Boards::Issues::MoveService, services: true do
end
end
end
end
shared_examples
'moving an issue to/from iteration lists'
do
context
'from backlog to iteration list'
do
let!
(
:issue
)
{
create
(
:issue
,
project:
project
)
}
let
(
:params
)
{
{
board_id:
board1
.
id
,
from_list_id:
backlog
.
id
,
to_list_id:
iteration_list1
.
id
}
}
it
'assigns the iteration'
do
expect
{
described_class
.
new
(
parent
,
user
,
params
).
execute
(
issue
)
}
.
to
change
{
issue
.
reload
.
iteration
}
.
from
(
nil
)
.
to
(
iteration_list1
.
iteration
)
end
context
'when feature flag is disabled'
do
before
do
stub_feature_flags
(
iteration_board_lists:
false
)
end
it
'does not assign the iteration'
do
expect
{
described_class
.
new
(
parent
,
user
,
params
).
execute
(
issue
)
}
.
not_to
change
{
issue
.
reload
.
iteration
}
end
end
end
context
'from iteration to backlog list'
do
let!
(
:issue
)
{
create
(
:issue
,
project:
project
,
iteration:
iteration_list1
.
iteration
)
}
it
'removes the iteration'
do
params
=
{
board_id:
board1
.
id
,
from_list_id:
iteration_list1
.
id
,
to_list_id:
backlog
.
id
}
expect
{
described_class
.
new
(
parent
,
user
,
params
).
execute
(
issue
)
}
.
to
change
{
issue
.
reload
.
iteration
}
.
from
(
iteration_list1
.
iteration
)
.
to
(
nil
)
end
end
context
'from label to iteration list'
do
let
(
:issue
)
{
create
(
:labeled_issue
,
project:
project
,
labels:
[
bug
,
development
])
}
it
'assigns the iteration and keeps labels'
do
params
=
{
board_id:
board1
.
id
,
from_list_id:
label_list1
.
id
,
to_list_id:
iteration_list1
.
id
}
expect
{
described_class
.
new
(
parent
,
user
,
params
).
execute
(
issue
)
}
.
to
change
{
issue
.
reload
.
iteration
}
.
from
(
nil
)
.
to
(
iteration_list1
.
iteration
)
expect
(
issue
.
labels
).
to
contain_exactly
(
bug
,
development
)
end
end
context
'from iteration to label list'
do
let!
(
:issue
)
do
create
(
:labeled_issue
,
project:
project
,
iteration:
iteration_list1
.
iteration
,
labels:
[
bug
,
development
])
end
it
'adds labels and keeps iteration'
do
params
=
{
board_id:
board1
.
id
,
from_list_id:
iteration_list1
.
id
,
to_list_id:
label_list2
.
id
}
expect
{
described_class
.
new
(
parent
,
user
,
params
).
execute
(
issue
)
}
.
not_to
change
{
issue
.
reload
.
iteration
}
expect
(
issue
.
labels
).
to
contain_exactly
(
bug
,
development
,
testing
)
end
end
context
'between iteration lists'
do
let!
(
:issue
)
{
create
(
:issue
,
project:
project
,
iteration:
iteration_list1
.
iteration
)
}
it
'replaces previous list iteration to targeting list iteration'
do
params
=
{
board_id:
board1
.
id
,
from_list_id:
iteration_list1
.
id
,
to_list_id:
iteration_list2
.
id
}
expect
{
described_class
.
new
(
parent
,
user
,
params
).
execute
(
issue
)
}
.
to
change
{
issue
.
reload
.
iteration
}
.
from
(
iteration_list1
.
iteration
)
.
to
(
iteration_list2
.
iteration
)
end
end
end
shared_examples
'moving an issue to/from assignee lists'
do
shared_examples
'moving an issue to/from assignee lists'
do
let
(
:issue
)
{
create
(
:labeled_issue
,
project:
project
,
labels:
[
bug
,
development
],
milestone:
milestone1
)
}
let
(
:issue
)
{
create
(
:labeled_issue
,
project:
project
,
labels:
[
bug
,
development
],
milestone:
milestone1
)
}
let
(
:params
)
{
{
board_id:
board1
.
id
,
from_list_id:
label_list1
.
id
,
to_list_id:
label_list2
.
id
}
}
let
(
:params
)
{
{
board_id:
board1
.
id
,
from_list_id:
label_list1
.
id
,
to_list_id:
label_list2
.
id
}
}
...
@@ -193,15 +274,20 @@ RSpec.describe Boards::Issues::MoveService, services: true do
...
@@ -193,15 +274,20 @@ RSpec.describe Boards::Issues::MoveService, services: true do
let
(
:user_list2
)
{
create
(
:user_list
,
board:
board1
,
user:
user
,
position:
3
)
}
let
(
:user_list2
)
{
create
(
:user_list
,
board:
board1
,
user:
user
,
position:
3
)
}
let
(
:milestone_list1
)
{
create
(
:milestone_list
,
board:
board1
,
milestone:
milestone1
,
position:
4
)
}
let
(
:milestone_list1
)
{
create
(
:milestone_list
,
board:
board1
,
milestone:
milestone1
,
position:
4
)
}
let
(
:milestone_list2
)
{
create
(
:milestone_list
,
board:
board1
,
milestone:
milestone2
,
position:
5
)
}
let
(
:milestone_list2
)
{
create
(
:milestone_list
,
board:
board1
,
milestone:
milestone2
,
position:
5
)
}
let
(
:iteration_list1
)
{
create
(
:iteration_list
,
board:
board1
,
iteration:
iteration1
,
position:
6
)
}
let
(
:iteration_list2
)
{
create
(
:iteration_list
,
board:
board1
,
iteration:
iteration2
,
position:
7
)
}
let
(
:closed
)
{
create
(
:closed_list
,
board:
board1
)
}
let
(
:closed
)
{
create
(
:closed_list
,
board:
board1
)
}
let
(
:backlog
)
{
create
(
:backlog_list
,
board:
board1
)
}
let
(
:backlog
)
{
create
(
:backlog_list
,
board:
board1
)
}
context
'when parent is a project'
do
context
'when parent is a project'
do
let
(
:project
)
{
create
(
:project
)
}
let
(
:group
)
{
create
(
:group
)
}
let
(
:project
)
{
create
(
:project
,
namespace:
group
)
}
let
(
:parent_attr
)
{
{
project:
project
}
}
let
(
:parent_attr
)
{
{
project:
project
}
}
let
(
:parent
)
{
project
}
let
(
:parent
)
{
project
}
let
(
:milestone1
)
{
create
(
:milestone
,
project:
project
)
}
let
(
:milestone1
)
{
create
(
:milestone
,
project:
project
)
}
let
(
:milestone2
)
{
create
(
:milestone
,
project:
project
)
}
let
(
:milestone2
)
{
create
(
:milestone
,
project:
project
)
}
let
(
:iteration1
)
{
create
(
:iteration
,
group:
group
)
}
let
(
:iteration2
)
{
create
(
:iteration
,
group:
group
)
}
let
(
:bug
)
{
create
(
:label
,
project:
project
,
name:
'Bug'
)
}
let
(
:bug
)
{
create
(
:label
,
project:
project
,
name:
'Bug'
)
}
let
(
:development
)
{
create
(
:label
,
project:
project
,
name:
'Development'
)
}
let
(
:development
)
{
create
(
:label
,
project:
project
,
name:
'Development'
)
}
...
@@ -209,13 +295,14 @@ RSpec.describe Boards::Issues::MoveService, services: true do
...
@@ -209,13 +295,14 @@ RSpec.describe Boards::Issues::MoveService, services: true do
let
(
:regression
)
{
create
(
:label
,
project:
project
,
name:
'Regression'
)
}
let
(
:regression
)
{
create
(
:label
,
project:
project
,
name:
'Regression'
)
}
before
do
before
do
stub_licensed_features
(
board_assignee_lists:
true
,
board_milestone_lists:
true
)
stub_licensed_features
(
board_assignee_lists:
true
,
board_milestone_lists:
true
,
board_iteration_lists:
true
)
parent
.
add_developer
(
user
)
parent
.
add_developer
(
user
)
parent
.
add_developer
(
user_list1
.
user
)
parent
.
add_developer
(
user_list1
.
user
)
end
end
it_behaves_like
'moving an issue to/from assignee lists'
it_behaves_like
'moving an issue to/from assignee lists'
it_behaves_like
'moving an issue to/from milestone lists'
it_behaves_like
'moving an issue to/from milestone lists'
it_behaves_like
'moving an issue to/from iteration lists'
end
end
context
'when parent is a group'
do
context
'when parent is a group'
do
...
@@ -225,6 +312,8 @@ RSpec.describe Boards::Issues::MoveService, services: true do
...
@@ -225,6 +312,8 @@ RSpec.describe Boards::Issues::MoveService, services: true do
let
(
:parent
)
{
group
}
let
(
:parent
)
{
group
}
let
(
:milestone1
)
{
create
(
:milestone
,
group:
group
)
}
let
(
:milestone1
)
{
create
(
:milestone
,
group:
group
)
}
let
(
:milestone2
)
{
create
(
:milestone
,
group:
group
)
}
let
(
:milestone2
)
{
create
(
:milestone
,
group:
group
)
}
let
(
:iteration1
)
{
create
(
:iteration
,
group:
group
)
}
let
(
:iteration2
)
{
create
(
:iteration
,
group:
group
)
}
let
(
:bug
)
{
create
(
:group_label
,
group:
group
,
name:
'Bug'
)
}
let
(
:bug
)
{
create
(
:group_label
,
group:
group
,
name:
'Bug'
)
}
let
(
:development
)
{
create
(
:group_label
,
group:
group
,
name:
'Development'
)
}
let
(
:development
)
{
create
(
:group_label
,
group:
group
,
name:
'Development'
)
}
...
@@ -239,6 +328,7 @@ RSpec.describe Boards::Issues::MoveService, services: true do
...
@@ -239,6 +328,7 @@ RSpec.describe Boards::Issues::MoveService, services: true do
it_behaves_like
'moving an issue to/from assignee lists'
it_behaves_like
'moving an issue to/from assignee lists'
it_behaves_like
'moving an issue to/from milestone lists'
it_behaves_like
'moving an issue to/from milestone lists'
it_behaves_like
'moving an issue to/from iteration lists'
context
'when moving to same list'
do
context
'when moving to same list'
do
let
(
:subgroup
)
{
create
(
:group
,
parent:
group
)
}
let
(
:subgroup
)
{
create
(
:group
,
parent:
group
)
}
...
...
ee/spec/services/ee/boards/lists/create_service_spec.rb
View file @
edfe463a
...
@@ -62,7 +62,7 @@ RSpec.describe Boards::Lists::CreateService do
...
@@ -62,7 +62,7 @@ RSpec.describe Boards::Lists::CreateService do
subject
(
:service
)
{
described_class
.
new
(
project
,
user
,
'iteration_id'
=>
iteration
.
id
)
}
subject
(
:service
)
{
described_class
.
new
(
project
,
user
,
'iteration_id'
=>
iteration
.
id
)
}
before
do
before
do
stub_licensed_features
(
iteration
s:
true
)
stub_licensed_features
(
board_iteration_list
s:
true
)
end
end
it
'creates an iteration list when param is valid'
do
it
'creates an iteration list when param is valid'
do
...
@@ -93,7 +93,7 @@ RSpec.describe Boards::Lists::CreateService do
...
@@ -93,7 +93,7 @@ RSpec.describe Boards::Lists::CreateService do
end
end
it
'returns an error when license is unavailable'
do
it
'returns an error when license is unavailable'
do
stub_licensed_features
(
iteration
s:
false
)
stub_licensed_features
(
board_iteration_list
s:
false
)
response
=
service
.
execute
(
board
)
response
=
service
.
execute
(
board
)
...
...
ee/spec/services/ee/boards/lists/list_service_spec.rb
View file @
edfe463a
...
@@ -4,6 +4,14 @@ require 'spec_helper'
...
@@ -4,6 +4,14 @@ require 'spec_helper'
RSpec
.
describe
Boards
::
Lists
::
ListService
do
RSpec
.
describe
Boards
::
Lists
::
ListService
do
describe
'#execute'
do
describe
'#execute'
do
before
do
stub_licensed_features
(
board_assignee_lists:
false
,
board_milestone_lists:
false
,
board_iteration_lists:
false
)
end
def
execute_service
service
.
execute
(
Board
.
find
(
board
.
id
))
end
shared_examples
'list service for board with assignee lists'
do
shared_examples
'list service for board with assignee lists'
do
let!
(
:assignee_list
)
{
build
(
:user_list
,
board:
board
).
tap
{
|
l
|
l
.
save
(
validate:
false
)
}
}
let!
(
:assignee_list
)
{
build
(
:user_list
,
board:
board
).
tap
{
|
l
|
l
.
save
(
validate:
false
)
}
}
let!
(
:backlog_list
)
{
create
(
:backlog_list
,
board:
board
)
}
let!
(
:backlog_list
)
{
create
(
:backlog_list
,
board:
board
)
}
...
@@ -11,18 +19,17 @@ RSpec.describe Boards::Lists::ListService do
...
@@ -11,18 +19,17 @@ RSpec.describe Boards::Lists::ListService do
context
'when the feature is enabled'
do
context
'when the feature is enabled'
do
before
do
before
do
allow
(
board
.
resource_parent
).
to
receive
(
:feature_available?
).
with
(
:board_assignee_lists
).
and_return
(
true
)
stub_licensed_features
(
board_assignee_lists:
true
)
allow
(
board
.
resource_parent
).
to
receive
(
:feature_available?
).
with
(
:board_milestone_lists
).
and_return
(
false
)
end
end
it
'returns all lists'
do
it
'returns all lists'
do
expect
(
service
.
execute
(
board
)
).
to
match_array
[
backlog_list
,
list
,
assignee_list
,
board
.
closed_list
]
expect
(
execute_service
).
to
match_array
[
backlog_list
,
list
,
assignee_list
,
board
.
closed_list
]
end
end
end
end
context
'when the feature is disabled'
do
context
'when the feature is disabled'
do
it
'filters out assignee lists that might have been created while subscribed'
do
it
'filters out assignee lists that might have been created while subscribed'
do
expect
(
service
.
execute
(
board
)
).
to
match_array
[
backlog_list
,
list
,
board
.
closed_list
]
expect
(
execute_service
).
to
match_array
[
backlog_list
,
list
,
board
.
closed_list
]
end
end
end
end
end
end
...
@@ -34,19 +41,51 @@ RSpec.describe Boards::Lists::ListService do
...
@@ -34,19 +41,51 @@ RSpec.describe Boards::Lists::ListService do
context
'when the feature is enabled'
do
context
'when the feature is enabled'
do
before
do
before
do
allow
(
board
.
resource_parent
).
to
receive
(
:feature_available?
).
with
(
:board_assignee_lists
).
and_return
(
false
)
stub_licensed_features
(
board_milestone_lists:
true
)
allow
(
board
.
resource_parent
).
to
receive
(
:feature_available?
).
with
(
:board_milestone_lists
).
and_return
(
true
)
end
end
it
'returns all lists'
do
it
'returns all lists'
do
expect
(
service
.
execute
(
board
)
)
expect
(
execute_service
)
.
to
match_array
([
backlog_list
,
list
,
milestone_list
,
board
.
closed_list
])
.
to
match_array
([
backlog_list
,
list
,
milestone_list
,
board
.
closed_list
])
end
end
end
end
context
'when the feature is disabled'
do
context
'when the feature is disabled'
do
it
'filters out assignee lists that might have been created while subscribed'
do
it
'filters out assignee lists that might have been created while subscribed'
do
expect
(
service
.
execute
(
board
)).
to
match_array
[
backlog_list
,
list
,
board
.
closed_list
]
expect
(
execute_service
).
to
match_array
[
backlog_list
,
list
,
board
.
closed_list
]
end
end
end
shared_examples
'list service for board with iteration lists'
do
let!
(
:iteration_list
)
{
build
(
:iteration_list
,
board:
board
).
tap
{
|
l
|
l
.
save
(
validate:
false
)
}
}
let!
(
:backlog_list
)
{
create
(
:backlog_list
,
board:
board
)
}
let!
(
:list
)
{
create
(
:list
,
board:
board
,
label:
label
)
}
context
'when the feature is enabled'
do
before
do
stub_licensed_features
(
board_iteration_lists:
true
)
end
it
'returns all lists'
do
expect
(
execute_service
)
.
to
match_array
([
backlog_list
,
list
,
iteration_list
,
board
.
closed_list
])
end
context
'when the feature flag is disabled'
do
before
do
stub_feature_flags
(
iteration_board_lists:
false
)
end
it
'filters out iteration lists that might have been created while subscribed'
do
expect
(
execute_service
).
to
match_array
[
backlog_list
,
list
,
board
.
closed_list
]
end
end
end
context
'when feature is disabled'
do
it
'filters out iteration lists that might have been created while subscribed'
do
expect
(
execute_service
).
to
match_array
[
backlog_list
,
list
,
board
.
closed_list
]
end
end
end
end
end
end
...
@@ -58,7 +97,7 @@ RSpec.describe Boards::Lists::ListService do
...
@@ -58,7 +97,7 @@ RSpec.describe Boards::Lists::ListService do
it
'hides backlog list'
do
it
'hides backlog list'
do
board
.
update
(
hide_backlog_list:
true
)
board
.
update
(
hide_backlog_list:
true
)
expect
(
service
.
execute
(
board
)
).
to
match_array
([
board
.
closed_list
,
list
])
expect
(
execute_service
).
to
match_array
([
board
.
closed_list
,
list
])
end
end
end
end
...
@@ -66,7 +105,7 @@ RSpec.describe Boards::Lists::ListService do
...
@@ -66,7 +105,7 @@ RSpec.describe Boards::Lists::ListService do
it
'hides closed list'
do
it
'hides closed list'
do
board
.
update
(
hide_closed_list:
true
)
board
.
update
(
hide_closed_list:
true
)
expect
(
service
.
execute
(
board
)
).
to
match_array
([
board
.
backlog_list
,
list
])
expect
(
execute_service
).
to
match_array
([
board
.
backlog_list
,
list
])
end
end
end
end
end
end
...
@@ -80,6 +119,7 @@ RSpec.describe Boards::Lists::ListService do
...
@@ -80,6 +119,7 @@ RSpec.describe Boards::Lists::ListService do
it_behaves_like
'list service for board with assignee lists'
it_behaves_like
'list service for board with assignee lists'
it_behaves_like
'list service for board with milestone lists'
it_behaves_like
'list service for board with milestone lists'
it_behaves_like
'list service for board with iteration lists'
it_behaves_like
'hidden lists'
it_behaves_like
'hidden lists'
end
end
...
@@ -92,6 +132,7 @@ RSpec.describe Boards::Lists::ListService do
...
@@ -92,6 +132,7 @@ RSpec.describe Boards::Lists::ListService do
it_behaves_like
'list service for board with assignee lists'
it_behaves_like
'list service for board with assignee lists'
it_behaves_like
'list service for board with milestone lists'
it_behaves_like
'list service for board with milestone lists'
it_behaves_like
'list service for board with iteration lists'
it_behaves_like
'hidden lists'
it_behaves_like
'hidden lists'
end
end
end
end
...
...
ee/spec/support/shared_examples/requests/api/iteration_board_list_shared_examples.rb
View file @
edfe463a
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
RSpec
.
shared_examples
'iteration board list'
do
RSpec
.
shared_examples
'iteration board list'
do
before
do
before
do
stub_licensed_features
(
iteration
s:
true
)
stub_licensed_features
(
board_iteration_list
s:
true
)
end
end
context
'when iteration_id is sent'
do
context
'when iteration_id is sent'
do
...
@@ -24,7 +24,7 @@ RSpec.shared_examples 'iteration board list' do
...
@@ -24,7 +24,7 @@ RSpec.shared_examples 'iteration board list' do
end
end
it
'returns 400 if not licensed'
do
it
'returns 400 if not licensed'
do
stub_licensed_features
(
iteration
s:
false
)
stub_licensed_features
(
board_iteration_list
s:
false
)
post
api
(
url
,
user
),
params:
{
iteration_id:
iteration
.
id
}
post
api
(
url
,
user
),
params:
{
iteration_id:
iteration
.
id
}
...
...
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