Commit e5d666a7 authored by Vitali Tatarintev's avatar Vitali Tatarintev

Merge branch 'graphql-milestones-top-level' into 'master'

Add top-level GraphQL query for a single milestone

See merge request gitlab-org/gitlab!38682
parents 38d58208 b24dd21e
# frozen_string_literal: true
module Resolvers
class GroupMilestoneResolver < MilestoneResolver
class GroupMilestonesResolver < MilestonesResolver
argument :include_descendants, GraphQL::BOOLEAN_TYPE,
required: false,
description: 'Also return milestones in all subgroups and subprojects'
required: false,
description: 'Also return milestones in all subgroups and subprojects'
private
......
# frozen_string_literal: true
module Resolvers
class MilestoneResolver < BaseResolver
class MilestonesResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
include TimeFrameArguments
argument :ids, [GraphQL::ID_TYPE],
required: false,
description: 'Array of global milestone IDs, e.g., "gid://gitlab/Milestone/1"'
required: false,
description: 'Array of global milestone IDs, e.g., "gid://gitlab/Milestone/1"'
argument :state, Types::MilestoneStateEnum,
required: false,
description: 'Filter milestones by state'
required: false,
description: 'Filter milestones by state'
type Types::MilestoneType, null: true
......@@ -35,7 +35,7 @@ module Resolvers
end
def parent
@parent ||= object.respond_to?(:sync) ? object.sync : object
synchronized_object
end
def parent_id_parameters(args)
......
# frozen_string_literal: true
module Resolvers
class ProjectMilestoneResolver < MilestoneResolver
class ProjectMilestonesResolver < MilestonesResolver
argument :include_ancestors, GraphQL::BOOLEAN_TYPE,
required: false,
description: "Also return milestones in the project's parent group and its ancestors"
required: false,
description: "Also return milestones in the project's parent group and its ancestors"
private
......
......@@ -51,7 +51,7 @@ module Types
field :milestones, Types::MilestoneType.connection_type, null: true,
description: 'Milestones of the group',
resolver: Resolvers::GroupMilestoneResolver
resolver: Resolvers::GroupMilestonesResolver
field :boards,
Types::BoardType.connection_type,
......
......@@ -150,7 +150,7 @@ module Types
field :milestones, Types::MilestoneType.connection_type, null: true,
description: 'Milestones of the project',
resolver: Resolvers::ProjectMilestoneResolver
resolver: Resolvers::ProjectMilestonesResolver
field :project_members,
Types::ProjectMemberType.connection_type,
......
......@@ -47,6 +47,15 @@ module Types
null: false,
description: 'Fields related to design management'
field :milestone, ::Types::MilestoneType,
null: true,
description: 'Find a milestone',
resolve: -> (_obj, args, _ctx) { GitlabSchema.find_by_gid(args[:id]) } do
argument :id, ::Types::GlobalIDType[Milestone],
required: true,
description: 'Find a milestone by its ID'
end
field :user, Types::UserType,
null: true,
description: 'Find a user',
......
---
title: Add GraphQL query for a single milestone
merge_request: 38682
author:
type: added
......@@ -8960,6 +8960,11 @@ type MilestoneEdge {
node: Milestone
}
"""
Identifier of Milestone
"""
scalar MilestoneID
enum MilestoneStateEnum {
active
closed
......@@ -11621,6 +11626,16 @@ type Query {
"""
metadata: Metadata
"""
Find a milestone
"""
milestone(
"""
Find a milestone by its ID
"""
id: MilestoneID!
): Milestone
"""
Find a namespace
"""
......
......@@ -25146,6 +25146,16 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "SCALAR",
"name": "MilestoneID",
"description": "Identifier of Milestone",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "ENUM",
"name": "MilestoneStateEnum",
......@@ -34301,6 +34311,33 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "milestone",
"description": "Find a milestone",
"args": [
{
"name": "id",
"description": "Find a milestone by its ID",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "MilestoneID",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "Milestone",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "namespace",
"description": "Find a namespace",
......@@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Resolvers::GroupMilestoneResolver do
RSpec.describe Resolvers::GroupMilestonesResolver do
include GraphqlHelpers
describe '#resolve' do
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Resolvers::ProjectMilestoneResolver do
RSpec.describe Resolvers::ProjectMilestonesResolver do
include GraphqlHelpers
describe '#resolve' do
......
......@@ -17,6 +17,7 @@ RSpec.describe GitlabSchema.types['Query'] do
current_user
snippets
design_management
milestone
user
users
]
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Querying a Milestone' do
include GraphqlHelpers
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:milestone) { create(:milestone, project: project) }
let(:query) do
graphql_query_for('milestone', { id: milestone.to_global_id.to_s }, 'title')
end
subject { graphql_data['milestone'] }
before do
post_graphql(query, current_user: current_user)
end
context 'when the user has access to the milestone' do
before_all do
project.add_guest(current_user)
end
it_behaves_like 'a working graphql query'
it { is_expected.to include('title' => milestone.name) }
end
context 'when the user does not have access to the milestone' do
it_behaves_like 'a working graphql query'
it { is_expected.to be_nil }
end
context 'when ID argument is missing' do
let(:query) do
graphql_query_for('milestone', {}, 'title')
end
it 'raises an exception' do
expect(graphql_errors).to include(a_hash_including('message' => "Field 'milestone' is missing required arguments: id"))
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