Commit 86111ba9 authored by James Lopez's avatar James Lopez

Merge branch 'georgekoltsov/add-board-lists' into 'master'

Add Board Lists to Group Export

See merge request gitlab-org/gitlab!24863
parents cd4a5674 9d2c7938
---
title: Add Board Lists to Group Export
merge_request: 24863
author:
type: changed
{
"name": "ymg09t5704clnxnqfgaj2h098gz4r7gyx4wc3fzmlqj1en24zf",
"path": "ymg09t5704clnxnqfgaj2h098gz4r7gyx4wc3fzmlqj1en24zf",
"owner_id": null,
"created_at": "2019-11-20 17:01:53 UTC",
"updated_at": "2019-11-20 17:05:44 UTC",
"description": "Group Description",
"avatar": {
"url": null
},
"membership_lock": false,
"share_with_group_lock": false,
"visibility_level": 0,
"request_access_enabled": true,
"ldap_sync_status": "ready",
"ldap_sync_error": null,
"ldap_sync_last_update_at": null,
"ldap_sync_last_successful_update_at": null,
"ldap_sync_last_sync_at": null,
"lfs_enabled": null,
"parent_id": null,
"shared_runners_minutes_limit": null,
"repository_size_limit": null,
"require_two_factor_authentication": false,
"two_factor_grace_period": 48,
"plan_id": null,
"project_creation_level": 2,
"trial_ends_on": null,
"file_template_project_id": null,
"saml_discovery_token": "rBKx3ioz",
"custom_project_templates_group_id": null,
"auto_devops_enabled": null,
"extra_shared_runners_minutes_limit": null,
"last_ci_minutes_notification_at": null,
"last_ci_minutes_usage_notification_level": null,
"subgroup_creation_level": 1,
"emails_disabled": null,
"max_pages_size": null,
"max_artifacts_size": null,
"milestones": [
{
"id": 7642,
"title": "v4.0",
"project_id": null,
"description": "Et laudantium enim omnis ea reprehenderit iure.",
"due_date": null,
"created_at": "2019-11-20T17:02:14.336Z",
"updated_at": "2019-11-20T17:02:14.336Z",
"state": "closed",
"iid": 5,
"start_date": null,
"group_id": 4351
}
],
"badges": [
{
"id": 10,
"link_url": "https://localhost:3443/%{default_branch}",
"image_url": "https://badge_image.png",
"project_id": null,
"group_id": 4351,
"created_at": "2019-11-20T17:27:02.047Z",
"updated_at": "2019-11-20T17:27:02.047Z",
"type": "GroupBadge"
}
],
"labels": [
{
"id": 23452,
"title": "Bruffefunc",
"color": "#1d2da4",
"project_id": null,
"created_at": "2019-11-20T17:02:20.546Z",
"updated_at": "2019-11-20T17:02:20.546Z",
"template": false,
"description": null,
"group_id": 4351,
"type": "GroupLabel",
"priorities": [],
"textColor": "#FFFFFF"
}
],
"boards": [
{
"id": 57,
"project_id": null,
"created_at": "2019-11-20T17:27:41.118Z",
"updated_at": "2019-11-20T17:27:41.118Z",
"name": "first board",
"milestone_id": 7638,
"group_id": 4351,
"weight": null,
"labels": [],
"lists": [
{
"id": 231,
"board_id": 173,
"label_id": null,
"list_type": "assignee",
"position": 3,
"created_at": "2020-02-11T17:02:14.073Z",
"updated_at": "2020-02-11T17:02:14.073Z",
"user_id": 70,
"milestone_id": null,
"max_issue_count": 0,
"max_issue_weight": 0,
"board": {
"id": 173,
"project_id": null,
"created_at": "2020-02-11T14:35:51.561Z",
"updated_at": "2020-02-11T14:35:51.561Z",
"name": "hi",
"milestone_id": null,
"group_id": 4351,
"weight": null
}
},
{
"id": 33,
"board_id": 173,
"label_id": null,
"list_type": "milestone",
"position": 1,
"created_at": "2020-02-10T16:16:01.896Z",
"updated_at": "2020-02-10T16:16:01.896Z",
"user_id": null,
"milestone_id": 264,
"max_issue_count": 0,
"max_issue_weight": 0,
"milestone": {
"id": 264,
"title": "v2.2",
"project_id": null,
"description": "Voluptatum itaque natus laboriosam dolor omnis eaque quos cupiditate.",
"due_date": null,
"created_at": "2020-02-06T15:44:52.126Z",
"updated_at": "2020-02-06T15:44:52.126Z",
"state": "active",
"iid": 1,
"start_date": null,
"group_id": 4351,
"events": []
},
"board": {
"id": 173,
"project_id": null,
"created_at": "2020-02-11T14:35:51.561Z",
"updated_at": "2020-02-11T14:35:51.561Z",
"name": "hi",
"milestone_id": null,
"group_id": 4351,
"weight": null
}
}
]
}
],
"members": [
{
"id": 13766,
"access_level": 30,
"source_id": 4351,
"source_type": "Namespace",
"user_id": 42,
"notification_level": 3,
"created_at": "2019-11-20T17:04:36.184Z",
"updated_at": "2019-11-20T17:04:36.184Z",
"created_by_id": null,
"invite_email": null,
"invite_token": null,
"invite_accepted_at": null,
"requested_at": null,
"expires_at": null,
"ldap": false,
"override": false,
"user": {
"id": 42,
"email": "moriah@collinsmurphy.com",
"username": "reported_user_15"
}
}
],
"epics": [
{
"id": 13622,
"milestone_id": null,
"group_id": 4351,
"author_id": 1,
"assignee_id": null,
"iid": 1,
"updated_by_id": null,
"last_edited_by_id": null,
"lock_version": 0,
"start_date": null,
"end_date": null,
"last_edited_at": null,
"created_at": "2019-11-20T17:02:09.754Z",
"updated_at": "2019-11-20T18:38:40.054Z",
"title": "Provident neque consequatur numquam ad laboriosam voluptatem magnam.",
"description": "Fugit nisi est ut numquam quia rerum vitae qui. Et in est aliquid voluptas et ut vitae. In distinctio voluptates ut deleniti iste.\n\nReiciendis eum sunt vero blanditiis at quia. Voluptate eum facilis illum ea distinctio maiores. Doloribus aut nemo ea distinctio.\n\nNihil cum distinctio voluptates quam. Laboriosam distinctio ea accusantium soluta perspiciatis nesciunt impedit. Id qui natus quis minima voluptatum velit ut reprehenderit. Molestiae quia est harum sapiente rem error architecto id. Et minus ipsa et ut ut.",
"start_date_sourcing_milestone_id": null,
"due_date_sourcing_milestone_id": null,
"start_date_fixed": null,
"due_date_fixed": null,
"start_date_is_fixed": null,
"due_date_is_fixed": null,
"closed_by_id": null,
"closed_at": null,
"parent_id": null,
"relative_position": null,
"state_id": "opened",
"start_date_sourcing_epic_id": null,
"due_date_sourcing_epic_id": null,
"notes": [
{
"id": 44164,
"note": "added epic \u00262 as child epic",
"noteable_type": "Epic",
"author_id": 1,
"created_at": "2019-11-20T18:38:26.689Z",
"updated_at": "2019-11-20T18:38:26.724Z",
"project_id": null,
"attachment": {
"url": null
},
"line_code": null,
"commit_id": null,
"noteable_id": 13622,
"system": true,
"st_diff": null,
"updated_by_id": null,
"position": null,
"original_position": null,
"resolved_at": null,
"resolved_by_id": null,
"discussion_id": "133f0c3001860fa8d2031e398a65db74477378c4",
"change_position": null,
"resolved_by_push": null,
"review_id": null,
"type": null,
"author": {
"name": "Administrator"
},
"award_emoji": [
{
"id": 12,
"name": "drum",
"user_id": 1,
"awardable_type": "Note",
"awardable_id": 44170,
"created_at": "2019-11-05T15:32:21.287Z",
"updated_at": "2019-11-05T15:32:21.287Z"
}
]
}
],
"award_emoji": [
{
"id": 12,
"name": "thumbsup",
"user_id": 1,
"awardable_type": "Epic",
"awardable_id": 13622,
"created_at": "2019-11-05T15:37:21.287Z",
"updated_at": "2019-11-05T15:37:21.287Z"
}
]
}
]
}
...@@ -11,7 +11,9 @@ describe Gitlab::ImportExport::GroupTreeRestorer do ...@@ -11,7 +11,9 @@ describe Gitlab::ImportExport::GroupTreeRestorer do
let(:group_tree_restorer) { described_class.new(user: user, shared: shared, group: group, group_hash: nil) } let(:group_tree_restorer) { described_class.new(user: user, shared: shared, group: group, group_hash: nil) }
before do before do
setup_import_export_config('group_exports/complex') stub_licensed_features(board_assignee_lists: true, board_milestone_lists: true)
setup_import_export_config('group_exports/light', 'ee')
group.add_owner(user) group.add_owner(user)
group_tree_restorer.restore group_tree_restorer.restore
end end
...@@ -19,7 +21,7 @@ describe Gitlab::ImportExport::GroupTreeRestorer do ...@@ -19,7 +21,7 @@ describe Gitlab::ImportExport::GroupTreeRestorer do
describe 'restore group tree' do describe 'restore group tree' do
context 'epics' do context 'epics' do
it 'has group epics' do it 'has group epics' do
expect(group.epics.count).to eq(5) expect(group.epics.count).to eq(1)
end end
it 'has award emoji' do it 'has award emoji' do
...@@ -29,12 +31,20 @@ describe Gitlab::ImportExport::GroupTreeRestorer do ...@@ -29,12 +31,20 @@ describe Gitlab::ImportExport::GroupTreeRestorer do
context 'epic notes' do context 'epic notes' do
it 'has epic notes' do it 'has epic notes' do
expect(group.epics.first.notes.count).to eq(4) expect(group.epics.first.notes.count).to eq(1)
end end
it 'has award emoji on epic notes' do it 'has award emoji on epic notes' do
expect(group.epics.first.notes.first.award_emoji.first.name).to eq('drum') expect(group.epics.first.notes.first.award_emoji.first.name).to eq('drum')
end end
end end
context 'board lists' do
it 'has milestone & assignee lists' do
lists = group.boards.find_by(name: 'first board').lists
expect(lists.map(&:list_type)).to contain_exactly('assignee', 'milestone')
end
end
end end
end end
...@@ -11,6 +11,7 @@ describe Gitlab::ImportExport::GroupTreeSaver do ...@@ -11,6 +11,7 @@ describe Gitlab::ImportExport::GroupTreeSaver do
let_it_be(:epic) { create(:epic, group: group, parent: parent_epic) } let_it_be(:epic) { create(:epic, group: group, parent: parent_epic) }
let_it_be(:epic_event) { create(:event, :created, target: epic, group: group, author: user) } let_it_be(:epic_event) { create(:event, :created, target: epic, group: group, author: user) }
let_it_be(:epic_push_event) { create(:event, :pushed, target: epic, group: group, author: user) } let_it_be(:epic_push_event) { create(:event, :pushed, target: epic, group: group, author: user) }
let_it_be(:milestone) { create(:milestone, group: group) }
let_it_be(:board) { create(:board, group: group, assignee: user, labels: [label]) } let_it_be(:board) { create(:board, group: group, assignee: user, labels: [label]) }
let_it_be(:note) { create(:note, noteable: epic) } let_it_be(:note) { create(:note, noteable: epic) }
let_it_be(:note_event) { create(:event, :created, target: note, author: user) } let_it_be(:note_event) { create(:event, :created, target: note, author: user) }
...@@ -101,24 +102,41 @@ describe Gitlab::ImportExport::GroupTreeSaver do ...@@ -101,24 +102,41 @@ describe Gitlab::ImportExport::GroupTreeSaver do
end end
context 'boards relation' do context 'boards relation' do
it 'saves top level boards' do before do
stub_licensed_features(board_assignee_lists: true, board_milestone_lists: true)
create(:list, board: board, user: user, list_type: List.list_types[:assignee], position: 0)
create(:list, board: board, milestone: milestone, list_type: List.list_types[:milestone], position: 1)
expect_successful_save(group_tree_saver) expect_successful_save(group_tree_saver)
end
it 'saves top level boards' do
expect(saved_group_json['boards'].size).to eq(1) expect(saved_group_json['boards'].size).to eq(1)
end end
it 'saves board assignee' do it 'saves board assignee' do
expect_successful_save(group_tree_saver)
expect(saved_group_json['boards'].first['board_assignee']['assignee_id']).to eq(user.id) expect(saved_group_json['boards'].first['board_assignee']['assignee_id']).to eq(user.id)
end end
it 'saves board labels' do it 'saves board labels' do
expect_successful_save(group_tree_saver)
labels = saved_group_json['boards'].first['labels'] labels = saved_group_json['boards'].first['labels']
expect(labels).not_to be_empty expect(labels).not_to be_empty
expect(labels.first['title']).to eq(label.title) expect(labels.first['title']).to eq(label.title)
end end
it 'saves board lists' do
lists = saved_group_json['boards'].first['lists']
expect(lists).not_to be_empty
milestone_list = lists.find { |list| list['list_type'] == 'milestone' }
assignee_list = lists.find { |list| list['list_type'] == 'assignee' }
expect(milestone_list['milestone_id']).to eq(milestone.id)
expect(assignee_list['user_id']).to eq(user.id)
end
end end
end end
......
...@@ -9,7 +9,11 @@ tree: ...@@ -9,7 +9,11 @@ tree:
- :badges - :badges
- labels: - labels:
- :priorities - :priorities
- :boards - boards:
- lists:
- label:
- :priorities
- :board
- members: - members:
- :user - :user
...@@ -30,12 +34,16 @@ excluded_attributes: ...@@ -30,12 +34,16 @@ excluded_attributes:
methods: methods:
labels: labels:
- :type - :type
label:
- :type
badges: badges:
- :type - :type
notes: notes:
- :type - :type
events: events:
- :action - :action
lists:
- :list_type
preloads: preloads:
...@@ -58,3 +66,7 @@ ee: ...@@ -58,3 +66,7 @@ ee:
- :board_assignee - :board_assignee
- labels: - labels:
- :priorities - :priorities
- lists:
- milestone:
- events:
- :push_event_payload
...@@ -260,25 +260,101 @@ ...@@ -260,25 +260,101 @@
], ],
"boards": [ "boards": [
{ {
"id": 56, "id": 173,
"project_id": null, "project_id": null,
"created_at": "2019-11-20T17:27:16.808Z", "created_at": "2020-02-11T14:35:51.561Z",
"updated_at": "2019-11-20T17:27:16.808Z", "updated_at": "2020-02-11T14:35:51.561Z",
"name": "Development", "name": "first board",
"milestone_id": null, "milestone_id": null,
"group_id": 4351, "group_id": 4351,
"weight": null, "weight": null,
"labels": [] "lists": [
{
"id": 189,
"board_id": 173,
"label_id": 271,
"list_type": "label",
"position": 0,
"created_at": "2020-02-11T14:35:57.131Z",
"updated_at": "2020-02-11T14:35:57.131Z",
"user_id": null,
"milestone_id": null,
"max_issue_count": 0,
"max_issue_weight": 0,
"label": {
"id": 271,
"title": "TSL",
"color": "#58796f",
"project_id": null,
"created_at": "2019-11-20T17:02:20.541Z",
"updated_at": "2020-02-06T15:44:52.048Z",
"template": false,
"description": null,
"group_id": 4351,
"type": "GroupLabel",
"priorities": []
},
"board": {
"id": 173,
"project_id": null,
"created_at": "2020-02-11T14:35:51.561Z",
"updated_at": "2020-02-11T14:35:51.561Z",
"name": "hi",
"milestone_id": null,
"group_id": 4351,
"weight": null
}
}, },
{ {
"id": 57, "id": 190,
"board_id": 173,
"label_id": 272,
"list_type": "label",
"position": 1,
"created_at": "2020-02-11T14:35:57.868Z",
"updated_at": "2020-02-11T14:35:57.868Z",
"user_id": null,
"milestone_id": null,
"max_issue_count": 0,
"max_issue_weight": 0,
"label": {
"id": 272,
"title": "Sosync",
"color": "#110320",
"project_id": null, "project_id": null,
"created_at": "2019-11-20T17:27:41.118Z", "created_at": "2019-11-20T17:02:20.532Z",
"updated_at": "2019-11-20T17:27:41.118Z", "updated_at": "2020-02-06T15:44:52.057Z",
"name": "Board!", "template": false,
"milestone_id": 7638, "description": null,
"group_id": 4351, "group_id": 4351,
"weight": null, "type": "GroupLabel",
"priorities": []
},
"board": {
"id": 173,
"project_id": null,
"created_at": "2020-02-11T14:35:51.561Z",
"updated_at": "2020-02-11T14:35:51.561Z",
"name": "hi",
"milestone_id": null,
"group_id": 4351,
"weight": null
}
},
{
"id": 188,
"board_id": 173,
"label_id": null,
"list_type": "closed",
"position": null,
"created_at": "2020-02-11T14:35:51.593Z",
"updated_at": "2020-02-11T14:35:51.593Z",
"user_id": null,
"milestone_id": null,
"max_issue_count": 0,
"max_issue_weight": 0
}
],
"labels": [] "labels": []
} }
], ],
......
...@@ -39,8 +39,18 @@ describe Gitlab::ImportExport::GroupTreeRestorer do ...@@ -39,8 +39,18 @@ describe Gitlab::ImportExport::GroupTreeRestorer do
expect(@group.labels.count).to eq(10) expect(@group.labels.count).to eq(10)
end end
context 'issue boards' do
it 'has issue boards' do it 'has issue boards' do
expect(@group.boards.count).to eq(2) expect(@group.boards.count).to eq(1)
end
it 'has board label lists' do
lists = @group.boards.find_by(name: 'first board').lists
expect(lists.count).to eq(3)
expect(lists.first.label.title).to eq('TSL')
expect(lists.second.label.title).to eq('Sosync')
end
end end
it 'has badges' do it 'has badges' do
......
...@@ -95,6 +95,10 @@ describe Gitlab::ImportExport::GroupTreeSaver do ...@@ -95,6 +95,10 @@ describe Gitlab::ImportExport::GroupTreeSaver do
expect(saved_group_json['boards']).not_to be_empty expect(saved_group_json['boards']).not_to be_empty
end end
it 'has board label list' do
expect(saved_group_json['boards'].first['lists']).not_to be_empty
end
it 'has group members' do it 'has group members' do
expect(saved_group_json['members']).not_to be_empty expect(saved_group_json['members']).not_to be_empty
end end
...@@ -168,7 +172,8 @@ describe Gitlab::ImportExport::GroupTreeSaver do ...@@ -168,7 +172,8 @@ describe Gitlab::ImportExport::GroupTreeSaver do
create(:group_badge, group: group) create(:group_badge, group: group)
group_label = create(:group_label, group: group) group_label = create(:group_label, group: group)
create(:label_priority, label: group_label, priority: 1) create(:label_priority, label: group_label, priority: 1)
create(:board, group: group) board = create(:board, group: group)
create(:list, board: board, label: group_label)
create(:group_badge, group: group) create(:group_badge, group: group)
group group
......
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