Commit e558ef90 authored by Eulyeon Ko's avatar Eulyeon Ko

Expose iteration ordinal number via APIs

When a cadence's iterations are sorted by start or due date,
each iteration's numerical position is its ordinal number.
The earliest starting/ending iteration's ordinal number is assigned 1.

Changelog: added
EE: true
parent 58e8d463
...@@ -11527,6 +11527,7 @@ Represents an iteration object. ...@@ -11527,6 +11527,7 @@ Represents an iteration object.
| <a id="iterationid"></a>`id` | [`ID!`](#id) | ID of the iteration. | | <a id="iterationid"></a>`id` | [`ID!`](#id) | ID of the iteration. |
| <a id="iterationiid"></a>`iid` | [`ID!`](#id) | Internal ID of the iteration. | | <a id="iterationiid"></a>`iid` | [`ID!`](#id) | Internal ID of the iteration. |
| <a id="iterationiterationcadence"></a>`iterationCadence` | [`IterationCadence!`](#iterationcadence) | Cadence of the iteration. | | <a id="iterationiterationcadence"></a>`iterationCadence` | [`IterationCadence!`](#iterationcadence) | Cadence of the iteration. |
| <a id="iterationordinalnumber"></a>`ordinalNumber` | [`Int!`](#int) | Ordinal number of the iteration. The number represents the iteration's numerical position when the cadence's iterations are sorted by the start and end date. The earliest starting and ending iteration is assigned 1. |
| <a id="iterationreport"></a>`report` | [`TimeboxReport`](#timeboxreport) | Historically accurate report about the timebox. | | <a id="iterationreport"></a>`report` | [`TimeboxReport`](#timeboxreport) | Historically accurate report about the timebox. |
| <a id="iterationscopedpath"></a>`scopedPath` | [`String`](#string) | Web path of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts. | | <a id="iterationscopedpath"></a>`scopedPath` | [`String`](#string) | Web path of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts. |
| <a id="iterationscopedurl"></a>`scopedUrl` | [`String`](#string) | Web URL of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts. | | <a id="iterationscopedurl"></a>`scopedUrl` | [`String`](#string) | Web URL of the iteration, scoped to the query parent. Only valid for Project parents. Returns null in other contexts. |
...@@ -43,6 +43,7 @@ Example response: ...@@ -43,6 +43,7 @@ Example response:
{ {
"id": 53, "id": 53,
"iid": 13, "iid": 13,
"ordinal_number": 1,
"group_id": 5, "group_id": 5,
"title": "Iteration II", "title": "Iteration II",
"description": "Ipsum Lorem ipsum", "description": "Ipsum Lorem ipsum",
......
...@@ -17,6 +17,9 @@ module Types ...@@ -17,6 +17,9 @@ module Types
field :iid, GraphQL::Types::ID, null: false, field :iid, GraphQL::Types::ID, null: false,
description: 'Internal ID of the iteration.' description: 'Internal ID of the iteration.'
field :ordinal_number, GraphQL::Types::Int, method: :sequence, null: false,
description: "Ordinal number of the iteration. The number represents the iteration's numerical position when the cadence's iterations are sorted by the start and end date. The earliest starting and ending iteration is assigned 1."
field :title, GraphQL::Types::String, null: false, field :title, GraphQL::Types::String, null: false,
description: 'Title of the iteration.' description: 'Title of the iteration.'
......
...@@ -4,6 +4,7 @@ module API ...@@ -4,6 +4,7 @@ module API
module Entities module Entities
class Iteration < Grape::Entity class Iteration < Grape::Entity
expose :id, :iid expose :id, :iid
expose :sequence, as: :ordinal_number
expose :project_id, if: -> (entity, options) { entity&.project_id } expose :project_id, if: -> (entity, options) { entity&.project_id }
expose :group_id, if: -> (entity, options) { entity&.group_id } expose :group_id, if: -> (entity, options) { entity&.group_id }
expose :title, :description expose :title, :description
......
...@@ -9,7 +9,7 @@ RSpec.describe GitlabSchema.types['Iteration'] do ...@@ -9,7 +9,7 @@ RSpec.describe GitlabSchema.types['Iteration'] do
it 'has the expected fields' do it 'has the expected fields' do
expected_fields = %w[ expected_fields = %w[
id id title description state web_path web_url scoped_path scoped_url id iid ordinal_number title description state web_path web_url scoped_path scoped_url
due_date start_date created_at updated_at report iteration_cadence due_date start_date created_at updated_at report iteration_cadence
] ]
......
...@@ -25,12 +25,13 @@ RSpec.describe API::Iterations do ...@@ -25,12 +25,13 @@ RSpec.describe API::Iterations do
end end
context 'when user has access' do context 'when user has access' do
it 'returns a list of iterations' do it 'returns a list of iterations', :aggregate_failures do
get api(api_path, user) get api(api_path, user)
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(json_response.size).to eq(3) expect(json_response.size).to eq(3)
expect(json_response.map { |i| i['id'] }).to contain_exactly(current_iteration.id, closed_iteration.id, ancestor_iteration.id) expect(json_response.map { |i| i['id'] }).to contain_exactly(current_iteration.id, closed_iteration.id, ancestor_iteration.id)
expect(json_response.map { |i| i['ordinal_number'] }.compact).to contain_exactly(current_iteration.sequence, closed_iteration.sequence, ancestor_iteration.sequence)
end end
context 'filter by iteration state' do context 'filter by iteration state' do
......
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