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:
Nick Thomas 2019-05-22 15:06:03 +00:00
commit 454cbac3ef
19 changed files with 318 additions and 0 deletions

View 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

View file

@ -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,

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View file

@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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