Merge branch 'graphql-tree' into 'master'
Added repository files to GraphQL API See merge request gitlab-org/gitlab-ce!28325
This commit is contained in:
commit
454cbac3ef
19 changed files with 318 additions and 0 deletions
26
app/graphql/resolvers/tree_resolver.rb
Normal file
26
app/graphql/resolvers/tree_resolver.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
class TreeResolver < BaseResolver
|
||||
argument :path, GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
default_value: '',
|
||||
description: 'The path to get the tree for. Default value is the root of the repository'
|
||||
argument :ref, GraphQL::STRING_TYPE,
|
||||
required: false,
|
||||
default_value: :head,
|
||||
description: 'The commit ref to get the tree for. Default value is HEAD'
|
||||
argument :recursive, GraphQL::BOOLEAN_TYPE,
|
||||
required: false,
|
||||
default_value: false,
|
||||
description: 'Used to get a recursive tree. Default is false'
|
||||
|
||||
alias_method :repository, :object
|
||||
|
||||
def resolve(**args)
|
||||
return unless repository.exists?
|
||||
|
||||
repository.tree(args[:ref], args[:path], recursive: args[:recursive])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -69,6 +69,8 @@ module Types
|
|||
field :namespace, Types::NamespaceType, null: false
|
||||
field :group, Types::GroupType, null: true
|
||||
|
||||
field :repository, Types::RepositoryType, null: false
|
||||
|
||||
field :merge_requests,
|
||||
Types::MergeRequestType.connection_type,
|
||||
null: true,
|
||||
|
|
14
app/graphql/types/repository_type.rb
Normal file
14
app/graphql/types/repository_type.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
class RepositoryType < BaseObject
|
||||
graphql_name 'Repository'
|
||||
|
||||
authorize :download_code
|
||||
|
||||
field :root_ref, GraphQL::STRING_TYPE, null: true
|
||||
field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty?
|
||||
field :exists, GraphQL::BOOLEAN_TYPE, null: false, method: :exists?
|
||||
field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver
|
||||
end
|
||||
end
|
10
app/graphql/types/tree/blob_type.rb
Normal file
10
app/graphql/types/tree/blob_type.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
module Types
|
||||
module Tree
|
||||
class BlobType < BaseObject
|
||||
implements Types::Tree::EntryType
|
||||
|
||||
graphql_name 'Blob'
|
||||
end
|
||||
end
|
||||
end
|
14
app/graphql/types/tree/entry_type.rb
Normal file
14
app/graphql/types/tree/entry_type.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
module Types
|
||||
module Tree
|
||||
module EntryType
|
||||
include Types::BaseInterface
|
||||
|
||||
field :id, GraphQL::ID_TYPE, null: false
|
||||
field :name, GraphQL::STRING_TYPE, null: false
|
||||
field :type, Tree::TypeEnum, null: false
|
||||
field :path, GraphQL::STRING_TYPE, null: false
|
||||
field :flat_path, GraphQL::STRING_TYPE, null: false
|
||||
end
|
||||
end
|
||||
end
|
10
app/graphql/types/tree/submodule_type.rb
Normal file
10
app/graphql/types/tree/submodule_type.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
module Types
|
||||
module Tree
|
||||
class SubmoduleType < BaseObject
|
||||
implements Types::Tree::EntryType
|
||||
|
||||
graphql_name 'Submodule'
|
||||
end
|
||||
end
|
||||
end
|
11
app/graphql/types/tree/tree_entry_type.rb
Normal file
11
app/graphql/types/tree/tree_entry_type.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
module Types
|
||||
module Tree
|
||||
class TreeEntryType < BaseObject
|
||||
implements Types::Tree::EntryType
|
||||
|
||||
graphql_name 'TreeEntry'
|
||||
description 'Represents a directory'
|
||||
end
|
||||
end
|
||||
end
|
12
app/graphql/types/tree/tree_type.rb
Normal file
12
app/graphql/types/tree/tree_type.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
module Types
|
||||
module Tree
|
||||
class TreeType < BaseObject
|
||||
graphql_name 'Tree'
|
||||
|
||||
field :trees, Types::Tree::TreeEntryType.connection_type, null: false
|
||||
field :submodules, Types::Tree::SubmoduleType.connection_type, null: false
|
||||
field :blobs, Types::Tree::BlobType.connection_type, null: false
|
||||
end
|
||||
end
|
||||
end
|
14
app/graphql/types/tree/type_enum.rb
Normal file
14
app/graphql/types/tree/type_enum.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
module Tree
|
||||
class TypeEnum < BaseEnum
|
||||
graphql_name 'EntryType'
|
||||
description 'Type of a tree entry'
|
||||
|
||||
value 'tree', value: :tree
|
||||
value 'blob', value: :blob
|
||||
value 'commit', value: :commit
|
||||
end
|
||||
end
|
||||
end
|
35
spec/graphql/resolvers/tree_resolver_spec.rb
Normal file
35
spec/graphql/resolvers/tree_resolver_spec.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Resolvers::TreeResolver do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:repository) { create(:project, :repository).repository }
|
||||
|
||||
describe '#resolve' do
|
||||
it 'resolves to a tree' do
|
||||
result = resolve_repository({ ref: "master" })
|
||||
|
||||
expect(result).to be_an_instance_of(Tree)
|
||||
end
|
||||
|
||||
it 'resolve to a recursive tree' do
|
||||
result = resolve_repository({ ref: "master", recursive: true })
|
||||
|
||||
expect(result.trees[4].path).to eq('files/html')
|
||||
end
|
||||
|
||||
context 'when repository does not exist' do
|
||||
it 'returns nil' do
|
||||
allow(repository).to receive(:exists?).and_return(false)
|
||||
|
||||
result = resolve_repository({ ref: "master" })
|
||||
|
||||
expect(result).to be(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_repository(args)
|
||||
resolve(described_class, obj: repository, args: args)
|
||||
end
|
||||
end
|
|
@ -17,4 +17,6 @@ describe GitlabSchema.types['Project'] do
|
|||
end
|
||||
|
||||
it { is_expected.to have_graphql_field(:pipelines) }
|
||||
|
||||
it { is_expected.to have_graphql_field(:repository) }
|
||||
end
|
||||
|
|
11
spec/graphql/types/repository_type_spec.rb
Normal file
11
spec/graphql/types/repository_type_spec.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe GitlabSchema.types['Repository'] do
|
||||
it { expect(described_class.graphql_name).to eq('Repository') }
|
||||
|
||||
it { expect(described_class).to require_graphql_authorizations(:download_code) }
|
||||
|
||||
it { is_expected.to have_graphql_field(:root_ref) }
|
||||
|
||||
it { is_expected.to have_graphql_field(:tree) }
|
||||
end
|
9
spec/graphql/types/tree/blob_type_spec.rb
Normal file
9
spec/graphql/types/tree/blob_type_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Types::Tree::BlobType do
|
||||
it { expect(described_class.graphql_name).to eq('Blob') }
|
||||
|
||||
it { expect(described_class).to have_graphql_fields(:id, :name, :type, :path, :flat_path) }
|
||||
end
|
9
spec/graphql/types/tree/submodule_type_spec.rb
Normal file
9
spec/graphql/types/tree/submodule_type_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Types::Tree::SubmoduleType do
|
||||
it { expect(described_class.graphql_name).to eq('Submodule') }
|
||||
|
||||
it { expect(described_class).to have_graphql_fields(:id, :name, :type, :path, :flat_path) }
|
||||
end
|
9
spec/graphql/types/tree/tree_entry_type_spec.rb
Normal file
9
spec/graphql/types/tree/tree_entry_type_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Types::Tree::TreeEntryType do
|
||||
it { expect(described_class.graphql_name).to eq('TreeEntry') }
|
||||
|
||||
it { expect(described_class).to have_graphql_fields(:id, :name, :type, :path, :flat_path) }
|
||||
end
|
9
spec/graphql/types/tree/tree_type_spec.rb
Normal file
9
spec/graphql/types/tree/tree_type_spec.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Types::Tree::TreeType do
|
||||
it { expect(described_class.graphql_name).to eq('Tree') }
|
||||
|
||||
it { expect(described_class).to have_graphql_fields(:trees, :submodules, :blobs) }
|
||||
end
|
11
spec/graphql/types/tree/type_enum_spec.rb
Normal file
11
spec/graphql/types/tree/type_enum_spec.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Types::Tree::TypeEnum do
|
||||
it { expect(described_class.graphql_name).to eq('EntryType') }
|
||||
|
||||
it 'exposes all tree entry types' do
|
||||
expect(described_class.values.keys).to include(*%w[tree blob commit])
|
||||
end
|
||||
end
|
37
spec/requests/api/graphql/project/repository_spec.rb
Normal file
37
spec/requests/api/graphql/project/repository_spec.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
# frozen_string_literal: true
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'getting a repository in a project' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:current_user) { project.owner }
|
||||
let(:fields) do
|
||||
<<~QUERY
|
||||
#{all_graphql_fields_for('repository'.classify)}
|
||||
QUERY
|
||||
end
|
||||
let(:query) do
|
||||
graphql_query_for(
|
||||
'project',
|
||||
{ 'fullPath' => project.full_path },
|
||||
query_graphql_field('repository', {}, fields)
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns repository' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data['project']['repository']).to be_present
|
||||
end
|
||||
|
||||
context 'as a non-authorized user' do
|
||||
let(:current_user) { create(:user) }
|
||||
|
||||
it 'returns nil' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data['project']).to be(nil)
|
||||
end
|
||||
end
|
||||
end
|
73
spec/requests/api/graphql/project/tree/tree_spec.rb
Normal file
73
spec/requests/api/graphql/project/tree/tree_spec.rb
Normal file
|
@ -0,0 +1,73 @@
|
|||
# frozen_string_literal: true
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'getting a tree in a project' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let(:project) { create(:project, :repository) }
|
||||
let(:current_user) { project.owner }
|
||||
let(:path) { "" }
|
||||
let(:ref) { "master" }
|
||||
let(:fields) do
|
||||
<<~QUERY
|
||||
tree(path:"#{path}", ref:"#{ref}") {
|
||||
#{all_graphql_fields_for('tree'.classify)}
|
||||
}
|
||||
QUERY
|
||||
end
|
||||
let(:query) do
|
||||
graphql_query_for(
|
||||
'project',
|
||||
{ 'fullPath' => project.full_path },
|
||||
query_graphql_field('repository', {}, fields)
|
||||
)
|
||||
end
|
||||
|
||||
context 'when path does not exist' do
|
||||
let(:path) { "testing123" }
|
||||
|
||||
it 'returns empty tree' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data['project']['repository']['tree']['trees']['edges']).to eq([])
|
||||
expect(graphql_data['project']['repository']['tree']['submodules']['edges']).to eq([])
|
||||
expect(graphql_data['project']['repository']['tree']['blobs']['edges']).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ref does not exist' do
|
||||
let(:ref) { "testing123" }
|
||||
|
||||
it 'returns empty tree' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data['project']['repository']['tree']['trees']['edges']).to eq([])
|
||||
expect(graphql_data['project']['repository']['tree']['submodules']['edges']).to eq([])
|
||||
expect(graphql_data['project']['repository']['tree']['blobs']['edges']).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ref and path exist' do
|
||||
it 'returns tree' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data['project']['repository']['tree']).to be_present
|
||||
end
|
||||
|
||||
it 'returns blobs, subtrees and submodules inside tree' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data['project']['repository']['tree']['trees']['edges'].size).to be > 0
|
||||
expect(graphql_data['project']['repository']['tree']['blobs']['edges'].size).to be > 0
|
||||
expect(graphql_data['project']['repository']['tree']['submodules']['edges'].size).to be > 0
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current user is nil' do
|
||||
it 'returns empty project' do
|
||||
post_graphql(query, current_user: nil)
|
||||
|
||||
expect(graphql_data['project']).to be(nil)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue