diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb index 447528917f0428ebd48f3419dcdcc0be9548ea69..79bc7dcb17c7b56fdf66f86e07fe4b521ad886b5 100644 --- a/app/graphql/types/milestone_type.rb +++ b/app/graphql/types/milestone_type.rb @@ -29,6 +29,9 @@ class MilestoneType < BaseObject field :expired, GraphQL::Types::Boolean, null: false, description: 'Expired state of the milestone (a milestone is expired when the due date is past the current date). Defaults to `false` when due date has not been set.' + field :upcoming, GraphQL::Types::Boolean, null: false, + description: 'Upcoming state of the milestone (a milestone is upcoming when the start date is in the future). Defaults to `false` when start date has not been set.' + field :web_path, GraphQL::Types::String, null: false, method: :milestone_path, description: 'Web path of the milestone.' @@ -44,10 +47,14 @@ class MilestoneType < BaseObject field :updated_at, Types::TimeType, null: false, description: 'Timestamp of last milestone update.' + field :project, Types::ProjectType, null: true, description: 'Project of the milestone.' + field :project_milestone, GraphQL::Types::Boolean, null: false, description: 'Indicates if milestone is at project level.', method: :project_milestone? + field :group, Types::GroupType, null: true, description: 'Group of the milestone.' + field :group_milestone, GraphQL::Types::Boolean, null: false, description: 'Indicates if milestone is at group level.', method: :group_milestone? diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb index 3d9e09acf44e0fd479a6dfcbd9d9c852b261d352..33d11936c6e7d5653942934c35e21497fb9a6d60 100644 --- a/app/models/concerns/milestoneish.rb +++ b/app/models/concerns/milestoneish.rb @@ -88,6 +88,10 @@ def upcoming? start_date && start_date.future? end + def upcoming + upcoming? || false + end + def expires_at if due_date if due_date.past? diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index a0fbc616cb58c6c28db47724e8c4a15c0a3ebb71..26c59d84edb36a4901e6b439196edf4b7a956f63 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -24204,9 +24204,11 @@ Represents a milestone. | <a id="milestonedescription"></a>`description` | [`String`](#string) | Description of the milestone. | | <a id="milestoneduedate"></a>`dueDate` | [`Time`](#time) | Timestamp of the milestone due date. | | <a id="milestoneexpired"></a>`expired` | [`Boolean!`](#boolean) | Expired state of the milestone (a milestone is expired when the due date is past the current date). Defaults to `false` when due date has not been set. | +| <a id="milestonegroup"></a>`group` | [`Group`](#group) | Group of the milestone. | | <a id="milestonegroupmilestone"></a>`groupMilestone` | [`Boolean!`](#boolean) | Indicates if milestone is at group level. | | <a id="milestoneid"></a>`id` | [`ID!`](#id) | ID of the milestone. | | <a id="milestoneiid"></a>`iid` | [`ID!`](#id) | Internal ID of the milestone. | +| <a id="milestoneproject"></a>`project` | [`Project`](#project) | Project of the milestone. | | <a id="milestoneprojectmilestone"></a>`projectMilestone` | [`Boolean!`](#boolean) | Indicates if milestone is at project level. | | <a id="milestonereleases"></a>`releases` | [`ReleaseConnection`](#releaseconnection) | Releases associated with this milestone. (see [Connections](#connections)) | | <a id="milestonestartdate"></a>`startDate` | [`Time`](#time) | Timestamp of the milestone start date. | @@ -24214,6 +24216,7 @@ Represents a milestone. | <a id="milestonestats"></a>`stats` | [`MilestoneStats`](#milestonestats) | Milestone statistics. | | <a id="milestonesubgroupmilestone"></a>`subgroupMilestone` | [`Boolean!`](#boolean) | Indicates if milestone is at subgroup level. | | <a id="milestonetitle"></a>`title` | [`String!`](#string) | Title of the milestone. | +| <a id="milestoneupcoming"></a>`upcoming` | [`Boolean!`](#boolean) | Upcoming state of the milestone (a milestone is upcoming when the start date is in the future). Defaults to `false` when start date has not been set. | | <a id="milestoneupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of last milestone update. | | <a id="milestonewebpath"></a>`webPath` | [`String!`](#string) | Web path of the milestone. | diff --git a/spec/graphql/types/milestone_type_spec.rb b/spec/graphql/types/milestone_type_spec.rb index f00acb3f7cf76980fbeaa4049c008e334a4b6121..8eadc1ddd874460e3a0a85b16b8d65e1f378ba64 100644 --- a/spec/graphql/types/milestone_type_spec.rb +++ b/spec/graphql/types/milestone_type_spec.rb @@ -9,9 +9,9 @@ it 'has the expected fields' do expected_fields = %w[ - id iid title description state expired web_path + id iid title description state expired upcoming web_path due_date start_date created_at updated_at - project_milestone group_milestone subgroup_milestone + project project_milestone group group_milestone subgroup_milestone stats ] diff --git a/spec/requests/api/graphql/milestone_spec.rb b/spec/requests/api/graphql/milestone_spec.rb index 3c5f29f05293ab6abef7e819d99bb9fa1e95e217..a2c226a0fe6649b2217809bed5c44a83d395802a 100644 --- a/spec/requests/api/graphql/milestone_spec.rb +++ b/spec/requests/api/graphql/milestone_spec.rb @@ -40,7 +40,11 @@ context 'when we post the query' do context 'and the project is private' do let(:query) do - graphql_query_for('milestone', { id: milestone.to_global_id.to_s }, all_graphql_fields_for('Milestone')) + graphql_query_for( + 'milestone', + { id: milestone.to_global_id.to_s }, + all_graphql_fields_for('Milestone', excluded: %w[project group]) + ) end subject { graphql_data['milestone'] } @@ -55,6 +59,15 @@ it_behaves_like 'returns the milestone successfully' + context 'when milestone has no dates' do + it 'returns upcoming and expired as false' do + expect(graphql_data_at(:milestone, :due_date)).to be_nil + expect(graphql_data_at(:milestone, :start_date)).to be_nil + expect(graphql_data_at(:milestone, :upcoming)).to be false + expect(graphql_data_at(:milestone, :expired)).to be false + end + end + context 'when there are two milestones' do let_it_be(:milestone_b) { create(:milestone, project: project) }