Commit 1166c2b8 authored by Alex Kalderimis's avatar Alex Kalderimis

Merge branch 'pb-add-jobs-field-to-project-type' into 'master'

Add jobs field to project type

See merge request gitlab-org/gitlab!57376
parents d9737d72 1446d1c7
# frozen_string_literal: true
module Resolvers
class ProjectJobsResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
include LooksAhead
type ::Types::Ci::JobType.connection_type, null: true
authorize :read_build
authorizes_object!
argument :statuses, [::Types::Ci::JobStatusEnum],
required: false,
description: 'Filter jobs by status.'
alias_method :project, :object
def ready?(**args)
context[self.class] ||= { executions: 0 }
context[self.class][:executions] += 1
raise GraphQL::ExecutionError, "Jobs can only be requested for one project at a time" if context[self.class][:executions] > 1
super
end
def resolve_with_lookahead(statuses: nil)
jobs = ::Ci::JobsFinder.new(current_user: current_user, project: project, params: { scope: statuses }).execute
apply_lookahead(jobs)
end
private
def preloads
{
artifacts: [:job_artifacts],
pipeline: [:user]
}
end
end
end
...@@ -183,6 +183,12 @@ module Types ...@@ -183,6 +183,12 @@ module Types
description: 'Packages of the project.', description: 'Packages of the project.',
resolver: Resolvers::ProjectPackagesResolver resolver: Resolvers::ProjectPackagesResolver
field :jobs,
Types::Ci::JobType.connection_type,
null: true,
description: 'Jobs of a project. This field can only be resolved for one project in any single request.',
resolver: Resolvers::ProjectJobsResolver
field :pipelines, field :pipelines,
null: true, null: true,
description: 'Build pipelines of the project.', description: 'Build pipelines of the project.',
......
---
title: Add jobs field to the project type
merge_request: 57376
author:
type: added
...@@ -4835,6 +4835,7 @@ An edge in a connection. ...@@ -4835,6 +4835,7 @@ An edge in a connection.
| `iterations` | [`IterationConnection`](#iterationconnection) | Find iterations. | | `iterations` | [`IterationConnection`](#iterationconnection) | Find iterations. |
| `jiraImportStatus` | [`String`](#string) | Status of Jira import background job of the project. | | `jiraImportStatus` | [`String`](#string) | Status of Jira import background job of the project. |
| `jiraImports` | [`JiraImportConnection`](#jiraimportconnection) | Jira imports into the project. | | `jiraImports` | [`JiraImportConnection`](#jiraimportconnection) | Jira imports into the project. |
| `jobs` | [`CiJobConnection`](#cijobconnection) | Jobs of a project. This field can only be resolved for one project in any single request. |
| `jobsEnabled` | [`Boolean`](#boolean) | Indicates if CI/CD pipeline jobs are enabled for the current user. | | `jobsEnabled` | [`Boolean`](#boolean) | Indicates if CI/CD pipeline jobs are enabled for the current user. |
| `label` | [`Label`](#label) | A label available on this project. | | `label` | [`Label`](#label) | A label available on this project. |
| `labels` | [`LabelConnection`](#labelconnection) | Labels available on this project. | | `labels` | [`LabelConnection`](#labelconnection) | Labels available on this project. |
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::ProjectJobsResolver do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
let_it_be(:irrelevant_project) { create(:project, :repository) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let_it_be(:irrelevant_pipeline) { create(:ci_pipeline, project: irrelevant_project) }
let_it_be(:build_one) { create(:ci_build, :success, name: 'Build One', pipeline: pipeline) }
let_it_be(:build_two) { create(:ci_build, :success, name: 'Build Two', pipeline: pipeline) }
let_it_be(:build_three) { create(:ci_build, :failed, name: 'Build Three', pipeline: pipeline) }
let(:irrelevant_build) { create(:ci_build, name: 'Irrelevant Build', pipeline: irrelevant_pipeline)}
let(:args) { {} }
let(:current_user) { create(:user) }
subject { resolve_jobs(args) }
describe '#resolve' do
context 'with authorized user' do
before do
project.add_developer(current_user)
end
context 'with statuses argument' do
let(:args) { { statuses: [Types::Ci::JobStatusEnum.coerce_isolated_input('SUCCESS')] } }
it { is_expected.to contain_exactly(build_one, build_two) }
end
context 'without statuses argument' do
it { is_expected.to contain_exactly(build_one, build_two, build_three) }
end
end
context 'with unauthorized user' do
let(:current_user) { nil }
it { is_expected.to be_nil }
end
end
private
def resolve_jobs(args = {}, context = { current_user: current_user })
resolve(described_class, obj: project, args: args, ctx: context)
end
end
...@@ -371,4 +371,11 @@ RSpec.describe GitlabSchema.types['Project'] do ...@@ -371,4 +371,11 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_type(Types::Ci::AnalyticsType) } it { is_expected.to have_graphql_type(Types::Ci::AnalyticsType) }
it { is_expected.to have_graphql_resolver(Resolvers::ProjectPipelineStatisticsResolver) } it { is_expected.to have_graphql_resolver(Resolvers::ProjectPipelineStatisticsResolver) }
end end
describe 'jobs field' do
subject { described_class.fields['jobs'] }
it { is_expected.to have_graphql_type(Types::Ci::JobType.connection_type) }
it { is_expected.to have_graphql_arguments(:statuses) }
end
end end
...@@ -16,7 +16,7 @@ RSpec.describe 'getting container repositories in a project' do ...@@ -16,7 +16,7 @@ RSpec.describe 'getting container repositories in a project' do
<<~GQL <<~GQL
edges { edges {
node { node {
#{all_graphql_fields_for('container_repositories'.classify, excluded: ['pipeline'])} #{all_graphql_fields_for('container_repositories'.classify, excluded: %w(pipeline jobs))}
} }
} }
GQL GQL
......
...@@ -9,7 +9,7 @@ RSpec.describe 'getting merge request information nested in a project' do ...@@ -9,7 +9,7 @@ RSpec.describe 'getting merge request information nested in a project' do
let(:current_user) { create(:user) } let(:current_user) { create(:user) }
let(:merge_request_graphql_data) { graphql_data['project']['mergeRequest'] } let(:merge_request_graphql_data) { graphql_data['project']['mergeRequest'] }
let!(:merge_request) { create(:merge_request, source_project: project) } let!(:merge_request) { create(:merge_request, source_project: project) }
let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: ['pipeline']) } let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: %w(pipeline jobs)) }
let(:query) do let(:query) do
graphql_query_for( graphql_query_for(
......
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