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
0292365e
Commit
0292365e
authored
Jun 03, 2019
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab-ce master
parents
dbf63dda
205f0d0c
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
370 additions
and
8 deletions
+370
-8
app/graphql/resolvers/namespace_projects_resolver.rb
app/graphql/resolvers/namespace_projects_resolver.rb
+33
-0
app/graphql/resolvers/namespace_resolver.rb
app/graphql/resolvers/namespace_resolver.rb
+13
-0
app/graphql/types/namespace_type.rb
app/graphql/types/namespace_type.rb
+5
-0
app/graphql/types/project_statistics_type.rb
app/graphql/types/project_statistics_type.rb
+15
-0
app/graphql/types/project_type.rb
app/graphql/types/project_type.rb
+4
-0
app/graphql/types/query_type.rb
app/graphql/types/query_type.rb
+5
-0
app/models/project_statistics.rb
app/models/project_statistics.rb
+2
-0
app/views/shared/boards/components/sidebar/_labels.html.haml
app/views/shared/boards/components/sidebar/_labels.html.haml
+1
-1
app/views/shared/issuable/_label_dropdown.html.haml
app/views/shared/issuable/_label_dropdown.html.haml
+1
-1
app/views/shared/issuable/_sidebar.html.haml
app/views/shared/issuable/_sidebar.html.haml
+1
-1
changelogs/unreleased/51022-added-extended-height-to-labels-dropdown.yml
...leased/51022-added-extended-height-to-labels-dropdown.yml
+5
-0
changelogs/unreleased/ac-graphql-stats.yml
changelogs/unreleased/ac-graphql-stats.yml
+5
-0
doc/api/graphql/index.md
doc/api/graphql/index.md
+1
-0
lib/gitlab/graphql/loaders/batch_project_statistics_loader.rb
...gitlab/graphql/loaders/batch_project_statistics_loader.rb
+23
-0
spec/graphql/resolvers/namespace_projects_resolver_spec.rb
spec/graphql/resolvers/namespace_projects_resolver_spec.rb
+69
-0
spec/graphql/types/namespace_type_spec.rb
spec/graphql/types/namespace_type_spec.rb
+2
-0
spec/graphql/types/project_statistics_type_spec.rb
spec/graphql/types/project_statistics_type_spec.rb
+10
-0
spec/graphql/types/project_type_spec.rb
spec/graphql/types/project_type_spec.rb
+2
-0
spec/graphql/types/query_type_spec.rb
spec/graphql/types/query_type_spec.rb
+11
-1
spec/lib/gitlab/graphql/loaders/batch_project_statistics_loader_spec.rb
...b/graphql/loaders/batch_project_statistics_loader_spec.rb
+18
-0
spec/models/project_statistics_spec.rb
spec/models/project_statistics_spec.rb
+14
-0
spec/requests/api/graphql/group_query_spec.rb
spec/requests/api/graphql/group_query_spec.rb
+5
-4
spec/requests/api/graphql/namespace/projects_spec.rb
spec/requests/api/graphql/namespace/projects_spec.rb
+82
-0
spec/requests/api/graphql/project/project_statistics_spec.rb
spec/requests/api/graphql/project/project_statistics_spec.rb
+43
-0
No files found.
app/graphql/resolvers/namespace_projects_resolver.rb
0 → 100644
View file @
0292365e
# frozen_string_literal: true
module
Resolvers
class
NamespaceProjectsResolver
<
BaseResolver
argument
:include_subgroups
,
GraphQL
::
BOOLEAN_TYPE
,
required:
false
,
default_value:
false
,
description:
'Include also subgroup projects'
type
Types
::
ProjectType
,
null:
true
alias_method
:namespace
,
:object
def
resolve
(
include_subgroups
:)
# The namespace could have been loaded in batch by `BatchLoader`.
# At this point we need the `id` or the `full_path` of the namespace
# to query for projects, so make sure it's loaded and not `nil` before continuing.
namespace
.
sync
if
namespace
.
respond_to?
(
:sync
)
return
Project
.
none
if
namespace
.
nil?
if
include_subgroups
namespace
.
all_projects
.
with_route
else
namespace
.
projects
.
with_route
end
end
def
self
.
resolver_complexity
(
args
,
child_complexity
:)
complexity
=
super
complexity
+
10
end
end
end
app/graphql/resolvers/namespace_resolver.rb
0 → 100644
View file @
0292365e
# frozen_string_literal: true
module
Resolvers
class
NamespaceResolver
<
BaseResolver
prepend
FullPathResolver
type
Types
::
NamespaceType
,
null:
true
def
resolve
(
full_path
:)
model_by_full_path
(
Namespace
,
full_path
)
end
end
end
app/graphql/types/namespace_type.rb
View file @
0292365e
...
...
@@ -15,5 +15,10 @@ module Types
field
:visibility
,
GraphQL
::
STRING_TYPE
,
null:
true
field
:lfs_enabled
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
,
method: :lfs_enabled?
field
:request_access_enabled
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
field
:projects
,
Types
::
ProjectType
.
connection_type
,
null:
false
,
resolver:
::
Resolvers
::
NamespaceProjectsResolver
end
end
app/graphql/types/project_statistics_type.rb
0 → 100644
View file @
0292365e
# frozen_string_literal: true
module
Types
class
ProjectStatisticsType
<
BaseObject
graphql_name
'ProjectStatistics'
field
:commit_count
,
GraphQL
::
INT_TYPE
,
null:
false
field
:storage_size
,
GraphQL
::
INT_TYPE
,
null:
false
field
:repository_size
,
GraphQL
::
INT_TYPE
,
null:
false
field
:lfs_objects_size
,
GraphQL
::
INT_TYPE
,
null:
false
field
:build_artifacts_size
,
GraphQL
::
INT_TYPE
,
null:
false
field
:packages_size
,
GraphQL
::
INT_TYPE
,
null:
false
end
end
app/graphql/types/project_type.rb
View file @
0292365e
...
...
@@ -69,6 +69,10 @@ module Types
field
:namespace
,
Types
::
NamespaceType
,
null:
false
field
:group
,
Types
::
GroupType
,
null:
true
field
:statistics
,
Types
::
ProjectStatisticsType
,
null:
false
,
resolve:
->
(
obj
,
_args
,
_ctx
)
{
Gitlab
::
Graphql
::
Loaders
::
BatchProjectStatisticsLoader
.
new
(
obj
.
id
).
find
}
field
:repository
,
Types
::
RepositoryType
,
null:
false
field
:merge_requests
,
...
...
app/graphql/types/query_type.rb
View file @
0292365e
...
...
@@ -14,6 +14,11 @@ module Types
resolver:
Resolvers
::
GroupResolver
,
description:
"Find a group"
field
:namespace
,
Types
::
NamespaceType
,
null:
true
,
resolver:
Resolvers
::
NamespaceResolver
,
description:
"Find a namespace"
field
:metadata
,
Types
::
MetadataType
,
null:
true
,
resolver:
Resolvers
::
MetadataResolver
,
...
...
app/models/project_statistics.rb
View file @
0292365e
...
...
@@ -16,6 +16,8 @@ class ProjectStatistics < ApplicationRecord
COLUMNS_TO_REFRESH
=
[
:repository_size
,
:wiki_size
,
:lfs_objects_size
,
:commit_count
].
freeze
INCREMENTABLE_COLUMNS
=
{
build_artifacts_size:
%i[storage_size]
,
packages_size:
%i[storage_size]
}.
freeze
scope
:for_project_ids
,
->
(
project_ids
)
{
where
(
project_id:
project_ids
)
}
def
total_repository_size
repository_size
+
lfs_objects_size
end
...
...
app/views/shared/boards/components/sidebar/_labels.html.haml
View file @
0292365e
...
...
@@ -32,7 +32,7 @@
%span
.dropdown-toggle-text
{{ labelDropdownTitle }}
=
icon
(
'chevron-down'
)
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
.dropdown-extended-height
=
render
partial:
"shared/issuable/label_page_default"
-
if
can?
(
current_user
,
:admin_label
,
current_board_parent
)
=
render
partial:
"shared/issuable/label_page_create"
,
locals:
{
show_add_list:
true
}
app/views/shared/issuable/_label_dropdown.html.haml
View file @
0292365e
...
...
@@ -25,7 +25,7 @@
%span
.dropdown-toggle-text
{
class:
(
"is-default"
if
apply_is_default_styles
)
}
=
multi_label_name
(
selected
,
label_name
)
=
icon
(
'chevron-down'
)
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
.dropdown-extended-height
=
render
partial:
"shared/issuable/label_page_default"
,
locals:
{
title:
dropdown_title
,
show_footer:
show_footer
,
show_create:
show_create
}
-
if
show_create
&&
project
&&
can?
(
current_user
,
:admin_label
,
project
)
=
render
partial:
"shared/issuable/label_page_create"
...
...
app/views/shared/issuable/_sidebar.html.haml
View file @
0292365e
...
...
@@ -118,7 +118,7 @@
%span
.dropdown-toggle-text
{
class:
(
"is-default"
if
selected_labels
.
empty?
)
}
=
multi_label_name
(
selected_labels
,
"Labels"
)
=
icon
(
'chevron-down'
,
'aria-hidden'
:
'true'
)
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
.dropdown-extended-height
=
render
partial:
"shared/issuable/label_page_default"
-
if
issuable_sidebar
.
dig
(
:current_user
,
:can_admin_label
)
=
render
partial:
"shared/issuable/label_page_create"
...
...
changelogs/unreleased/51022-added-extended-height-to-labels-dropdown.yml
0 → 100644
View file @
0292365e
---
title
:
"
Added
the
`.extended-height`
class
to
the
labels-dropdown"
merge_request
:
28659
author
:
Michel Engelen
type
:
other
changelogs/unreleased/ac-graphql-stats.yml
0 → 100644
View file @
0292365e
---
title
:
Add Namespace and ProjectStatistics to GraphQL API
merge_request
:
28277
author
:
type
:
added
doc/api/graphql/index.md
View file @
0292365e
...
...
@@ -47,6 +47,7 @@ A first iteration of a GraphQL API includes the following queries
1.
`project`
: Within a project it is also possible to fetch a
`mergeRequest`
by IID.
1.
`group`
: Only basic group information is currently supported.
1.
`namespace`
: Within a namespace it is also possible to fetch
`projects`
.
### Multiplex queries
...
...
lib/gitlab/graphql/loaders/batch_project_statistics_loader.rb
0 → 100644
View file @
0292365e
# frozen_string_literal: true
module
Gitlab
module
Graphql
module
Loaders
class
BatchProjectStatisticsLoader
attr_reader
:project_id
def
initialize
(
project_id
)
@project_id
=
project_id
end
def
find
BatchLoader
.
for
(
project_id
).
batch
do
|
project_ids
,
loader
|
ProjectStatistics
.
for_project_ids
(
project_ids
).
each
do
|
statistics
|
loader
.
call
(
statistics
.
project_id
,
statistics
)
end
end
end
end
end
end
end
spec/graphql/resolvers/namespace_projects_resolver_spec.rb
0 → 100644
View file @
0292365e
# frozen_string_literal: true
require
'spec_helper'
describe
Resolvers
::
NamespaceProjectsResolver
,
:nested_groups
do
include
GraphqlHelpers
let
(
:current_user
)
{
create
(
:user
)
}
context
"with a group"
do
let
(
:group
)
{
create
(
:group
)
}
let
(
:namespace
)
{
group
}
let
(
:project1
)
{
create
(
:project
,
namespace:
namespace
)
}
let
(
:project2
)
{
create
(
:project
,
namespace:
namespace
)
}
let
(
:nested_group
)
{
create
(
:group
,
parent:
group
)
}
let
(
:nested_project
)
{
create
(
:project
,
group:
nested_group
)
}
before
do
project1
.
add_developer
(
current_user
)
project2
.
add_developer
(
current_user
)
nested_project
.
add_developer
(
current_user
)
end
describe
'#resolve'
do
it
'finds all projects'
do
expect
(
resolve_projects
).
to
contain_exactly
(
project1
,
project2
)
end
it
'finds all projects including the subgroups'
do
expect
(
resolve_projects
(
include_subgroups:
true
)).
to
contain_exactly
(
project1
,
project2
,
nested_project
)
end
context
'with an user namespace'
do
let
(
:namespace
)
{
current_user
.
namespace
}
it
'finds all projects'
do
expect
(
resolve_projects
).
to
contain_exactly
(
project1
,
project2
)
end
it
'finds all projects including the subgroups'
do
expect
(
resolve_projects
(
include_subgroups:
true
)).
to
contain_exactly
(
project1
,
project2
)
end
end
end
end
context
"when passing a non existent, batch loaded namespace"
do
let
(
:namespace
)
do
BatchLoader
.
for
(
"non-existent-path"
).
batch
do
|
_fake_paths
,
loader
,
_
|
loader
.
call
(
"non-existent-path"
,
nil
)
end
end
it
"returns nil without breaking"
do
expect
(
resolve_projects
).
to
be_empty
end
end
it
'has an high complexity regardless of arguments'
do
field
=
Types
::
BaseField
.
new
(
name:
'test'
,
type:
GraphQL
::
STRING_TYPE
,
resolver_class:
described_class
,
null:
false
,
max_page_size:
100
)
expect
(
field
.
to_graphql
.
complexity
.
call
({},
{},
1
)).
to
eq
24
expect
(
field
.
to_graphql
.
complexity
.
call
({},
{
include_subgroups:
true
},
1
)).
to
eq
24
end
def
resolve_projects
(
args
=
{
include_subgroups:
false
},
context
=
{
current_user:
current_user
})
resolve
(
described_class
,
obj:
namespace
,
args:
args
,
ctx:
context
)
end
end
spec/graphql/types/namespace_type.rb
→
spec/graphql/types/namespace_type
_spec
.rb
View file @
0292365e
...
...
@@ -4,4 +4,6 @@ require 'spec_helper'
describe
GitlabSchema
.
types
[
'Namespace'
]
do
it
{
expect
(
described_class
.
graphql_name
).
to
eq
(
'Namespace'
)
}
it
{
expect
(
described_class
).
to
have_graphql_field
(
:projects
)
}
end
spec/graphql/types/project_statistics_type_spec.rb
0 → 100644
View file @
0292365e
# frozen_string_literal: true
require
'spec_helper'
describe
GitlabSchema
.
types
[
'ProjectStatistics'
]
do
it
"has all the required fields"
do
is_expected
.
to
have_graphql_fields
(
:storage_size
,
:repository_size
,
:lfs_objects_size
,
:build_artifacts_size
,
:packages_size
,
:commit_count
)
end
end
spec/graphql/types/project_type_spec.rb
View file @
0292365e
...
...
@@ -19,4 +19,6 @@ describe GitlabSchema.types['Project'] do
it
{
is_expected
.
to
have_graphql_field
(
:pipelines
)
}
it
{
is_expected
.
to
have_graphql_field
(
:repository
)
}
it
{
is_expected
.
to
have_graphql_field
(
:statistics
)
}
end
spec/graphql/types/query_type_spec.rb
View file @
0292365e
...
...
@@ -5,7 +5,17 @@ describe GitlabSchema.types['Query'] do
expect
(
described_class
.
graphql_name
).
to
eq
(
'Query'
)
end
it
{
is_expected
.
to
have_graphql_fields
(
:project
,
:group
,
:echo
,
:metadata
)
}
it
{
is_expected
.
to
have_graphql_fields
(
:project
,
:namespace
,
:group
,
:echo
,
:metadata
)
}
describe
'namespace field'
do
subject
{
described_class
.
fields
[
'namespace'
]
}
it
'finds namespaces by full path'
do
is_expected
.
to
have_graphql_arguments
(
:full_path
)
is_expected
.
to
have_graphql_type
(
Types
::
NamespaceType
)
is_expected
.
to
have_graphql_resolver
(
Resolvers
::
NamespaceResolver
)
end
end
describe
'project field'
do
subject
{
described_class
.
fields
[
'project'
]
}
...
...
spec/lib/gitlab/graphql/loaders/batch_project_statistics_loader_spec.rb
0 → 100644
View file @
0292365e
# frozen_string_literal: true
require
'spec_helper'
describe
Gitlab
::
Graphql
::
Loaders
::
BatchProjectStatisticsLoader
do
describe
'#find'
do
it
'only queries once for project statistics'
do
stats
=
create_list
(
:project_statistics
,
2
)
project1
=
stats
.
first
.
project
project2
=
stats
.
last
.
project
expect
do
described_class
.
new
(
project1
.
id
).
find
described_class
.
new
(
project2
.
id
).
find
end
.
not_to
exceed_query_limit
(
1
)
end
end
end
spec/models/project_statistics_spec.rb
View file @
0292365e
...
...
@@ -11,6 +11,20 @@ describe ProjectStatistics do
it
{
is_expected
.
to
belong_to
(
:namespace
)
}
end
describe
'scopes'
do
describe
'.for_project_ids'
do
it
'returns only requested projects'
do
stats
=
create_list
(
:project_statistics
,
3
)
project_ids
=
stats
[
0
..
1
].
map
{
|
s
|
s
.
project_id
}
expected_ids
=
stats
[
0
..
1
].
map
{
|
s
|
s
.
id
}
requested_stats
=
described_class
.
for_project_ids
(
project_ids
).
pluck
(
:id
)
expect
(
requested_stats
).
to
eq
(
expected_ids
)
end
end
end
describe
'statistics columns'
do
it
"support values up to 8 exabytes"
do
statistics
.
update!
(
...
...
spec/requests/api/graphql/group_query_spec.rb
View file @
0292365e
...
...
@@ -86,17 +86,18 @@ describe 'getting group information' do
end
it
'avoids N+1 queries'
do
post_graphql
(
group_query
(
group1
),
current_user:
admin
)
control_count
=
ActiveRecord
::
QueryRecorder
.
new
do
post_graphql
(
group_query
(
group1
),
current_user:
admin
)
end
.
count
create
(
:project
,
namespace:
group1
)
queries
=
[{
query:
group_query
(
group1
)
},
{
query:
group_query
(
group2
)
}]
expect
do
post_
graphql
(
group_query
(
group1
)
,
current_user:
admin
)
post_
multiplex
(
queries
,
current_user:
admin
)
end
.
not_to
exceed_query_limit
(
control_count
)
expect
(
graphql_errors
).
to
contain_exactly
(
nil
,
nil
)
end
end
...
...
spec/requests/api/graphql/namespace/projects_spec.rb
0 → 100644
View file @
0292365e
# frozen_string_literal: true
require
'spec_helper'
describe
'getting projects'
,
:nested_groups
do
include
GraphqlHelpers
let
(
:group
)
{
create
(
:group
)
}
let!
(
:project
)
{
create
(
:project
,
namespace:
subject
)
}
let
(
:nested_group
)
{
create
(
:group
,
parent:
group
)
}
let!
(
:nested_project
)
{
create
(
:project
,
group:
nested_group
)
}
let!
(
:public_project
)
{
create
(
:project
,
:public
,
namespace:
subject
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:include_subgroups
)
{
true
}
subject
{
group
}
let
(
:query
)
do
graphql_query_for
(
'namespace'
,
{
'fullPath'
=>
subject
.
full_path
},
<<~
QUERY
projects(includeSubgroups:
#{
include_subgroups
}
) {
edges {
node {
#{
all_graphql_fields_for
(
'Project'
)
}
}
}
}
QUERY
)
end
before
do
group
.
add_owner
(
user
)
end
shared_examples
'a graphql namespace'
do
it_behaves_like
'a working graphql query'
do
before
do
post_graphql
(
query
,
current_user:
user
)
end
end
it
"includes the packages size if the user can read the statistics"
do
post_graphql
(
query
,
current_user:
user
)
count
=
if
include_subgroups
subject
.
all_projects
.
count
else
subject
.
projects
.
count
end
expect
(
graphql_data
[
'namespace'
][
'projects'
][
'edges'
].
size
).
to
eq
(
count
)
end
context
'with no user'
do
it
'finds only public projects'
do
post_graphql
(
query
,
current_user:
nil
)
expect
(
graphql_data
[
'namespace'
][
'projects'
][
'edges'
].
size
).
to
eq
(
1
)
project
=
graphql_data
[
'namespace'
][
'projects'
][
'edges'
][
0
][
'node'
]
expect
(
project
[
'id'
]).
to
eq
(
public_project
.
id
.
to_s
)
end
end
end
it_behaves_like
'a graphql namespace'
context
'when the namespace is a user'
do
subject
{
user
.
namespace
}
let
(
:include_subgroups
)
{
false
}
it_behaves_like
'a graphql namespace'
end
context
'when not including subgroups'
do
let
(
:include_subgroups
)
{
false
}
it_behaves_like
'a graphql namespace'
end
end
spec/requests/api/graphql/project/project_statistics_spec.rb
0 → 100644
View file @
0292365e
# frozen_string_literal: true
require
'spec_helper'
describe
'rendering namespace statistics'
do
include
GraphqlHelpers
let
(
:project
)
{
create
(
:project
)
}
let!
(
:project_statistics
)
{
create
(
:project_statistics
,
project:
project
,
packages_size:
5
.
megabytes
)
}
let
(
:user
)
{
create
(
:user
)
}
let
(
:query
)
do
graphql_query_for
(
'project'
,
{
'fullPath'
=>
project
.
full_path
},
"statistics {
#{
all_graphql_fields_for
(
'ProjectStatistics'
)
}
}"
)
end
before
do
project
.
add_reporter
(
user
)
end
it_behaves_like
'a working graphql query'
do
before
do
post_graphql
(
query
,
current_user:
user
)
end
end
it
"includes the packages size if the user can read the statistics"
do
post_graphql
(
query
,
current_user:
user
)
expect
(
graphql_data
[
'project'
][
'statistics'
][
'packagesSize'
]).
to
eq
(
5
.
megabytes
)
end
context
'when the project is public'
do
let
(
:project
)
{
create
(
:project
,
:public
)
}
it
'includes the statistics regardless of the user'
do
post_graphql
(
query
,
current_user:
nil
)
expect
(
graphql_data
[
'project'
][
'statistics'
]).
to
be_present
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment