Commit 2c229f97 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Merge branch '347527-no-way-to-access-parent-epic-from-epic-api-details' into 'master'

feat: Include epic parent_iid when epic has a parent

See merge request gitlab-org/gitlab!76443
parents a898ae32 16c439ad
......@@ -49,6 +49,8 @@ NOTE:
## List epics for a group
> `parent_iid` and `_links[parent]` in response were [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/347527) in GitLab 14.6.
Gets all epics of the requested group and its subgroups.
```plaintext
......@@ -89,6 +91,7 @@ Example response:
"iid": 4,
"group_id": 7,
"parent_id": 23,
"parent_iid": 3,
"title": "Accusamus iste et ullam ratione voluptatem omnis debitis dolor est.",
"description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.",
"state": "opened",
......@@ -128,7 +131,8 @@ Example response:
"_links":{
"self": "http://gitlab.example.com/api/v4/groups/7/epics/4",
"epic_issues": "http://gitlab.example.com/api/v4/groups/7/epics/4/issues",
"group":"http://gitlab.example.com/api/v4/groups/7"
"group":"http://gitlab.example.com/api/v4/groups/7",
"parent":"http://gitlab.example.com/api/v4/groups/7/epics/3"
}
},
{
......@@ -136,6 +140,7 @@ Example response:
"iid": 35,
"group_id": 17,
"parent_id": 19,
"parent_iid": 1,
"title": "Accusamus iste et ullam ratione voluptatem omnis debitis dolor est.",
"description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.",
"state": "opened",
......@@ -174,7 +179,8 @@ Example response:
"_links":{
"self": "http://gitlab.example.com/api/v4/groups/17/epics/35",
"epic_issues": "http://gitlab.example.com/api/v4/groups/17/epics/35/issues",
"group":"http://gitlab.example.com/api/v4/groups/17"
"group":"http://gitlab.example.com/api/v4/groups/17",
"parent":"http://gitlab.example.com/api/v4/groups/17/epics/1"
}
}
]
......@@ -182,6 +188,8 @@ Example response:
## Single epic
> `parent_iid` and `_links[parent]` in response were [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/347527) in GitLab 14.6.
Gets a single epic
```plaintext
......@@ -204,6 +212,8 @@ Example response:
"id": 30,
"iid": 5,
"group_id": 7,
"parent_id": null,
"parent_iid": null,
"title": "Ea cupiditate dolores ut vero consequatur quasi veniam voluptatem et non.",
"description": "Molestias dolorem eos vitae expedita impedit necessitatibus quo voluptatum.",
"state": "opened",
......@@ -243,13 +253,16 @@ Example response:
"_links":{
"self": "http://gitlab.example.com/api/v4/groups/7/epics/5",
"epic_issues": "http://gitlab.example.com/api/v4/groups/7/epics/5/issues",
"group":"http://gitlab.example.com/api/v4/groups/7"
"group":"http://gitlab.example.com/api/v4/groups/7",
"parent": null
}
}
```
## New epic
> `parent_iid` and `_links[parent]` in response were [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/347527) in GitLab 14.6.
Creates a new epic.
NOTE:
......@@ -276,7 +289,7 @@ POST /groups/:id/epics
| `parent_id` | integer/string | no | The ID of a parent epic (in GitLab 11.11 and later) |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/epics?title=Epic&description=Epic%20description"
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/epics?title=Epic&description=Epic%20description&parent_id=29"
```
Example response:
......@@ -286,6 +299,8 @@ Example response:
"id": 33,
"iid": 6,
"group_id": 7,
"parent_id": 29,
"parent_iid": 4,
"title": "Epic",
"description": "Epic description",
"state": "opened",
......@@ -325,13 +340,16 @@ Example response:
"_links":{
"self": "http://gitlab.example.com/api/v4/groups/7/epics/6",
"epic_issues": "http://gitlab.example.com/api/v4/groups/7/epics/6/issues",
"group":"http://gitlab.example.com/api/v4/groups/7"
"group":"http://gitlab.example.com/api/v4/groups/7",
"parent": "http://gitlab.example.com/api/v4/groups/7/epics/4"
}
}
```
## Update epic
> `parent_iid` and `_links[parent]` in response were [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/347527) in GitLab 14.6.
Updates an epic.
NOTE:
......@@ -371,6 +389,8 @@ Example response:
"id": 33,
"iid": 6,
"group_id": 7,
"parent_id": null,
"parent_iid": null,
"title": "New Title",
"description": "Epic description",
"state": "opened",
......
......@@ -137,7 +137,7 @@ module EE
where(boards_epic_board_positions: { relative_position: nil })
end
scope :with_api_entity_associations, -> { preload(:author, :labels, group: :route) }
scope :with_api_entity_associations, -> { preload(:author, :labels, :parent, group: :route) }
scope :start_date_inherited, -> { where(start_date_is_fixed: [nil, false]) }
scope :due_date_inherited, -> { where(due_date_is_fixed: [nil, false]) }
......
......@@ -12,6 +12,9 @@ module EE
expose :iid
expose :group_id
expose :parent_id
expose :parent_iid do |epic|
epic.parent.iid if epic.has_parent?
end
expose :title
expose :description
expose :confidential
......@@ -92,6 +95,10 @@ module EE
expose :group do |epic|
expose_url(api_v4_groups_path(id: epic.group_id))
end
expose :parent do |epic|
expose_url(api_v4_groups_epics_path(id: epic.parent.group_id, epic_iid: epic.parent.iid)) if epic.has_parent?
end
end
end
end
......
......@@ -5,6 +5,7 @@
"iid": { "type": "integer" },
"group_id": { "type": "integer" },
"parent_id": { "type": ["integer", "null"] },
"parent_iid": { "type": ["integer", "null"] },
"title": { "type": "string" },
"description": { "type": ["string", "null"] },
"confidential": { "type": "boolean" },
......@@ -58,6 +59,7 @@
"self": { "type": "uri" },
"epic_issues": { "type": "uri" },
"group": { "type": "uri" },
"parent": { "type": "uri" },
"additionalProperties": false
}
}
......
......@@ -96,8 +96,8 @@ RSpec.describe API::Epics do
pat = create(:personal_access_token, user: user)
subgroup_1 = create(:group, parent: group)
subgroup_2 = create(:group, parent: subgroup_1)
create(:epic, group: subgroup_1)
create(:epic, group: subgroup_2)
epic1 = create(:epic, group: subgroup_1)
epic2 = create(:epic, group: subgroup_2, parent_id: epic.id)
control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
get api(url, personal_access_token: pat), params: params
......@@ -105,6 +105,8 @@ RSpec.describe API::Epics do
label_2 = create(:label)
create_list(:labeled_epic, 2, group: group, labels: [label_2])
create_list(:epic, 2, group: subgroup_1, parent_id: epic1.id)
create_list(:epic, 2, group: subgroup_2, parent_id: epic2.id)
expect { get api(url, personal_access_token: pat), params: params }.not_to exceed_all_query_limit(control)
expect(response).to have_gitlab_http_status(:ok)
......@@ -156,6 +158,24 @@ RSpec.describe API::Epics do
end
end
context 'with a parent epic' do
let!(:epic) { create(:epic, group: group) }
let!(:epic2) { create(:epic, group: group, parent_id: epic.id) }
before do
stub_licensed_features(epics: true)
end
it 'returns parent_id and parent_iid' do
get api(url, user)
epics = json_response
expect(epics.map { |e| e["parent_id"] }).to match_array([nil, epic.id])
expect(epics.map { |e| e["parent_iid"] }).to match_array([nil, epic.iid])
end
end
context 'with multiple epics' do
let(:user2) { create(:user) }
let!(:epic) do
......@@ -569,6 +589,20 @@ RSpec.describe API::Epics do
expect(links['self']).to end_with("/api/v4/groups/#{epic.group.id}/epics/#{epic.iid}")
expect(links['epic_issues']).to end_with("/api/v4/groups/#{epic.group.id}/epics/#{epic.iid}/issues")
expect(links['group']).to end_with("/api/v4/groups/#{epic.group.id}")
expect(links['parent']).to eq(nil)
end
context 'with a parent epic' do
let!(:epic2) { create(:epic, group: group, parent_id: epic.id) }
let(:url) { "/groups/#{group.path}/epics/#{epic2.iid}" }
it 'exposes parent link' do
get api(url)
links = json_response['_links']
expect(links['parent']).to end_with("/api/v4/groups/#{epic.group.id}/epics/#{epic.iid}")
end
end
it_behaves_like 'can admin epics'
......@@ -619,6 +653,14 @@ RSpec.describe API::Epics do
expect(response).to match_response_schema('public_api/v4/epic', dir: 'ee')
end
it 'exposes parent information' do
post api(url, user), params: params
expect(json_response['parent_id']).to eq(parent_epic.id)
expect(json_response['parent_iid']).to eq(parent_epic.iid)
expect(json_response['_links']['parent']).to end_with("/api/v4/groups/#{parent_epic.group.id}/epics/#{parent_epic.iid}")
end
it 'creates a new epic' do
epic = Epic.last
......
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