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
00a5db6a
Commit
00a5db6a
authored
Oct 28, 2020
by
charlie ablett
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Expose blocked_by_count in issues in GraphQL
- Add changelog and docs
parent
2329d705
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
103 additions
and
21 deletions
+103
-21
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+10
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+28
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+2
-0
ee/app/graphql/ee/types/issue_type.rb
ee/app/graphql/ee/types/issue_type.rb
+11
-1
ee/changelogs/unreleased/cablett-258965-blocked-issue-count.yml
...ngelogs/unreleased/cablett-258965-blocked-issue-count.yml
+5
-0
ee/lib/gitlab/graphql/aggregations/issues/lazy_block_aggregate.rb
...itlab/graphql/aggregations/issues/lazy_block_aggregate.rb
+10
-5
ee/spec/graphql/types/issue_type_spec.rb
ee/spec/graphql/types/issue_type_spec.rb
+1
-0
ee/spec/lib/gitlab/graphql/aggregations/issues/lazy_block_aggregate_spec.rb
.../graphql/aggregations/issues/lazy_block_aggregate_spec.rb
+21
-5
ee/spec/requests/api/graphql/project/issues_spec.rb
ee/spec/requests/api/graphql/project/issues_spec.rb
+15
-10
No files found.
doc/api/graphql/reference/gitlab_schema.graphql
View file @
00a5db6a
...
...
@@ -6909,6 +6909,11 @@ type EpicIssue implements CurrentUserTodos & Noteable {
"""
blocked
:
Boolean
!
"""
Count
of
issues
blocking
this
issue
"""
blockedByCount
:
Int
"""
Timestamp
of
when
the
issue
was
closed
"""
...
...
@@ -9172,6 +9177,11 @@ type Issue implements CurrentUserTodos & Noteable {
"""
blocked
:
Boolean
!
"""
Count
of
issues
blocking
this
issue
"""
blockedByCount
:
Int
"""
Timestamp
of
when
the
issue
was
closed
"""
...
...
doc/api/graphql/reference/gitlab_schema.json
View file @
00a5db6a
...
...
@@ -19037,6 +19037,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "blockedByCount",
"description": "Count of issues blocking this issue",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "closedAt",
"description": "Timestamp of when the issue was closed",
...
...
@@ -24965,6 +24979,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "blockedByCount",
"description": "Count of issues blocking this issue",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "closedAt",
"description": "Timestamp of when the issue was closed",
doc/api/graphql/reference/index.md
View file @
00a5db6a
...
...
@@ -1115,6 +1115,7 @@ Relationship between an epic and an issue.
|
`alertManagementAlert`
| AlertManagementAlert | Alert associated to this issue |
|
`author`
| User! | User that created the issue |
|
`blocked`
| Boolean! | Indicates the issue is blocked |
|
`blockedByCount`
| Int | Count of issues blocking this issue |
|
`closedAt`
| Time | Timestamp of when the issue was closed |
|
`confidential`
| Boolean! | Indicates the issue is confidential |
|
`createdAt`
| Time! | Timestamp of when the issue was created |
...
...
@@ -1310,6 +1311,7 @@ Represents a recorded measurement (object count) for the Admins.
|
`alertManagementAlert`
| AlertManagementAlert | Alert associated to this issue |
|
`author`
| User! | User that created the issue |
|
`blocked`
| Boolean! | Indicates the issue is blocked |
|
`blockedByCount`
| Int | Count of issues blocking this issue |
|
`closedAt`
| Time | Timestamp of when the issue was closed |
|
`confidential`
| Boolean! | Indicates the issue is confidential |
|
`createdAt`
| Time! | Timestamp of when the issue was created |
...
...
ee/app/graphql/ee/types/issue_type.rb
View file @
00a5db6a
...
...
@@ -20,7 +20,17 @@ module EE
field
:blocked
,
GraphQL
::
BOOLEAN_TYPE
,
null:
false
,
description:
'Indicates the issue is blocked'
,
resolve:
->
(
obj
,
_args
,
ctx
)
{
::
Gitlab
::
Graphql
::
Aggregations
::
Issues
::
LazyBlockAggregate
.
new
(
ctx
,
obj
.
id
)
::
Gitlab
::
Graphql
::
Aggregations
::
Issues
::
LazyBlockAggregate
.
new
(
ctx
,
obj
.
id
)
do
|
count
|
(
count
||
0
)
>
0
end
}
field
:blocked_by_count
,
GraphQL
::
INT_TYPE
,
null:
true
,
description:
'Count of issues blocking this issue'
,
resolve:
->
(
obj
,
_args
,
ctx
)
{
::
Gitlab
::
Graphql
::
Aggregations
::
Issues
::
LazyBlockAggregate
.
new
(
ctx
,
obj
.
id
)
do
|
count
|
count
||
0
end
}
field
:health_status
,
::
Types
::
HealthStatusEnum
,
null:
true
,
...
...
ee/changelogs/unreleased/cablett-258965-blocked-issue-count.yml
0 → 100644
View file @
00a5db6a
---
title
:
Expose blocked issue count in GraphQL
merge_request
:
46303
author
:
type
:
added
ee/lib/gitlab/graphql/aggregations/issues/lazy_block_aggregate.rb
View file @
00a5db6a
...
...
@@ -7,8 +7,9 @@ module Gitlab
class
LazyBlockAggregate
attr_reader
:issue_id
,
:lazy_state
def
initialize
(
query_ctx
,
issue_id
)
def
initialize
(
query_ctx
,
issue_id
,
&
block
)
@issue_id
=
issue_id
@block
=
block
# Initialize the loading state for this query,
# or get the previously-initiated state
...
...
@@ -27,7 +28,11 @@ module Gitlab
load_records_into_loaded_objects
end
!!
@lazy_state
[
:loaded_objects
][
@issue_id
]
result
=
@lazy_state
[
:loaded_objects
][
@issue_id
]
return
@block
.
call
(
result
)
if
@block
result
end
private
...
...
@@ -36,10 +41,10 @@ module Gitlab
# The record hasn't been loaded yet, so
# hit the database with all pending IDs to prevent N+1
pending_ids
=
@lazy_state
[
:pending_ids
].
to_a
blocked
=
IssueLink
.
blocked_issues_for_collection
(
pending_ids
).
compact
.
flatten
blocked
_data
=
IssueLink
.
blocked_issues_for_collection
(
pending_ids
).
compact
.
flatten
blocked
.
each
do
|
o
|
@lazy_state
[
:loaded_objects
][
o
.
blocked_issue_id
]
=
true
blocked
_data
.
each
do
|
blocked
|
@lazy_state
[
:loaded_objects
][
blocked
.
blocked_issue_id
]
=
blocked
.
count
end
@lazy_state
[
:pending_ids
].
clear
...
...
ee/spec/graphql/types/issue_type_spec.rb
View file @
00a5db6a
...
...
@@ -8,6 +8,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
it
{
expect
(
described_class
).
to
have_graphql_field
(
:weight
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:health_status
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:blocked
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:blocked_by_count
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:sla_due_at
)
}
context
'N+1 queries'
do
...
...
ee/spec/lib/gitlab/graphql/aggregations/issues/lazy_block_aggregate_spec.rb
View file @
00a5db6a
...
...
@@ -23,18 +23,36 @@ RSpec.describe Gitlab::Graphql::Aggregations::Issues::LazyBlockAggregate do
describe
'#block_aggregate'
do
subject
{
described_class
.
new
(
query_ctx
,
issue_id
)
}
# We cannot directly stub IssueLink, otherwise we get a strange RSpec error
let
(
:issue_link
)
{
class_double
(
'IssueLink'
).
as_stubbed_const
}
let
(
:fake_state
)
do
{
pending_ids:
Set
.
new
,
loaded_objects:
{}
}
end
before
do
subject
.
instance_variable_set
(
:@lazy_state
,
fake_state
)
end
context
'when there is a block provided'
do
subject
do
described_class
.
new
(
query_ctx
,
issue_id
)
do
|
result
|
result
.
do_thing
end
end
it
'calls the block'
do
expect
(
fake_state
[
:loaded_objects
][
issue_id
]).
to
receive
(
:do_thing
)
subject
.
block_aggregate
end
end
context
'if the record has already been loaded'
do
let
(
:fake_state
)
do
{
pending_ids:
Set
.
new
,
loaded_objects:
{
issue_id
=>
true
}
}
{
pending_ids:
Set
.
new
,
loaded_objects:
{
issue_id
=>
double
(
count:
10
)
}
}
end
it
'does not make the query again'
do
# We cannot directly stub IssueLink, otherwise we get a strange RSpec error
issue_link
=
class_double
(
'IssueLink'
).
as_stubbed_const
expect
(
issue_link
).
not_to
receive
(
:blocked_issues_for_collection
)
subject
.
block_aggregate
...
...
@@ -55,8 +73,6 @@ RSpec.describe Gitlab::Graphql::Aggregations::Issues::LazyBlockAggregate do
end
before
do
# We cannot directly stub IssueLink, otherwise we get a strange RSpec error
issue_link
=
class_double
(
'IssueLink'
).
as_stubbed_const
expect
(
issue_link
).
to
receive
(
:blocked_issues_for_collection
).
and_return
(
fake_data
)
end
...
...
ee/spec/requests/api/graphql/project/issues_spec.rb
View file @
00a5db6a
...
...
@@ -56,9 +56,11 @@ RSpec.describe 'getting an issue list for a project' do
let_it_be
(
:blocking_issue1
)
{
create
(
:issue
,
project:
project
)
}
let_it_be
(
:blocked_issue2
)
{
create
(
:issue
,
project:
project
)
}
let_it_be
(
:blocking_issue2
)
{
create
(
:issue
,
:confidential
,
project:
project
)
}
let_it_be
(
:blocking_issue3
)
{
create
(
:issue
,
project:
project
)
}
let_it_be
(
:issue_link1
)
{
create
(
:issue_link
,
source:
blocked_issue1
,
target:
blocking_issue1
,
link_type:
'is_blocked_by'
)
}
let_it_be
(
:issue_link2
)
{
create
(
:issue_link
,
source:
blocking_issue2
,
target:
blocked_issue2
,
link_type:
'blocks'
)
}
let_it_be
(
:issue_link3
)
{
create
(
:issue_link
,
source:
blocking_issue3
,
target:
blocked_issue2
,
link_type:
'blocks'
)
}
let
(
:query
)
do
graphql_query_for
(
'project'
,
{
fullPath:
project
.
full_path
},
query_graphql_field
(
'issues'
,
{},
issue_links_aggregates_query
))
...
...
@@ -73,6 +75,7 @@ RSpec.describe 'getting an issue list for a project' do
nodes {
id
blocked
blockedByCount
}
QUERY
end
...
...
@@ -95,19 +98,21 @@ RSpec.describe 'getting an issue list for a project' do
post_graphql
(
single_issue_query
,
current_user:
current_user
)
end
it
'returns the correct results'
,
:aggregate_failures
do
it
'returns the correct result'
,
:aggregate_failures
do
check_result
(
blocked_issue1
,
true
,
1
)
check_result
(
blocked_issue2
,
true
,
2
)
check_result
(
blocking_issue1
,
false
,
0
)
check_result
(
blocking_issue2
,
false
,
0
)
end
def
check_result
(
issue
,
expected_blocked
,
expected_blocked_count
)
post_graphql
(
query
,
current_user:
current_user
)
result
=
graphql_data
.
dig
(
'project'
,
'issues'
,
'nodes'
)
nodes
=
graphql_data
.
dig
(
'project'
,
'issues'
,
'nodes'
)
node
=
nodes
.
find
{
|
r
|
r
[
'id'
]
==
issue
.
to_global_id
.
to_s
}
expect
(
find_result
(
result
,
blocked_issue1
)).
to
eq
true
expect
(
find_result
(
result
,
blocked_issue2
)).
to
eq
true
expect
(
find_result
(
result
,
blocking_issue1
)).
to
eq
false
expect
(
find_result
(
result
,
blocking_issue2
)).
to
eq
false
expect
(
node
[
'blocked'
]).
to
eq
expected_blocked
expect
(
node
[
'blockedByCount'
]).
to
eq
expected_blocked_count
end
end
def
find_result
(
result
,
issue
)
result
.
find
{
|
r
|
r
[
'id'
]
==
issue
.
to_global_id
.
to_s
}[
'blocked'
]
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