Commit df48758c authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'fix/gb/fix-import-export-restoring-associations' into 'master'

Fix restoring associations with import/export

Closes #41646

See merge request gitlab-org/gitlab-ce!16221
parents 64ef3bfd 92df3a74
...@@ -79,7 +79,7 @@ module Ci ...@@ -79,7 +79,7 @@ module Ci
before_save :ensure_token before_save :ensure_token
before_destroy { unscoped_project } before_destroy { unscoped_project }
after_create do |build| after_create unless: :importing? do |build|
run_after_commit { BuildHooksWorker.perform_async(build.id) } run_after_commit { BuildHooksWorker.perform_async(build.id) }
end end
......
---
title: Fix missing references to pipeline objects when restoring project with import/export
feature
merge_request: 16221
author:
type: fixed
...@@ -30,7 +30,8 @@ with all their related data and be moved into a new GitLab instance. ...@@ -30,7 +30,8 @@ with all their related data and be moved into a new GitLab instance.
| GitLab version | Import/Export version | | GitLab version | Import/Export version |
| ---------------- | --------------------- | | ---------------- | --------------------- |
| 10.3 to current | 0.2.1 | | 10.4 to current | 0.2.2 |
| 10.3 | 0.2.1 |
| 10.0 | 0.2.0 | | 10.0 | 0.2.0 |
| 9.4.0 | 0.1.8 | | 9.4.0 | 0.1.8 |
| 9.2.0 | 0.1.7 | | 9.2.0 | 0.1.7 |
......
...@@ -3,7 +3,7 @@ module Gitlab ...@@ -3,7 +3,7 @@ module Gitlab
extend self extend self
# For every version update, the version history in import_export.md has to be kept up to date. # For every version update, the version history in import_export.md has to be kept up to date.
VERSION = '0.2.1'.freeze VERSION = '0.2.2'.freeze
FILENAME_LIMIT = 50 FILENAME_LIMIT = 50
def export_path(relative_path:) def export_path(relative_path:)
......
...@@ -49,7 +49,7 @@ project_tree: ...@@ -49,7 +49,7 @@ project_tree:
- :author - :author
- events: - events:
- :push_event_payload - :push_event_payload
- :stages - stages:
- :statuses - :statuses
- :auto_devops - :auto_devops
- :triggers - :triggers
......
...@@ -62,6 +62,7 @@ module Gitlab ...@@ -62,6 +62,7 @@ module Gitlab
when :notes then setup_note when :notes then setup_note
when :project_label, :project_labels then setup_label when :project_label, :project_labels then setup_label
when :milestone, :milestones then setup_milestone when :milestone, :milestones then setup_milestone
when 'Ci::Pipeline' then setup_pipeline
else else
@relation_hash['project_id'] = @project.id @relation_hash['project_id'] = @project.id
end end
...@@ -112,9 +113,7 @@ module Gitlab ...@@ -112,9 +113,7 @@ module Gitlab
@relation_hash.delete('trace') # old export files have trace @relation_hash.delete('trace') # old export files have trace
@relation_hash.delete('token') @relation_hash.delete('token')
imported_object do |object| imported_object
object.commit_id = nil
end
elsif @relation_name == :merge_requests elsif @relation_name == :merge_requests
MergeRequestParser.new(@project, @relation_hash.delete('diff_head_sha'), imported_object, @relation_hash).parse! MergeRequestParser.new(@project, @relation_hash.delete('diff_head_sha'), imported_object, @relation_hash).parse!
else else
...@@ -182,8 +181,9 @@ module Gitlab ...@@ -182,8 +181,9 @@ module Gitlab
end end
def imported_object def imported_object
yield(existing_or_new_object) if block_given? if existing_or_new_object.respond_to?(:importing)
existing_or_new_object.importing = true if existing_or_new_object.respond_to?(:importing) existing_or_new_object.importing = true
end
existing_or_new_object existing_or_new_object
rescue ActiveRecord::RecordNotUnique rescue ActiveRecord::RecordNotUnique
...@@ -211,6 +211,14 @@ module Gitlab ...@@ -211,6 +211,14 @@ module Gitlab
@relation_hash['diff'] = @relation_hash.delete('utf8_diff') @relation_hash['diff'] = @relation_hash.delete('utf8_diff')
end end
def setup_pipeline
@relation_hash.fetch('stages').each do |stage|
stage.statuses.each do |status|
status.pipeline = imported_object
end
end
end
def existing_or_new_object def existing_or_new_object
# Only find existing records to avoid mapping tables such as milestones # Only find existing records to avoid mapping tables such as milestones
# Otherwise always create the record, skipping the extra SELECT clause. # Otherwise always create the record, skipping the extra SELECT clause.
......
...@@ -6465,6 +6465,15 @@ ...@@ -6465,6 +6465,15 @@
} }
} }
], ],
"stages": [
{
"id": 11,
"project_id": 5,
"pipeline_id": 36,
"name": "test",
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
"updated_at": "2016-03-29T06:44:44.634Z",
"statuses": [ "statuses": [
{ {
"id": 71, "id": 71,
...@@ -6487,6 +6496,7 @@ ...@@ -6487,6 +6496,7 @@
"stage": "test", "stage": "test",
"trigger_request_id": null, "trigger_request_id": null,
"stage_idx": 1, "stage_idx": 1,
"stage_id": 11,
"tag": null, "tag": null,
"ref": "master", "ref": "master",
"user_id": null, "user_id": null,
...@@ -6515,15 +6525,16 @@ ...@@ -6515,15 +6525,16 @@
"runner_id": null, "runner_id": null,
"coverage": null, "coverage": null,
"commit_id": 36, "commit_id": 36,
"commands": "$ build command", "commands": "$ deploy command",
"job_id": null, "job_id": null,
"name": "test build 2", "name": "test build 2",
"deploy": false, "deploy": false,
"options": null, "options": null,
"allow_failure": false, "allow_failure": false,
"stage": "test", "stage": "deploy",
"trigger_request_id": null, "trigger_request_id": null,
"stage_idx": 1, "stage_idx": 1,
"stage_id": 12,
"tag": null, "tag": null,
"ref": "master", "ref": "master",
"user_id": null, "user_id": null,
...@@ -6540,6 +6551,17 @@ ...@@ -6540,6 +6551,17 @@
} }
] ]
}, },
{
"id": 12,
"project_id": 5,
"pipeline_id": 36,
"name": "deploy",
"status": 2,
"created_at": "2016-03-22T15:45:45.772Z",
"updated_at": "2016-03-29T06:45:45.634Z"
}
]
},
{ {
"id": 37, "id": 37,
"project_id": 5, "project_id": 5,
...@@ -6556,6 +6578,15 @@ ...@@ -6556,6 +6578,15 @@
"started_at": null, "started_at": null,
"finished_at": null, "finished_at": null,
"duration": null, "duration": null,
"stages": [
{
"id": 21,
"project_id": 5,
"pipeline_id": 37,
"name": "test",
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
"updated_at": "2016-03-29T06:44:44.634Z",
"statuses": [ "statuses": [
{ {
"id": 74, "id": 74,
...@@ -6628,6 +6659,8 @@ ...@@ -6628,6 +6659,8 @@
"erased_at": null "erased_at": null
} }
] ]
}
]
}, },
{ {
"id": 38, "id": 38,
...@@ -6645,6 +6678,15 @@ ...@@ -6645,6 +6678,15 @@
"started_at": null, "started_at": null,
"finished_at": null, "finished_at": null,
"duration": null, "duration": null,
"stages": [
{
"id": 22,
"project_id": 5,
"pipeline_id": 38,
"name": "test",
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
"updated_at": "2016-03-29T06:44:44.634Z",
"statuses": [ "statuses": [
{ {
"id": 76, "id": 76,
...@@ -6717,6 +6759,8 @@ ...@@ -6717,6 +6759,8 @@
"erased_at": null "erased_at": null
} }
] ]
}
]
}, },
{ {
"id": 39, "id": 39,
...@@ -6734,6 +6778,15 @@ ...@@ -6734,6 +6778,15 @@
"started_at": null, "started_at": null,
"finished_at": null, "finished_at": null,
"duration": null, "duration": null,
"stages": [
{
"id": 23,
"project_id": 5,
"pipeline_id": 39,
"name": "test",
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
"updated_at": "2016-03-29T06:44:44.634Z",
"statuses": [ "statuses": [
{ {
"id": 78, "id": 78,
...@@ -6806,6 +6859,8 @@ ...@@ -6806,6 +6859,8 @@
"erased_at": null "erased_at": null
} }
] ]
}
]
}, },
{ {
"id": 40, "id": 40,
...@@ -6823,6 +6878,15 @@ ...@@ -6823,6 +6878,15 @@
"started_at": null, "started_at": null,
"finished_at": null, "finished_at": null,
"duration": null, "duration": null,
"stages": [
{
"id": 24,
"project_id": 5,
"pipeline_id": 40,
"name": "test",
"status": 1,
"created_at": "2016-03-22T15:44:44.772Z",
"updated_at": "2016-03-29T06:44:44.634Z",
"statuses": [ "statuses": [
{ {
"id": 79, "id": 79,
...@@ -6896,6 +6960,8 @@ ...@@ -6896,6 +6960,8 @@
} }
] ]
} }
]
}
], ],
"triggers": [ "triggers": [
{ {
......
...@@ -179,6 +179,32 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do ...@@ -179,6 +179,32 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end end
end end
end end
context 'when restoring hierarchy of pipeline, stages and jobs' do
it 'restores pipelines' do
expect(Ci::Pipeline.all.count).to be 5
end
it 'restores pipeline stages' do
expect(Ci::Stage.all.count).to be 6
end
it 'correctly restores association between stage and a pipeline' do
expect(Ci::Stage.all).to all(have_attributes(pipeline_id: a_value > 0))
end
it 'restores statuses' do
expect(CommitStatus.all.count).to be 10
end
it 'correctly restores association between a stage and a job' do
expect(CommitStatus.all).to all(have_attributes(stage_id: a_value > 0))
end
it 'correctly restores association between a pipeline and a job' do
expect(CommitStatus.all).to all(have_attributes(pipeline_id: a_value > 0))
end
end
end end
end end
......
...@@ -109,12 +109,20 @@ describe Gitlab::ImportExport::ProjectTreeSaver do ...@@ -109,12 +109,20 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
expect(saved_project_json['merge_requests'].first['notes'].first['author']).not_to be_empty expect(saved_project_json['merge_requests'].first['notes'].first['author']).not_to be_empty
end end
it 'has pipeline stages' do
expect(saved_project_json.dig('pipelines', 0, 'stages')).not_to be_empty
end
it 'has pipeline statuses' do it 'has pipeline statuses' do
expect(saved_project_json['pipelines'].first['statuses']).not_to be_empty expect(saved_project_json.dig('pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty
end end
it 'has pipeline builds' do it 'has pipeline builds' do
expect(saved_project_json['pipelines'].first['statuses'].count { |hash| hash['type'] == 'Ci::Build' }).to eq(1) builds_count = saved_project_json
.dig('pipelines', 0, 'stages', 0, 'statuses')
.count { |hash| hash['type'] == 'Ci::Build' }
expect(builds_count).to eq(1)
end end
it 'has no when YML attributes but only the DB column' do it 'has no when YML attributes but only the DB column' 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