Merge branch 'graphql-tree-last-commit' into 'master'
Added commit type to tree GraphQL type See merge request gitlab-org/gitlab-ce!29412
This commit is contained in:
commit
2321b337f1
12 changed files with 139 additions and 3 deletions
30
app/graphql/types/commit_type.rb
Normal file
30
app/graphql/types/commit_type.rb
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Types
|
||||||
|
class CommitType < BaseObject
|
||||||
|
graphql_name 'Commit'
|
||||||
|
|
||||||
|
authorize :download_code
|
||||||
|
|
||||||
|
present_using CommitPresenter
|
||||||
|
|
||||||
|
field :id, type: GraphQL::ID_TYPE, null: false
|
||||||
|
field :sha, type: GraphQL::STRING_TYPE, null: false
|
||||||
|
field :title, type: GraphQL::STRING_TYPE, null: true
|
||||||
|
field :description, type: GraphQL::STRING_TYPE, null: true
|
||||||
|
field :message, type: GraphQL::STRING_TYPE, null: true
|
||||||
|
field :authored_date, type: Types::TimeType, null: true
|
||||||
|
field :web_url, type: GraphQL::STRING_TYPE, null: false
|
||||||
|
|
||||||
|
# models/commit lazy loads the author by email
|
||||||
|
field :author, type: Types::UserType, null: true
|
||||||
|
|
||||||
|
field :latest_pipeline,
|
||||||
|
type: Types::Ci::PipelineType,
|
||||||
|
null: true,
|
||||||
|
description: "Latest pipeline for this commit",
|
||||||
|
resolve: -> (obj, ctx, args) do
|
||||||
|
Gitlab::Graphql::Loaders::PipelineForShaLoader.new(obj.project, obj.sha).find_last
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,6 +4,11 @@ module Types
|
||||||
class TreeType < BaseObject
|
class TreeType < BaseObject
|
||||||
graphql_name 'Tree'
|
graphql_name 'Tree'
|
||||||
|
|
||||||
|
# Complexity 10 as it triggers a Gitaly call on each render
|
||||||
|
field :last_commit, Types::CommitType, null: true, complexity: 10, resolve: -> (tree, args, ctx) do
|
||||||
|
tree.repository.last_commit_for_path(tree.sha, tree.path)
|
||||||
|
end
|
||||||
|
|
||||||
field :trees, Types::Tree::TreeEntryType.connection_type, null: false, resolve: -> (obj, args, ctx) do
|
field :trees, Types::Tree::TreeEntryType.connection_type, null: false, resolve: -> (obj, args, ctx) do
|
||||||
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.trees, obj.repository)
|
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.trees, obj.repository)
|
||||||
end
|
end
|
||||||
|
|
|
@ -295,6 +295,11 @@ module Ci
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.latest_for_shas(shas)
|
||||||
|
max_id_per_sha = for_sha(shas).group(:sha).select("max(id)")
|
||||||
|
where(id: max_id_per_sha)
|
||||||
|
end
|
||||||
|
|
||||||
def self.latest_successful_ids_per_project
|
def self.latest_successful_ids_per_project
|
||||||
success.group(:project_id).select('max(id) as id')
|
success.group(:project_id).select('max(id) as id')
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class CommitPresenter < Gitlab::View::Presenter::Simple
|
class CommitPresenter < Gitlab::View::Presenter::Delegated
|
||||||
|
include GlobalID::Identification
|
||||||
|
|
||||||
presents :commit
|
presents :commit
|
||||||
|
|
||||||
def status_for(ref)
|
def status_for(ref)
|
||||||
|
@ -10,4 +12,8 @@ class CommitPresenter < Gitlab::View::Presenter::Simple
|
||||||
def any_pipelines?
|
def any_pipelines?
|
||||||
can?(current_user, :read_pipeline, commit.project) && commit.pipelines.any?
|
can?(current_user, :read_pipeline, commit.project) && commit.pipelines.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def web_url
|
||||||
|
Gitlab::UrlBuilder.new(commit).url
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
5
changelogs/unreleased/graphql-tree-last-commit.yml
Normal file
5
changelogs/unreleased/graphql-tree-last-commit.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Added commit type to tree GraphQL response
|
||||||
|
merge_request: 29412
|
||||||
|
author:
|
||||||
|
type: added
|
25
lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb
Normal file
25
lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module Graphql
|
||||||
|
module Loaders
|
||||||
|
class PipelineForShaLoader
|
||||||
|
attr_accessor :project, :sha
|
||||||
|
|
||||||
|
def initialize(project, sha)
|
||||||
|
@project, @sha = project, sha
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_last
|
||||||
|
BatchLoader.for(sha).batch(key: project) do |shas, loader, args|
|
||||||
|
pipelines = args[:key].ci_pipelines.latest_for_shas(shas)
|
||||||
|
|
||||||
|
pipelines.each do |pipeline|
|
||||||
|
loader.call(pipeline.sha, pipeline)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -113,7 +113,7 @@ describe GitlabSchema do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "raises a meaningful error if a global id couldn't be generated" do
|
it "raises a meaningful error if a global id couldn't be generated" do
|
||||||
expect { described_class.id_from_object(build(:commit)) }
|
expect { described_class.id_from_object(build(:wiki_directory)) }
|
||||||
.to raise_error(RuntimeError, /include `GlobalID::Identification` into/i)
|
.to raise_error(RuntimeError, /include `GlobalID::Identification` into/i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
11
spec/graphql/types/commit_type_spec.rb
Normal file
11
spec/graphql/types/commit_type_spec.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe GitlabSchema.types['Commit'] do
|
||||||
|
it { expect(described_class.graphql_name).to eq('Commit') }
|
||||||
|
|
||||||
|
it { expect(described_class).to require_graphql_authorizations(:download_code) }
|
||||||
|
|
||||||
|
it { expect(described_class).to have_graphql_fields(:id, :sha, :title, :description, :message, :authored_date, :author, :web_url, :latest_pipeline) }
|
||||||
|
end
|
|
@ -5,5 +5,5 @@ require 'spec_helper'
|
||||||
describe Types::Tree::TreeType do
|
describe Types::Tree::TreeType do
|
||||||
it { expect(described_class.graphql_name).to eq('Tree') }
|
it { expect(described_class.graphql_name).to eq('Tree') }
|
||||||
|
|
||||||
it { expect(described_class).to have_graphql_fields(:trees, :submodules, :blobs) }
|
it { expect(described_class).to have_graphql_fields(:trees, :submodules, :blobs, :last_commit) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Gitlab::Graphql::Loaders::PipelineForShaLoader do
|
||||||
|
include GraphqlHelpers
|
||||||
|
|
||||||
|
describe '#find_last' do
|
||||||
|
it 'batch-resolves latest pipeline' do
|
||||||
|
project = create(:project, :repository)
|
||||||
|
pipeline1 = create(:ci_pipeline, project: project, ref: project.default_branch, sha: project.commit.sha)
|
||||||
|
pipeline2 = create(:ci_pipeline, project: project, ref: project.default_branch, sha: project.commit.sha)
|
||||||
|
pipeline3 = create(:ci_pipeline, project: project, ref: 'improve/awesome', sha: project.commit('improve/awesome').sha)
|
||||||
|
|
||||||
|
result = batch(max_queries: 1) do
|
||||||
|
[pipeline1.sha, pipeline3.sha].map { |sha| described_class.new(project, sha).find_last }
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(result).to contain_exactly(pipeline2, pipeline3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1886,6 +1886,17 @@ describe Ci::Pipeline, :mailer do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.latest_for_shas' do
|
||||||
|
let(:sha) { 'abc' }
|
||||||
|
|
||||||
|
it 'returns latest pipeline for sha' do
|
||||||
|
create(:ci_pipeline, sha: sha)
|
||||||
|
pipeline2 = create(:ci_pipeline, sha: sha)
|
||||||
|
|
||||||
|
expect(described_class.latest_for_shas(sha)).to contain_exactly(pipeline2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '.latest_successful_ids_per_project' do
|
describe '.latest_successful_ids_per_project' do
|
||||||
let(:projects) { create_list(:project, 2) }
|
let(:projects) { create_list(:project, 2) }
|
||||||
let!(:pipeline1) { create(:ci_pipeline, :success, project: projects[0]) }
|
let!(:pipeline1) { create(:ci_pipeline, :success, project: projects[0]) }
|
||||||
|
|
|
@ -33,6 +33,12 @@ describe 'getting a tree in a project' do
|
||||||
expect(graphql_data['project']['repository']['tree']['submodules']['edges']).to eq([])
|
expect(graphql_data['project']['repository']['tree']['submodules']['edges']).to eq([])
|
||||||
expect(graphql_data['project']['repository']['tree']['blobs']['edges']).to eq([])
|
expect(graphql_data['project']['repository']['tree']['blobs']['edges']).to eq([])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns null commit' do
|
||||||
|
post_graphql(query, current_user: current_user)
|
||||||
|
|
||||||
|
expect(graphql_data['project']['repository']['last_commit']).to be_nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when ref does not exist' do
|
context 'when ref does not exist' do
|
||||||
|
@ -45,6 +51,12 @@ describe 'getting a tree in a project' do
|
||||||
expect(graphql_data['project']['repository']['tree']['submodules']['edges']).to eq([])
|
expect(graphql_data['project']['repository']['tree']['submodules']['edges']).to eq([])
|
||||||
expect(graphql_data['project']['repository']['tree']['blobs']['edges']).to eq([])
|
expect(graphql_data['project']['repository']['tree']['blobs']['edges']).to eq([])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns null commit' do
|
||||||
|
post_graphql(query, current_user: current_user)
|
||||||
|
|
||||||
|
expect(graphql_data['project']['repository']['last_commit']).to be_nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when ref and path exist' do
|
context 'when ref and path exist' do
|
||||||
|
@ -61,6 +73,12 @@ describe 'getting a tree in a project' do
|
||||||
expect(graphql_data['project']['repository']['tree']['blobs']['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
|
expect(graphql_data['project']['repository']['tree']['submodules']['edges'].size).to be > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns tree latest commit' do
|
||||||
|
post_graphql(query, current_user: current_user)
|
||||||
|
|
||||||
|
expect(graphql_data['project']['repository']['tree']['lastCommit']).to be_present
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when current user is nil' do
|
context 'when current user is nil' do
|
||||||
|
|
Loading…
Reference in a new issue