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
0
Merge Requests
0
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
Boxiang Sun
gitlab-ce
Commits
f5c7c3b9
Commit
f5c7c3b9
authored
Apr 17, 2019
by
Brett Walker
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Basic GraphQL for a group
Add new query for Groups, with new GroupType and NamespaceType
parent
951ffd9d
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
296 additions
and
4 deletions
+296
-4
app/graphql/resolvers/full_path_resolver.rb
app/graphql/resolvers/full_path_resolver.rb
+3
-3
app/graphql/resolvers/group_resolver.rb
app/graphql/resolvers/group_resolver.rb
+13
-0
app/graphql/types/group_type.rb
app/graphql/types/group_type.rb
+21
-0
app/graphql/types/namespace_type.rb
app/graphql/types/namespace_type.rb
+19
-0
app/graphql/types/permission_types/group.rb
app/graphql/types/permission_types/group.rb
+11
-0
app/graphql/types/project_type.rb
app/graphql/types/project_type.rb
+3
-0
app/graphql/types/query_type.rb
app/graphql/types/query_type.rb
+5
-0
changelogs/unreleased/bw-add-graphql-groups.yml
changelogs/unreleased/bw-add-graphql-groups.yml
+5
-0
spec/graphql/types/group_type_spec.rb
spec/graphql/types/group_type_spec.rb
+11
-0
spec/graphql/types/namespace_type.rb
spec/graphql/types/namespace_type.rb
+7
-0
spec/graphql/types/query_type_spec.rb
spec/graphql/types/query_type_spec.rb
+1
-1
spec/requests/api/graphql/group_query_spec.rb
spec/requests/api/graphql/group_query_spec.rb
+197
-0
No files found.
app/graphql/resolvers/full_path_resolver.rb
View file @
f5c7c3b9
...
@@ -7,14 +7,14 @@ module Resolvers
...
@@ -7,14 +7,14 @@ module Resolvers
prepended
do
prepended
do
argument
:full_path
,
GraphQL
::
ID_TYPE
,
argument
:full_path
,
GraphQL
::
ID_TYPE
,
required:
true
,
required:
true
,
description:
'The full path of the project or namespace, e.g., "gitlab-org/gitlab-ce"'
description:
'The full path of the project
, group
or namespace, e.g., "gitlab-org/gitlab-ce"'
end
end
def
model_by_full_path
(
model
,
full_path
)
def
model_by_full_path
(
model
,
full_path
)
BatchLoader
.
for
(
full_path
).
batch
(
key:
model
)
do
|
full_paths
,
loader
,
args
|
BatchLoader
.
for
(
full_path
).
batch
(
key:
model
)
do
|
full_paths
,
loader
,
args
|
# `with_route` avoids an N+1 calculating full_path
# `with_route` avoids an N+1 calculating full_path
args
[
:key
].
where_full_path_in
(
full_paths
).
with_route
.
each
do
|
project
|
args
[
:key
].
where_full_path_in
(
full_paths
).
with_route
.
each
do
|
model_instance
|
loader
.
call
(
project
.
full_path
,
project
)
loader
.
call
(
model_instance
.
full_path
,
model_instance
)
end
end
end
end
end
end
...
...
app/graphql/resolvers/group_resolver.rb
0 → 100644
View file @
f5c7c3b9
# frozen_string_literal: true
module
Resolvers
class
GroupResolver
<
BaseResolver
prepend
FullPathResolver
type
Types
::
GroupType
,
null:
true
def
resolve
(
full_path
:)
model_by_full_path
(
Group
,
full_path
)
end
end
end
app/graphql/types/group_type.rb
0 → 100644
View file @
f5c7c3b9
# frozen_string_literal: true
module
Types
class
GroupType
<
NamespaceType
graphql_name
'Group'
authorize
:read_group
expose_permissions
Types
::
PermissionTypes
::
Group
field
:web_url
,
GraphQL
::
STRING_TYPE
,
null:
true
field
:avatar_url
,
GraphQL
::
STRING_TYPE
,
null:
true
,
resolve:
->
(
group
,
args
,
ctx
)
do
group
.
avatar_url
(
only_path:
false
)
end
if
::
Group
.
supports_nested_objects?
field
:parent
,
GroupType
,
null:
true
end
end
end
app/graphql/types/namespace_type.rb
0 → 100644
View file @
f5c7c3b9
# frozen_string_literal: true
module
Types
class
NamespaceType
<
BaseObject
graphql_name
'Namespace'
field
:id
,
GraphQL
::
ID_TYPE
,
null:
false
field
:name
,
GraphQL
::
STRING_TYPE
,
null:
false
field
:path
,
GraphQL
::
STRING_TYPE
,
null:
false
field
:description
,
GraphQL
::
STRING_TYPE
,
null:
true
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
:full_path
,
GraphQL
::
ID_TYPE
,
null:
false
field
:full_name
,
GraphQL
::
STRING_TYPE
,
null:
false
end
end
app/graphql/types/permission_types/group.rb
0 → 100644
View file @
f5c7c3b9
# frozen_string_literal: true
module
Types
module
PermissionTypes
class
Group
<
BasePermissionType
graphql_name
'GroupPermissions'
abilities
:read_group
end
end
end
app/graphql/types/project_type.rb
View file @
f5c7c3b9
...
@@ -66,6 +66,9 @@ module Types
...
@@ -66,6 +66,9 @@ module Types
field
:only_allow_merge_if_all_discussions_are_resolved
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
field
:only_allow_merge_if_all_discussions_are_resolved
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
field
:printing_merge_request_link_enabled
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
field
:printing_merge_request_link_enabled
,
GraphQL
::
BOOLEAN_TYPE
,
null:
true
field
:namespace
,
Types
::
NamespaceType
,
null:
false
field
:group
,
Types
::
GroupType
,
null:
true
field
:merge_requests
,
field
:merge_requests
,
Types
::
MergeRequestType
.
connection_type
,
Types
::
MergeRequestType
.
connection_type
,
null:
true
,
null:
true
,
...
...
app/graphql/types/query_type.rb
View file @
f5c7c3b9
...
@@ -9,6 +9,11 @@ module Types
...
@@ -9,6 +9,11 @@ module Types
resolver:
Resolvers
::
ProjectResolver
,
resolver:
Resolvers
::
ProjectResolver
,
description:
"Find a project"
description:
"Find a project"
field
:group
,
Types
::
GroupType
,
null:
true
,
resolver:
Resolvers
::
GroupResolver
,
description:
"Find a group"
field
:metadata
,
Types
::
MetadataType
,
field
:metadata
,
Types
::
MetadataType
,
null:
true
,
null:
true
,
resolver:
Resolvers
::
MetadataResolver
,
resolver:
Resolvers
::
MetadataResolver
,
...
...
changelogs/unreleased/bw-add-graphql-groups.yml
0 → 100644
View file @
f5c7c3b9
---
title
:
Add initial GraphQL query for Groups
merge_request
:
27492
author
:
type
:
added
spec/graphql/types/group_type_spec.rb
0 → 100644
View file @
f5c7c3b9
# frozen_string_literal: true
require
'spec_helper'
describe
GitlabSchema
.
types
[
'Group'
]
do
it
{
expect
(
described_class
).
to
expose_permissions_using
(
Types
::
PermissionTypes
::
Group
)
}
it
{
expect
(
described_class
.
graphql_name
).
to
eq
(
'Group'
)
}
it
{
expect
(
described_class
).
to
require_graphql_authorizations
(
:read_group
)
}
end
spec/graphql/types/namespace_type.rb
0 → 100644
View file @
f5c7c3b9
# frozen_string_literal: true
require
'spec_helper'
describe
GitlabSchema
.
types
[
'Namespace'
]
do
it
{
expect
(
described_class
.
graphql_name
).
to
eq
(
'Namespace'
)
}
end
spec/graphql/types/query_type_spec.rb
View file @
f5c7c3b9
...
@@ -5,7 +5,7 @@ describe GitlabSchema.types['Query'] do
...
@@ -5,7 +5,7 @@ describe GitlabSchema.types['Query'] do
expect
(
described_class
.
graphql_name
).
to
eq
(
'Query'
)
expect
(
described_class
.
graphql_name
).
to
eq
(
'Query'
)
end
end
it
{
is_expected
.
to
have_graphql_fields
(
:project
,
:echo
,
:metadata
)
}
it
{
is_expected
.
to
have_graphql_fields
(
:project
,
:
group
,
:
echo
,
:metadata
)
}
describe
'project field'
do
describe
'project field'
do
subject
{
described_class
.
fields
[
'project'
]
}
subject
{
described_class
.
fields
[
'project'
]
}
...
...
spec/requests/api/graphql/group_query_spec.rb
0 → 100644
View file @
f5c7c3b9
require
'spec_helper'
# Based on spec/requests/api/groups_spec.rb
# Should follow closely in order to ensure all situations are covered
describe
'getting group information'
do
include
GraphqlHelpers
include
UploadHelpers
let
(
:user1
)
{
create
(
:user
,
can_create_group:
false
)
}
let
(
:user2
)
{
create
(
:user
)
}
let
(
:admin
)
{
create
(
:admin
)
}
let!
(
:group1
)
{
create
(
:group
,
avatar:
File
.
open
(
uploaded_image_temp_path
))
}
let!
(
:group2
)
{
create
(
:group
,
:private
)
}
# let!(:project1) { create(:project, namespace: group1) }
# let!(:project2) { create(:project, namespace: group2) }
# let!(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
before
do
group1
.
add_owner
(
user1
)
group2
.
add_owner
(
user2
)
end
# similar to the API "GET /groups/:id"
describe
"Query group(fullPath)"
do
# Given a group, create one project for each visibility level
#
# group - Group to add projects to
# share_with - If provided, each project will be shared with this Group
#
# Returns a Hash of visibility_level => Project pairs
def
add_projects_to_group
(
group
,
share_with:
nil
)
projects
=
{
public:
create
(
:project
,
:public
,
namespace:
group
),
internal:
create
(
:project
,
:internal
,
namespace:
group
),
private:
create
(
:project
,
:private
,
namespace:
group
)
}
if
share_with
create
(
:project_group_link
,
project:
projects
[
:public
],
group:
share_with
)
create
(
:project_group_link
,
project:
projects
[
:internal
],
group:
share_with
)
create
(
:project_group_link
,
project:
projects
[
:private
],
group:
share_with
)
end
projects
end
def
response_project_ids
(
json_response
,
key
)
json_response
[
key
].
map
do
|
project
|
project
[
'id'
].
to_i
end
end
def
group_query
(
group
)
graphql_query_for
(
'group'
,
'fullPath'
=>
group
.
full_path
)
end
it_behaves_like
'a working graphql query'
do
before
do
post_graphql
(
group_query
(
group1
))
end
end
context
'when unauthenticated'
do
it
'returns nil for a private group'
do
post_graphql
(
group_query
(
group2
))
expect
(
graphql_data
[
'group'
]).
to
be_nil
end
it
'returns a public group'
do
post_graphql
(
group_query
(
group1
))
expect
(
graphql_data
[
'group'
]).
not_to
be_nil
end
# it 'returns only public projects in the group' do
# public_group = create(:group, :public)
# projects = add_projects_to_group(public_group)
#
# get api("/groups/#{public_group.id}")
#
# expect(response_project_ids(json_response, 'projects'))
# .to contain_exactly(projects[:public].id)
# end
# it 'returns only public projects shared with the group' do
# public_group = create(:group, :public)
# projects = add_projects_to_group(public_group, share_with: group1)
#
# get api("/groups/#{group1.id}")
#
# expect(response_project_ids(json_response, 'shared_projects'))
# .to contain_exactly(projects[:public].id)
# end
end
context
"when authenticated as user"
do
it
"returns one of user1's groups"
do
project
=
create
(
:project
,
namespace:
group2
,
path:
'Foo'
)
create
(
:project_group_link
,
project:
project
,
group:
group1
)
post_graphql
(
group_query
(
group1
),
current_user:
user1
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
graphql_data
[
'group'
][
'id'
]).
to
eq
(
group1
.
id
.
to_s
)
expect
(
graphql_data
[
'group'
][
'name'
]).
to
eq
(
group1
.
name
)
expect
(
graphql_data
[
'group'
][
'path'
]).
to
eq
(
group1
.
path
)
expect
(
graphql_data
[
'group'
][
'description'
]).
to
eq
(
group1
.
description
)
expect
(
graphql_data
[
'group'
][
'visibility'
]).
to
eq
(
Gitlab
::
VisibilityLevel
.
string_level
(
group1
.
visibility_level
))
expect
(
graphql_data
[
'group'
][
'avatarUrl'
]).
to
eq
(
group1
.
avatar_url
(
only_path:
false
))
expect
(
graphql_data
[
'group'
][
'webUrl'
]).
to
eq
(
group1
.
web_url
)
expect
(
graphql_data
[
'group'
][
'requestAccessEnabled'
]).
to
eq
(
group1
.
request_access_enabled
)
expect
(
graphql_data
[
'group'
][
'fullName'
]).
to
eq
(
group1
.
full_name
)
expect
(
graphql_data
[
'group'
][
'fullPath'
]).
to
eq
(
group1
.
full_path
)
expect
(
graphql_data
[
'group'
][
'parentId'
]).
to
eq
(
group1
.
parent_id
)
# expect(graphql_data['group']['projects']).to be_an Array
# expect(graphql_data['group']['projects'].length).to eq(2)
# expect(graphql_data['group']['sharedProjects']).to be_an Array
# expect(graphql_data['group']['sharedProjects'].length).to eq(1)
# expect(graphql_data['group']['sharedProjects'][0]['id']).to eq(project.id)
end
# it "returns one of user1's groups without projects when with_projects option is set to false" do
# project = create(:project, namespace: group2, path: 'Foo')
# create(:project_group_link, project: project, group: group1)
#
# get api("/groups/#{group1.id}", user1), params: { with_projects: false }
#
# expect(response).to have_gitlab_http_status(200)
# expect(json_response['projects']).to be_nil
# expect(json_response['shared_projects']).to be_nil
# end
it
"does not return a non existing group"
do
query
=
graphql_query_for
(
'group'
,
'fullPath'
=>
'1328'
)
post_graphql
(
query
,
current_user:
user1
)
expect
(
graphql_data
[
'group'
]).
to
be_nil
end
it
"does not return a group not attached to user1"
do
post_graphql
(
group_query
(
group2
),
current_user:
user1
)
expect
(
graphql_data
[
'group'
]).
to
be_nil
end
# it 'returns only public and internal projects in the group' do
# public_group = create(:group, :public)
# projects = add_projects_to_group(public_group)
#
# get api("/groups/#{public_group.id}", user2)
#
# expect(response_project_ids(json_response, 'projects'))
# .to contain_exactly(projects[:public].id, projects[:internal].id)
# end
# it 'returns only public and internal projects shared with the group' do
# public_group = create(:group, :public)
# projects = add_projects_to_group(public_group, share_with: group1)
#
# get api("/groups/#{group1.id}", user2)
#
# expect(response_project_ids(json_response, 'shared_projects'))
# .to contain_exactly(projects[:public].id, projects[:internal].id)
# 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
)
expect
do
post_graphql
(
group_query
(
group1
),
current_user:
admin
)
end
.
not_to
exceed_query_limit
(
control_count
)
end
end
context
"when authenticated as admin"
do
it
"returns any existing group"
do
post_graphql
(
group_query
(
group2
),
current_user:
admin
)
expect
(
graphql_data
[
'group'
][
'name'
]).
to
eq
(
group2
.
name
)
end
it
"does not return a non existing group"
do
query
=
graphql_query_for
(
'group'
,
'fullPath'
=>
'1328'
)
post_graphql
(
query
,
current_user:
admin
)
expect
(
graphql_data
[
'group'
]).
to
be_nil
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment