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 # frozen_string_literal: true
module Resolvers module Resolvers
class GroupMilestoneResolver < MilestoneResolver class GroupMilestonesResolver < MilestonesResolver
argument :include_descendants, GraphQL::BOOLEAN_TYPE, argument :include_descendants, GraphQL::BOOLEAN_TYPE,
required: false, required: false,
description: 'Also return milestones in all subgroups and subprojects' description: 'Also return milestones in all subgroups and subprojects'
private private
......
# frozen_string_literal: true # frozen_string_literal: true
module Resolvers module Resolvers
class MilestoneResolver < BaseResolver class MilestonesResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource include Gitlab::Graphql::Authorize::AuthorizeResource
include TimeFrameArguments include TimeFrameArguments
argument :ids, [GraphQL::ID_TYPE], argument :ids, [GraphQL::ID_TYPE],
required: false, required: false,
description: 'Array of global milestone IDs, e.g., "gid://gitlab/Milestone/1"' description: 'Array of global milestone IDs, e.g., "gid://gitlab/Milestone/1"'
argument :state, Types::MilestoneStateEnum, argument :state, Types::MilestoneStateEnum,
required: false, required: false,
description: 'Filter milestones by state' description: 'Filter milestones by state'
type Types::MilestoneType, null: true type Types::MilestoneType, null: true
...@@ -35,7 +35,7 @@ module Resolvers ...@@ -35,7 +35,7 @@ module Resolvers
end end
def parent def parent
@parent ||= object.respond_to?(:sync) ? object.sync : object synchronized_object
end end
def parent_id_parameters(args) def parent_id_parameters(args)
......
# frozen_string_literal: true # frozen_string_literal: true
module Resolvers module Resolvers
class ProjectMilestoneResolver < MilestoneResolver class ProjectMilestonesResolver < MilestonesResolver
argument :include_ancestors, GraphQL::BOOLEAN_TYPE, argument :include_ancestors, GraphQL::BOOLEAN_TYPE,
required: false, required: false,
description: "Also return milestones in the project's parent group and its ancestors" description: "Also return milestones in the project's parent group and its ancestors"
private private
......
...@@ -51,7 +51,7 @@ module Types ...@@ -51,7 +51,7 @@ module Types
field :milestones, Types::MilestoneType.connection_type, null: true, field :milestones, Types::MilestoneType.connection_type, null: true,
description: 'Milestones of the group', description: 'Milestones of the group',
resolver: Resolvers::GroupMilestoneResolver resolver: Resolvers::GroupMilestonesResolver
field :boards, field :boards,
Types::BoardType.connection_type, Types::BoardType.connection_type,
......
...@@ -150,7 +150,7 @@ module Types ...@@ -150,7 +150,7 @@ module Types
field :milestones, Types::MilestoneType.connection_type, null: true, field :milestones, Types::MilestoneType.connection_type, null: true,
description: 'Milestones of the project', description: 'Milestones of the project',
resolver: Resolvers::ProjectMilestoneResolver resolver: Resolvers::ProjectMilestonesResolver
field :project_members, field :project_members,
Types::ProjectMemberType.connection_type, Types::ProjectMemberType.connection_type,
......
...@@ -47,6 +47,15 @@ module Types ...@@ -47,6 +47,15 @@ module Types
null: false, null: false,
description: 'Fields related to design management' 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, field :user, Types::UserType,
null: true, null: true,
description: 'Find a user', description: 'Find a user',
......
---
title: Add GraphQL query for a single milestone
merge_request: 38682
author:
type: added
...@@ -8960,6 +8960,11 @@ type MilestoneEdge { ...@@ -8960,6 +8960,11 @@ type MilestoneEdge {
node: Milestone node: Milestone
} }
"""
Identifier of Milestone
"""
scalar MilestoneID
enum MilestoneStateEnum { enum MilestoneStateEnum {
active active
closed closed
...@@ -11621,6 +11626,16 @@ type Query { ...@@ -11621,6 +11626,16 @@ type Query {
""" """
metadata: Metadata metadata: Metadata
"""
Find a milestone
"""
milestone(
"""
Find a milestone by its ID
"""
id: MilestoneID!
): Milestone
""" """
Find a namespace Find a namespace
""" """
......
...@@ -25146,6 +25146,16 @@ ...@@ -25146,6 +25146,16 @@
"enumValues": null, "enumValues": null,
"possibleTypes": null "possibleTypes": null
}, },
{
"kind": "SCALAR",
"name": "MilestoneID",
"description": "Identifier of Milestone",
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{ {
"kind": "ENUM", "kind": "ENUM",
"name": "MilestoneStateEnum", "name": "MilestoneStateEnum",
...@@ -34301,6 +34311,33 @@ ...@@ -34301,6 +34311,33 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "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", "name": "namespace",
"description": "Find a namespace", "description": "Find a namespace",
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Resolvers::GroupMilestoneResolver do RSpec.describe Resolvers::GroupMilestonesResolver do
include GraphqlHelpers include GraphqlHelpers
describe '#resolve' do describe '#resolve' do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Resolvers::ProjectMilestoneResolver do RSpec.describe Resolvers::ProjectMilestonesResolver do
include GraphqlHelpers include GraphqlHelpers
describe '#resolve' do describe '#resolve' do
......
...@@ -17,6 +17,7 @@ RSpec.describe GitlabSchema.types['Query'] do ...@@ -17,6 +17,7 @@ RSpec.describe GitlabSchema.types['Query'] do
current_user current_user
snippets snippets
design_management design_management
milestone
user user
users 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