Add metadata about the GitLab server to GraphQL
This commit is contained in:
parent
42d3117f9c
commit
21779d0018
14 changed files with 171 additions and 5 deletions
11
app/graphql/resolvers/metadata_resolver.rb
Normal file
11
app/graphql/resolvers/metadata_resolver.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Resolvers
|
||||||
|
class MetadataResolver < BaseResolver
|
||||||
|
type Types::MetadataType, null: false
|
||||||
|
|
||||||
|
def resolve(**args)
|
||||||
|
{ version: Gitlab::VERSION, revision: Gitlab.revision }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
10
app/graphql/types/metadata_type.rb
Normal file
10
app/graphql/types/metadata_type.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Types
|
||||||
|
class MetadataType < ::Types::BaseObject
|
||||||
|
graphql_name 'Metadata'
|
||||||
|
|
||||||
|
field :version, GraphQL::STRING_TYPE, null: false
|
||||||
|
field :revision, GraphQL::STRING_TYPE, null: false
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Types
|
module Types
|
||||||
class QueryType < BaseObject
|
class QueryType < ::Types::BaseObject
|
||||||
graphql_name 'Query'
|
graphql_name 'Query'
|
||||||
|
|
||||||
field :project, Types::ProjectType,
|
field :project, Types::ProjectType,
|
||||||
|
@ -10,6 +10,14 @@ module Types
|
||||||
description: "Find a project",
|
description: "Find a project",
|
||||||
authorize: :read_project
|
authorize: :read_project
|
||||||
|
|
||||||
|
field :metadata, Types::MetadataType,
|
||||||
|
null: true,
|
||||||
|
resolver: Resolvers::MetadataResolver,
|
||||||
|
description: 'Metadata about GitLab' do |*args|
|
||||||
|
|
||||||
|
authorize :read_instance_metadata
|
||||||
|
end
|
||||||
|
|
||||||
field :echo, GraphQL::STRING_TYPE, null: false, function: Functions::Echo.new
|
field :echo, GraphQL::STRING_TYPE, null: false, function: Functions::Echo.new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -68,6 +68,10 @@ class GlobalPolicy < BasePolicy
|
||||||
enable :read_users_list
|
enable :read_users_list
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rule { ~anonymous }.policy do
|
||||||
|
enable :read_instance_metadata
|
||||||
|
end
|
||||||
|
|
||||||
rule { admin }.policy do
|
rule { admin }.policy do
|
||||||
enable :read_custom_attribute
|
enable :read_custom_attribute
|
||||||
enable :update_custom_attribute
|
enable :update_custom_attribute
|
||||||
|
|
5
changelogs/unreleased/56809-graphql-version-api.yml
Normal file
5
changelogs/unreleased/56809-graphql-version-api.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Add metadata about the GitLab server to GraphQL
|
||||||
|
merge_request: 24636
|
||||||
|
author:
|
||||||
|
type: added
|
22
lib/api/helpers/graphql_helpers.rb
Normal file
22
lib/api/helpers/graphql_helpers.rb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module API
|
||||||
|
module Helpers
|
||||||
|
# GraphqlHelpers is used by the REST API when it is acting like a client
|
||||||
|
# against the graphql API. Helper code for the graphql server implementation
|
||||||
|
# should be in app/graphql/ or lib/gitlab/graphql/
|
||||||
|
module GraphqlHelpers
|
||||||
|
def conditionally_graphql!(fallback:, query:, context: {}, transform: nil)
|
||||||
|
return fallback.call unless Feature.enabled?(:graphql)
|
||||||
|
|
||||||
|
result = GitlabSchema.execute(query, context: context)
|
||||||
|
|
||||||
|
if transform
|
||||||
|
transform.call(result)
|
||||||
|
else
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,13 +2,29 @@
|
||||||
|
|
||||||
module API
|
module API
|
||||||
class Version < Grape::API
|
class Version < Grape::API
|
||||||
|
helpers ::API::Helpers::GraphqlHelpers
|
||||||
|
|
||||||
before { authenticate! }
|
before { authenticate! }
|
||||||
|
|
||||||
|
METADATA_QUERY = <<~EOF
|
||||||
|
{
|
||||||
|
metadata {
|
||||||
|
version
|
||||||
|
revision
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
desc 'Get the version information of the GitLab instance.' do
|
desc 'Get the version information of the GitLab instance.' do
|
||||||
detail 'This feature was introduced in GitLab 8.13.'
|
detail 'This feature was introduced in GitLab 8.13.'
|
||||||
end
|
end
|
||||||
get '/version' do
|
get '/version' do
|
||||||
{ version: Gitlab::VERSION, revision: Gitlab.revision }
|
conditionally_graphql!(
|
||||||
|
query: METADATA_QUERY,
|
||||||
|
context: { current_user: current_user },
|
||||||
|
transform: ->(result) { result.dig('data', 'metadata') },
|
||||||
|
fallback: -> { { version: Gitlab::VERSION, revision: Gitlab.revision } }
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
11
spec/graphql/resolvers/metadata_resolver_spec.rb
Normal file
11
spec/graphql/resolvers/metadata_resolver_spec.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Resolvers::MetadataResolver do
|
||||||
|
include GraphqlHelpers
|
||||||
|
|
||||||
|
describe '#resolve' do
|
||||||
|
it 'returns version and revision' do
|
||||||
|
expect(resolve(described_class)).to eq(version: Gitlab::VERSION, revision: Gitlab.revision)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
5
spec/graphql/types/metadata_type_spec.rb
Normal file
5
spec/graphql/types/metadata_type_spec.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe GitlabSchema.types['Metadata'] do
|
||||||
|
it { expect(described_class.graphql_name).to eq('Metadata') }
|
||||||
|
end
|
|
@ -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) }
|
it { is_expected.to have_graphql_fields(:project, :echo, :metadata) }
|
||||||
|
|
||||||
describe 'project field' do
|
describe 'project field' do
|
||||||
subject { described_class.fields['project'] }
|
subject { described_class.fields['project'] }
|
||||||
|
@ -20,4 +20,17 @@ describe GitlabSchema.types['Query'] do
|
||||||
is_expected.to require_graphql_authorizations(:read_project)
|
is_expected.to require_graphql_authorizations(:read_project)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'metadata field' do
|
||||||
|
subject { described_class.fields['metadata'] }
|
||||||
|
|
||||||
|
it 'returns metadata' do
|
||||||
|
is_expected.to have_graphql_type(Types::MetadataType)
|
||||||
|
is_expected.to have_graphql_resolver(Resolvers::MetadataResolver)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'authorizes with log_in' do
|
||||||
|
is_expected.to require_graphql_authorizations(:read_instance_metadata)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -181,6 +181,18 @@ describe GlobalPolicy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'read instance metadata' do
|
||||||
|
context 'regular user' do
|
||||||
|
it { is_expected.to be_allowed(:read_instance_metadata) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'anonymous' do
|
||||||
|
let(:current_user) { nil }
|
||||||
|
|
||||||
|
it { is_expected.not_to be_allowed(:read_instance_metadata) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe 'read instance statistics' do
|
describe 'read instance statistics' do
|
||||||
context 'regular user' do
|
context 'regular user' do
|
||||||
it { is_expected.to be_allowed(:read_instance_statistics) }
|
it { is_expected.to be_allowed(:read_instance_statistics) }
|
||||||
|
|
32
spec/requests/api/graphql/metadata_query_spec.rb
Normal file
32
spec/requests/api/graphql/metadata_query_spec.rb
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe 'getting project information' do
|
||||||
|
include GraphqlHelpers
|
||||||
|
|
||||||
|
let(:query) { graphql_query_for('metadata', {}, all_graphql_fields_for('Metadata')) }
|
||||||
|
|
||||||
|
context 'logged in' do
|
||||||
|
it 'returns version and revision' do
|
||||||
|
post_graphql(query, current_user: create(:user))
|
||||||
|
|
||||||
|
expect(graphql_errors).to be_nil
|
||||||
|
expect(graphql_data).to eq(
|
||||||
|
'metadata' => {
|
||||||
|
'version' => Gitlab::VERSION,
|
||||||
|
'revision' => Gitlab.revision
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'anonymous user' do
|
||||||
|
it 'returns nothing' do
|
||||||
|
post_graphql(query, current_user: nil)
|
||||||
|
|
||||||
|
expect(graphql_errors).to be_nil
|
||||||
|
expect(graphql_data).to eq('metadata' => nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe API::Version do
|
describe API::Version do
|
||||||
describe 'GET /version' do
|
shared_examples_for 'GET /version' do
|
||||||
context 'when unauthenticated' do
|
context 'when unauthenticated' do
|
||||||
it 'returns authentication error' do
|
it 'returns authentication error' do
|
||||||
get api('/version')
|
get api('/version')
|
||||||
|
@ -22,4 +22,20 @@ describe API::Version do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with graphql enabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(graphql: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
include_examples 'GET /version'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with graphql disabled' do
|
||||||
|
before do
|
||||||
|
stub_feature_flags(graphql: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
include_examples 'GET /version'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -77,8 +77,9 @@ module GraphqlHelpers
|
||||||
def query_graphql_field(name, attributes = {}, fields = nil)
|
def query_graphql_field(name, attributes = {}, fields = nil)
|
||||||
fields ||= all_graphql_fields_for(name.classify)
|
fields ||= all_graphql_fields_for(name.classify)
|
||||||
attributes = attributes_to_graphql(attributes)
|
attributes = attributes_to_graphql(attributes)
|
||||||
|
attributes = "(#{attributes})" if attributes.present?
|
||||||
<<~QUERY
|
<<~QUERY
|
||||||
#{name}(#{attributes}) {
|
#{name}#{attributes} {
|
||||||
#{fields}
|
#{fields}
|
||||||
}
|
}
|
||||||
QUERY
|
QUERY
|
||||||
|
|
Loading…
Reference in a new issue