Commit f4280ae8 authored by Phil Hughes's avatar Phil Hughes

GraphQL commit type correctly return pipeline for ref

This changes the pipeline field in the GraphQL commit type
to return the pipelines for a ref instead of just the sha
parent cc09e305
...@@ -38,7 +38,14 @@ export default { ...@@ -38,7 +38,14 @@ export default {
path: this.currentPath.replace(/^\//, ''), path: this.currentPath.replace(/^\//, ''),
}; };
}, },
update: data => data.project.repository.tree.lastCommit, update: data => {
const pipelines = data.project.repository.tree.lastCommit.pipelines.edges;
return {
...data.project.repository.tree.lastCommit,
pipeline: pipelines.length && pipelines[0].node,
};
},
context: { context: {
isSingleRequest: true, isSingleRequest: true,
}, },
...@@ -61,7 +68,7 @@ export default { ...@@ -61,7 +68,7 @@ export default {
computed: { computed: {
statusTitle() { statusTitle() {
return sprintf(s__('Commits|Commit: %{commitText}'), { return sprintf(s__('Commits|Commit: %{commitText}'), {
commitText: this.commit.latestPipeline.detailedStatus.text, commitText: this.commit.pipeline.detailedStatus.text,
}); });
}, },
isLoading() { isLoading() {
...@@ -127,14 +134,14 @@ export default { ...@@ -127,14 +134,14 @@ export default {
<div v-if="commit.signatureHtml" v-html="commit.signatureHtml"></div> <div v-if="commit.signatureHtml" v-html="commit.signatureHtml"></div>
<div class="ci-status-link"> <div class="ci-status-link">
<gl-link <gl-link
v-if="commit.latestPipeline" v-if="commit.pipeline"
v-gl-tooltip.left v-gl-tooltip.left
:href="commit.latestPipeline.detailedStatus.detailsPath" :href="commit.pipeline.detailedStatus.detailsPath"
:title="statusTitle" :title="statusTitle"
class="js-commit-pipeline" class="js-commit-pipeline"
> >
<ci-icon <ci-icon
:status="commit.latestPipeline.detailedStatus" :status="commit.pipeline.detailedStatus"
:size="24" :size="24"
:aria-label="statusTitle" :aria-label="statusTitle"
/> />
......
...@@ -14,13 +14,17 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) { ...@@ -14,13 +14,17 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
webUrl webUrl
} }
signatureHtml signatureHtml
latestPipeline { pipelines(ref: $ref, first: 1) {
detailedStatus { edges {
detailsPath node {
icon detailedStatus {
tooltip detailsPath
text icon
group tooltip
text
group
}
}
} }
} }
} }
......
...@@ -10,6 +10,14 @@ module Resolvers ...@@ -10,6 +10,14 @@ module Resolvers
end end
end end
def self.last
@last ||= Class.new(self) do
def resolve(**args)
super.last
end
end
end
def self.resolver_complexity(args, child_complexity:) def self.resolver_complexity(args, child_complexity:)
complexity = 1 complexity = 1
complexity += 1 if args[:sort] complexity += 1 if args[:sort]
......
# frozen_string_literal: true
module Resolvers
class CommitPipelinesResolver < BaseResolver
include ::ResolvesPipelines
alias_method :commit, :object
def resolve(**args)
resolve_pipelines(commit.project, args.merge!({ sha: commit.sha }))
end
end
end
...@@ -29,12 +29,16 @@ module Types ...@@ -29,12 +29,16 @@ module Types
field :author, type: Types::UserType, null: true, field :author, type: Types::UserType, null: true,
description: 'Author of the commit' description: 'Author of the commit'
field :pipelines, Types::Ci::PipelineType.connection_type,
null: true,
description: 'Pipelines of the commit ordered latest first',
resolver: Resolvers::CommitPipelinesResolver
field :latest_pipeline, field :latest_pipeline,
type: Types::Ci::PipelineType, type: Types::Ci::PipelineType,
null: true, null: true,
description: "Latest pipeline of the commit", description: "Latest pipeline of the commit",
resolve: -> (obj, ctx, args) do deprecation_reason: 'use pipelines',
Gitlab::Graphql::Loaders::PipelineForShaLoader.new(obj.project, obj.sha).find_last resolver: Resolvers::CommitPipelinesResolver.last
end
end end
end end
...@@ -139,13 +139,68 @@ type Commit { ...@@ -139,13 +139,68 @@ type Commit {
""" """
Latest pipeline of the commit Latest pipeline of the commit
""" """
latestPipeline: Pipeline latestPipeline(
"""
Filter pipelines by the ref they are run for
"""
ref: String
"""
Filter pipelines by the sha of the commit they are run for
"""
sha: String
"""
Filter pipelines by their status
"""
status: PipelineStatusEnum
): Pipeline @deprecated(reason: "use pipelines")
""" """
Raw commit message Raw commit message
""" """
message: String message: String
"""
Pipelines of the commit ordered latest first
"""
pipelines(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
"""
Filter pipelines by the ref they are run for
"""
ref: String
"""
Filter pipelines by the sha of the commit they are run for
"""
sha: String
"""
Filter pipelines by their status
"""
status: PipelineStatusEnum
): PipelineConnection
""" """
SHA1 ID of the commit SHA1 ID of the commit
""" """
......
# 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::GraphQL.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
...@@ -9,8 +9,6 @@ describe 'user reads pipeline status', :js do ...@@ -9,8 +9,6 @@ describe 'user reads pipeline status', :js do
let(:x110_pipeline) { create_pipeline('x1.1.0', 'failed') } let(:x110_pipeline) { create_pipeline('x1.1.0', 'failed') }
before do before do
stub_feature_flags(vue_file_list: false)
project.add_maintainer(user) project.add_maintainer(user)
project.repository.add_tag(user, 'x1.1.0', 'v1.1.0') project.repository.add_tag(user, 'x1.1.0', 'v1.1.0')
...@@ -25,7 +23,7 @@ describe 'user reads pipeline status', :js do ...@@ -25,7 +23,7 @@ describe 'user reads pipeline status', :js do
visit project_tree_path(project, expected_pipeline.ref) visit project_tree_path(project, expected_pipeline.ref)
wait_for_requests wait_for_requests
page.within('.blob-commit-info') do page.within('.commit-detail') do
expect(page).to have_link('', href: project_pipeline_path(project, expected_pipeline)) expect(page).to have_link('', href: project_pipeline_path(project, expected_pipeline))
expect(page).to have_selector(".ci-status-icon-#{expected_pipeline.status}") expect(page).to have_selector(".ci-status-icon-#{expected_pipeline.status}")
end end
......
...@@ -17,7 +17,7 @@ function createCommitData(data = {}) { ...@@ -17,7 +17,7 @@ function createCommitData(data = {}) {
avatarUrl: 'https://test.com', avatarUrl: 'https://test.com',
webUrl: 'https://test.com/test', webUrl: 'https://test.com/test',
}, },
latestPipeline: { pipeline: {
detailedStatus: { detailedStatus: {
detailsPath: 'https://test.com/pipeline', detailsPath: 'https://test.com/pipeline',
icon: 'failed', icon: 'failed',
...@@ -74,7 +74,7 @@ describe('Repository last commit component', () => { ...@@ -74,7 +74,7 @@ describe('Repository last commit component', () => {
}); });
it('hides pipeline components when pipeline does not exist', () => { it('hides pipeline components when pipeline does not exist', () => {
factory(createCommitData({ latestPipeline: null })); factory(createCommitData({ pipeline: null }));
expect(vm.find('.js-commit-pipeline').exists()).toBe(false); expect(vm.find('.js-commit-pipeline').exists()).toBe(false);
}); });
......
...@@ -13,6 +13,14 @@ describe Resolvers::BaseResolver do ...@@ -13,6 +13,14 @@ describe Resolvers::BaseResolver do
end end
end end
let(:last_resolver) do
Class.new(described_class) do
def resolve(**args)
[1, 2]
end
end
end
describe '.single' do describe '.single' do
it 'returns a subclass from the resolver' do it 'returns a subclass from the resolver' do
expect(resolver.single.superclass).to eq(resolver) expect(resolver.single.superclass).to eq(resolver)
...@@ -29,6 +37,22 @@ describe Resolvers::BaseResolver do ...@@ -29,6 +37,22 @@ describe Resolvers::BaseResolver do
end end
end end
describe '.last' do
it 'returns a subclass from the resolver' do
expect(last_resolver.last.superclass).to eq(last_resolver)
end
it 'returns the same subclass every time' do
expect(last_resolver.last.object_id).to eq(last_resolver.last.object_id)
end
it 'returns a resolver that gives the last result from the original resolver' do
result = resolve(last_resolver.last)
expect(result).to eq(2)
end
end
context 'when field is a connection' do context 'when field is a connection' do
it 'increases complexity based on arguments' do it 'increases complexity based on arguments' do
field = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE.connection_type, resolver_class: described_class, null: false, max_page_size: 1) field = Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE.connection_type, resolver_class: described_class, null: false, max_page_size: 1)
......
# frozen_string_literal: true
require 'spec_helper'
describe Resolvers::CommitPipelinesResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project) }
let(:commit) { create(:commit, project: project) }
let_it_be(:current_user) { create(:user) }
let!(:pipeline) do
create(
:ci_pipeline,
project: project,
sha: commit.id,
ref: 'master',
status: 'success'
)
end
let!(:pipeline2) do
create(
:ci_pipeline,
project: project,
sha: commit.id,
ref: 'master',
status: 'failed'
)
end
let!(:pipeline3) do
create(
:ci_pipeline,
project: project,
sha: commit.id,
ref: 'my_branch',
status: 'failed'
)
end
before do
commit.project.add_developer(current_user)
end
def resolve_pipelines
resolve(described_class, obj: commit, ctx: { current_user: current_user }, args: { ref: 'master' })
end
it 'resolves pipelines for commit and ref' do
pipelines = resolve_pipelines
expect(pipelines).to eq([pipeline2, pipeline])
end
end
...@@ -10,7 +10,7 @@ describe GitlabSchema.types['Commit'] do ...@@ -10,7 +10,7 @@ describe GitlabSchema.types['Commit'] do
it 'contains attributes related to commit' do it 'contains attributes related to commit' do
expect(described_class).to have_graphql_fields( expect(described_class).to have_graphql_fields(
:id, :sha, :title, :description, :message, :authored_date, :id, :sha, :title, :description, :message, :authored_date,
:author, :web_url, :latest_pipeline, :signature_html :author, :web_url, :latest_pipeline, :pipelines, :signature_html
) )
end end
end end
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_sync(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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment