Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
e06142fc
Commit
e06142fc
authored
Oct 27, 2021
by
Doug Stull
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Split RelationTreeRestorer into group and project
- remove branching logic on if project or group
parent
43ad1fba
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
565 additions
and
310 deletions
+565
-310
.rubocop_manual_todo.yml
.rubocop_manual_todo.yml
+1
-1
lib/gitlab/import_export/group/relation_tree_restorer.rb
lib/gitlab/import_export/group/relation_tree_restorer.rb
+274
-0
lib/gitlab/import_export/project/relation_tree_restorer.rb
lib/gitlab/import_export/project/relation_tree_restorer.rb
+27
-0
lib/gitlab/import_export/project/sample/relation_tree_restorer.rb
...ab/import_export/project/sample/relation_tree_restorer.rb
+3
-3
lib/gitlab/import_export/relation_tree_restorer.rb
lib/gitlab/import_export/relation_tree_restorer.rb
+0
-280
spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb
...gitlab/import_export/group/relation_tree_restorer_spec.rb
+88
-0
spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb
...tlab/import_export/project/relation_tree_restorer_spec.rb
+150
-0
spec/lib/gitlab/import_export/project/sample/relation_tree_restorer_spec.rb
...port_export/project/sample/relation_tree_restorer_spec.rb
+22
-26
No files found.
.rubocop_manual_todo.yml
View file @
e06142fc
...
...
@@ -2459,7 +2459,7 @@ Database/MultipleDatabases:
-
'
lib/gitlab/gitlab_import/importer.rb'
-
'
lib/gitlab/health_checks/db_check.rb'
-
'
lib/gitlab/import_export/base/relation_factory.rb'
-
'
lib/gitlab/import_export/relation_tree_restorer.rb'
-
'
lib/gitlab/import_export/
group/
relation_tree_restorer.rb'
-
'
lib/gitlab/legacy_github_import/importer.rb'
-
'
lib/gitlab/metrics/samplers/database_sampler.rb'
-
'
lib/gitlab/seeder.rb'
...
...
lib/gitlab/import_export/group/relation_tree_restorer.rb
0 → 100644
View file @
e06142fc
# frozen_string_literal: true
module
Gitlab
module
ImportExport
module
Group
class
RelationTreeRestorer
def
initialize
(
# rubocop:disable Metrics/ParameterLists
user
:,
shared
:,
relation_reader
:,
members_mapper
:,
object_builder
:,
relation_factory
:,
reader
:,
importable
:,
importable_attributes
:,
importable_path:
)
@user
=
user
@shared
=
shared
@importable
=
importable
@relation_reader
=
relation_reader
@members_mapper
=
members_mapper
@object_builder
=
object_builder
@relation_factory
=
relation_factory
@reader
=
reader
@importable_attributes
=
importable_attributes
@importable_path
=
importable_path
end
def
restore
ActiveRecord
::
Base
.
uncached
do
ActiveRecord
::
Base
.
no_touching
do
update_params!
BulkInsertableAssociations
.
with_bulk_insert
(
enabled:
bulk_insert_enabled
)
do
fix_ci_pipelines_not_sorted_on_legacy_project_json!
create_relations!
end
end
end
# ensure that we have latest version of the restore
@importable
.
reload
# rubocop:disable Cop/ActiveRecordAssociationReload
true
rescue
StandardError
=>
e
@shared
.
error
(
e
)
false
end
private
def
bulk_insert_enabled
false
end
# Loops through the tree of models defined in import_export.yml and
# finds them in the imported JSON so they can be instantiated and saved
# in the DB. The structure and relationships between models are guessed from
# the configuration yaml file too.
# Finally, it updates each attribute in the newly imported project/group.
def
create_relations!
relations
.
each
do
|
relation_key
,
relation_definition
|
process_relation!
(
relation_key
,
relation_definition
)
end
end
def
process_relation!
(
relation_key
,
relation_definition
)
@relation_reader
.
consume_relation
(
@importable_path
,
relation_key
).
each
do
|
data_hash
,
relation_index
|
process_relation_item!
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
end
end
def
process_relation_item!
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
relation_object
=
build_relation
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
return
unless
relation_object
return
if
relation_invalid_for_importable?
(
relation_object
)
relation_object
.
assign_attributes
(
importable_class_sym
=>
@importable
)
import_failure_service
.
with_retry
(
action:
'relation_object.save!'
,
relation_key:
relation_key
,
relation_index:
relation_index
)
do
relation_object
.
save!
log_relation_creation
(
@importable
,
relation_key
,
relation_object
)
end
rescue
StandardError
=>
e
import_failure_service
.
log_import_failure
(
source:
'process_relation_item!'
,
relation_key:
relation_key
,
relation_index:
relation_index
,
exception:
e
)
end
def
import_failure_service
@import_failure_service
||=
ImportFailureService
.
new
(
@importable
)
end
def
relations
@relations
||=
@reader
.
attributes_finder
.
find_relations_tree
(
importable_class_sym
)
.
deep_stringify_keys
end
def
update_params!
params
=
@importable_attributes
.
except
(
*
relations
.
keys
.
map
(
&
:to_s
))
params
=
params
.
merge
(
present_override_params
)
# Cleaning all imported and overridden params
params
=
Gitlab
::
ImportExport
::
AttributeCleaner
.
clean
(
relation_hash:
params
,
relation_class:
importable_class
,
excluded_keys:
excluded_keys_for_relation
(
importable_class_sym
))
@importable
.
assign_attributes
(
params
)
modify_attributes
Gitlab
::
Timeless
.
timeless
(
@importable
)
do
@importable
.
save!
end
end
def
present_override_params
# we filter out the empty strings from the overrides
# keeping the default values configured
override_params
&
.
transform_values
do
|
value
|
value
.
is_a?
(
String
)
?
value
.
presence
:
value
end
&
.
compact
end
def
override_params
@importable_override_params
||=
importable_override_params
end
def
importable_override_params
if
@importable
.
respond_to?
(
:import_data
)
@importable
.
import_data
&
.
data
&
.
fetch
(
'override_params'
,
nil
)
||
{}
else
{}
end
end
def
modify_attributes
# no-op to be overridden on inheritance
end
def
build_relations
(
relation_key
,
relation_definition
,
relation_index
,
data_hashes
)
data_hashes
.
map
{
|
data_hash
|
build_relation
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
}
.
tap
{
|
entries
|
entries
.
compact!
}
end
def
build_relation
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
# TODO: This is hack to not create relation for the author
# Rather make `RelationFactory#set_note_author` to take care of that
return
data_hash
if
relation_key
==
'author'
||
already_restored?
(
data_hash
)
# create relation objects recursively for all sub-objects
relation_definition
.
each
do
|
sub_relation_key
,
sub_relation_definition
|
transform_sub_relations!
(
data_hash
,
sub_relation_key
,
sub_relation_definition
,
relation_index
)
end
relation
=
@relation_factory
.
create
(
**
relation_factory_params
(
relation_key
,
relation_index
,
data_hash
))
if
relation
&&
!
relation
.
valid?
@shared
.
logger
.
warn
(
message:
"[Project/Group Import] Invalid object relation built"
,
relation_key:
relation_key
,
relation_index:
relation_index
,
relation_class:
relation
.
class
.
name
,
error_messages:
relation
.
errors
.
full_messages
.
join
(
". "
)
)
end
relation
end
# Since we update the data hash in place as we restore relation items,
# and since we also de-duplicate items, we might encounter items that
# have already been restored in a previous iteration.
def
already_restored?
(
relation_item
)
!
relation_item
.
is_a?
(
Hash
)
end
def
transform_sub_relations!
(
data_hash
,
sub_relation_key
,
sub_relation_definition
,
relation_index
)
sub_data_hash
=
data_hash
[
sub_relation_key
]
return
unless
sub_data_hash
# if object is a hash we can create simple object
# as it means that this is 1-to-1 vs 1-to-many
current_item
=
if
sub_data_hash
.
is_a?
(
Array
)
build_relations
(
sub_relation_key
,
sub_relation_definition
,
relation_index
,
sub_data_hash
).
presence
else
build_relation
(
sub_relation_key
,
sub_relation_definition
,
relation_index
,
sub_data_hash
)
end
if
current_item
data_hash
[
sub_relation_key
]
=
current_item
else
data_hash
.
delete
(
sub_relation_key
)
end
end
def
relation_invalid_for_importable?
(
_relation_object
)
false
end
def
excluded_keys_for_relation
(
relation
)
@reader
.
attributes_finder
.
find_excluded_keys
(
relation
)
end
def
importable_class
@importable
.
class
end
def
importable_class_sym
importable_class
.
to_s
.
downcase
.
to_sym
end
def
relation_factory_params
(
relation_key
,
relation_index
,
data_hash
)
{
relation_index:
relation_index
,
relation_sym:
relation_key
.
to_sym
,
relation_hash:
data_hash
,
importable:
@importable
,
members_mapper:
@members_mapper
,
object_builder:
@object_builder
,
user:
@user
,
excluded_keys:
excluded_keys_for_relation
(
relation_key
)
}
end
# Temporary fix for https://gitlab.com/gitlab-org/gitlab/-/issues/27883 when import from legacy project.json
# This should be removed once legacy JSON format is deprecated.
# Ndjson export file will fix the order during project export.
def
fix_ci_pipelines_not_sorted_on_legacy_project_json!
return
unless
@relation_reader
.
legacy?
@relation_reader
.
sort_ci_pipelines_by_id
end
# Enable logging of each top-level relation creation when Importing
# into a Group if feature flag is enabled
def
log_relation_creation
(
importable
,
relation_key
,
relation_object
)
root_ancestor_group
=
importable
.
try
(
:root_ancestor
)
return
unless
root_ancestor_group
return
unless
root_ancestor_group
.
instance_of?
(
::
Group
)
return
unless
Feature
.
enabled?
(
:log_import_export_relation_creation
,
root_ancestor_group
)
@shared
.
logger
.
info
(
importable_type:
importable
.
class
.
to_s
,
importable_id:
importable
.
id
,
relation_key:
relation_key
,
relation_id:
relation_object
.
id
,
author_id:
relation_object
.
try
(
:author_id
),
message:
'[Project/Group Import] Created new object relation'
)
end
end
end
end
end
lib/gitlab/import_export/project/relation_tree_restorer.rb
0 → 100644
View file @
e06142fc
# frozen_string_literal: true
module
Gitlab
module
ImportExport
module
Project
class
RelationTreeRestorer
<
ImportExport
::
Group
::
RelationTreeRestorer
# Relations which cannot be saved at project level (and have a group assigned)
GROUP_MODELS
=
[
GroupLabel
,
Milestone
,
Epic
].
freeze
private
def
bulk_insert_enabled
true
end
def
modify_attributes
@importable
.
reconcile_shared_runners_setting!
@importable
.
drop_visibility_level!
end
def
relation_invalid_for_importable?
(
relation_object
)
GROUP_MODELS
.
include?
(
relation_object
.
class
)
&&
relation_object
.
group_id
end
end
end
end
end
lib/gitlab/import_export/project/sample/relation_tree_restorer.rb
View file @
e06142fc
...
...
@@ -4,7 +4,7 @@ module Gitlab
module
ImportExport
module
Project
module
Sample
class
RelationTreeRestorer
<
ImportExport
::
RelationTreeRestorer
class
RelationTreeRestorer
<
ImportExport
::
Project
::
RelationTreeRestorer
def
initialize
(
...
)
super
(
...
)
...
...
@@ -18,10 +18,10 @@ module Gitlab
end
def
dates
return
[]
if
relation_reader
.
legacy?
return
[]
if
@
relation_reader
.
legacy?
RelationFactory
::
DATE_MODELS
.
flat_map
do
|
tag
|
relation_reader
.
consume_relation
(
@importable_path
,
tag
,
mark_as_consumed:
false
).
map
do
|
model
|
@
relation_reader
.
consume_relation
(
@importable_path
,
tag
,
mark_as_consumed:
false
).
map
do
|
model
|
model
.
first
[
'due_date'
]
end
end
...
...
lib/gitlab/import_export/relation_tree_restorer.rb
deleted
100644 → 0
View file @
43ad1fba
# frozen_string_literal: true
module
Gitlab
module
ImportExport
class
RelationTreeRestorer
# Relations which cannot be saved at project level (and have a group assigned)
GROUP_MODELS
=
[
GroupLabel
,
Milestone
,
Epic
].
freeze
attr_reader
:user
attr_reader
:shared
attr_reader
:importable
attr_reader
:relation_reader
def
initialize
(
# rubocop:disable Metrics/ParameterLists
user
:,
shared
:,
relation_reader
:,
members_mapper
:,
object_builder
:,
relation_factory
:,
reader
:,
importable
:,
importable_attributes
:,
importable_path:
)
@user
=
user
@shared
=
shared
@importable
=
importable
@relation_reader
=
relation_reader
@members_mapper
=
members_mapper
@object_builder
=
object_builder
@relation_factory
=
relation_factory
@reader
=
reader
@importable_attributes
=
importable_attributes
@importable_path
=
importable_path
end
def
restore
ActiveRecord
::
Base
.
uncached
do
ActiveRecord
::
Base
.
no_touching
do
update_params!
BulkInsertableAssociations
.
with_bulk_insert
(
enabled:
project?
)
do
fix_ci_pipelines_not_sorted_on_legacy_project_json!
create_relations!
end
end
end
# ensure that we have latest version of the restore
@importable
.
reload
# rubocop:disable Cop/ActiveRecordAssociationReload
true
rescue
StandardError
=>
e
@shared
.
error
(
e
)
false
end
private
def
project?
@importable
.
instance_of?
(
::
Project
)
end
# Loops through the tree of models defined in import_export.yml and
# finds them in the imported JSON so they can be instantiated and saved
# in the DB. The structure and relationships between models are guessed from
# the configuration yaml file too.
# Finally, it updates each attribute in the newly imported project/group.
def
create_relations!
relations
.
each
do
|
relation_key
,
relation_definition
|
process_relation!
(
relation_key
,
relation_definition
)
end
end
def
process_relation!
(
relation_key
,
relation_definition
)
@relation_reader
.
consume_relation
(
@importable_path
,
relation_key
).
each
do
|
data_hash
,
relation_index
|
process_relation_item!
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
end
end
def
process_relation_item!
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
relation_object
=
build_relation
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
return
unless
relation_object
return
if
project?
&&
group_model?
(
relation_object
)
relation_object
.
assign_attributes
(
importable_class_sym
=>
@importable
)
import_failure_service
.
with_retry
(
action:
'relation_object.save!'
,
relation_key:
relation_key
,
relation_index:
relation_index
)
do
relation_object
.
save!
log_relation_creation
(
@importable
,
relation_key
,
relation_object
)
end
rescue
StandardError
=>
e
import_failure_service
.
log_import_failure
(
source:
'process_relation_item!'
,
relation_key:
relation_key
,
relation_index:
relation_index
,
exception:
e
)
end
def
import_failure_service
@import_failure_service
||=
ImportFailureService
.
new
(
@importable
)
end
def
relations
@relations
||=
@reader
.
attributes_finder
.
find_relations_tree
(
importable_class_sym
)
.
deep_stringify_keys
end
def
update_params!
params
=
@importable_attributes
.
except
(
*
relations
.
keys
.
map
(
&
:to_s
))
params
=
params
.
merge
(
present_override_params
)
# Cleaning all imported and overridden params
params
=
Gitlab
::
ImportExport
::
AttributeCleaner
.
clean
(
relation_hash:
params
,
relation_class:
importable_class
,
excluded_keys:
excluded_keys_for_relation
(
importable_class_sym
))
@importable
.
assign_attributes
(
params
)
modify_attributes
Gitlab
::
Timeless
.
timeless
(
@importable
)
do
@importable
.
save!
end
end
def
present_override_params
# we filter out the empty strings from the overrides
# keeping the default values configured
override_params
&
.
transform_values
do
|
value
|
value
.
is_a?
(
String
)
?
value
.
presence
:
value
end
&
.
compact
end
def
override_params
@importable_override_params
||=
importable_override_params
end
def
importable_override_params
if
@importable
.
respond_to?
(
:import_data
)
@importable
.
import_data
&
.
data
&
.
fetch
(
'override_params'
,
nil
)
||
{}
else
{}
end
end
def
modify_attributes
return
unless
project?
@importable
.
reconcile_shared_runners_setting!
@importable
.
drop_visibility_level!
end
def
build_relations
(
relation_key
,
relation_definition
,
relation_index
,
data_hashes
)
data_hashes
.
map
{
|
data_hash
|
build_relation
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
}
.
tap
{
|
entries
|
entries
.
compact!
}
end
def
build_relation
(
relation_key
,
relation_definition
,
relation_index
,
data_hash
)
# TODO: This is hack to not create relation for the author
# Rather make `RelationFactory#set_note_author` to take care of that
return
data_hash
if
relation_key
==
'author'
||
already_restored?
(
data_hash
)
# create relation objects recursively for all sub-objects
relation_definition
.
each
do
|
sub_relation_key
,
sub_relation_definition
|
transform_sub_relations!
(
data_hash
,
sub_relation_key
,
sub_relation_definition
,
relation_index
)
end
relation
=
@relation_factory
.
create
(
**
relation_factory_params
(
relation_key
,
relation_index
,
data_hash
))
if
relation
&&
!
relation
.
valid?
@shared
.
logger
.
warn
(
message:
"[Project/Group Import] Invalid object relation built"
,
relation_key:
relation_key
,
relation_index:
relation_index
,
relation_class:
relation
.
class
.
name
,
error_messages:
relation
.
errors
.
full_messages
.
join
(
". "
)
)
end
relation
end
# Since we update the data hash in place as we restore relation items,
# and since we also de-duplicate items, we might encounter items that
# have already been restored in a previous iteration.
def
already_restored?
(
relation_item
)
!
relation_item
.
is_a?
(
Hash
)
end
def
transform_sub_relations!
(
data_hash
,
sub_relation_key
,
sub_relation_definition
,
relation_index
)
sub_data_hash
=
data_hash
[
sub_relation_key
]
return
unless
sub_data_hash
# if object is a hash we can create simple object
# as it means that this is 1-to-1 vs 1-to-many
current_item
=
if
sub_data_hash
.
is_a?
(
Array
)
build_relations
(
sub_relation_key
,
sub_relation_definition
,
relation_index
,
sub_data_hash
).
presence
else
build_relation
(
sub_relation_key
,
sub_relation_definition
,
relation_index
,
sub_data_hash
)
end
if
current_item
data_hash
[
sub_relation_key
]
=
current_item
else
data_hash
.
delete
(
sub_relation_key
)
end
end
def
group_model?
(
relation_object
)
GROUP_MODELS
.
include?
(
relation_object
.
class
)
&&
relation_object
.
group_id
end
def
excluded_keys_for_relation
(
relation
)
@reader
.
attributes_finder
.
find_excluded_keys
(
relation
)
end
def
importable_class
@importable
.
class
end
def
importable_class_sym
importable_class
.
to_s
.
downcase
.
to_sym
end
def
relation_factory_params
(
relation_key
,
relation_index
,
data_hash
)
{
relation_index:
relation_index
,
relation_sym:
relation_key
.
to_sym
,
relation_hash:
data_hash
,
importable:
@importable
,
members_mapper:
@members_mapper
,
object_builder:
@object_builder
,
user:
@user
,
excluded_keys:
excluded_keys_for_relation
(
relation_key
)
}
end
# Temporary fix for https://gitlab.com/gitlab-org/gitlab/-/issues/27883 when import from legacy project.json
# This should be removed once legacy JSON format is deprecated.
# Ndjson export file will fix the order during project export.
def
fix_ci_pipelines_not_sorted_on_legacy_project_json!
return
unless
relation_reader
.
legacy?
relation_reader
.
sort_ci_pipelines_by_id
end
# Enable logging of each top-level relation creation when Importing
# into a Group if feature flag is enabled
def
log_relation_creation
(
importable
,
relation_key
,
relation_object
)
root_ancestor_group
=
importable
.
try
(
:root_ancestor
)
return
unless
root_ancestor_group
return
unless
root_ancestor_group
.
instance_of?
(
::
Group
)
return
unless
Feature
.
enabled?
(
:log_import_export_relation_creation
,
root_ancestor_group
)
@shared
.
logger
.
info
(
importable_type:
importable
.
class
.
to_s
,
importable_id:
importable
.
id
,
relation_key:
relation_key
,
relation_id:
relation_object
.
id
,
author_id:
relation_object
.
try
(
:author_id
),
message:
'[Project/Group Import] Created new object relation'
)
end
end
end
end
spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb
0 → 100644
View file @
e06142fc
# frozen_string_literal: true
# This spec is a lightweight version of:
# * project/tree_restorer_spec.rb
#
# In depth testing is being done in the above specs.
# This spec tests that restore project works
# but does not have 100% relation coverage.
require
'spec_helper'
RSpec
.
describe
Gitlab
::
ImportExport
::
Group
::
RelationTreeRestorer
do
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:importable
)
{
create
(
:group
,
parent:
group
)
}
include_context
'relation tree restorer shared context'
do
let
(
:importable_name
)
{
nil
}
end
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/group_exports/no_children/group.json'
}
let
(
:relation_reader
)
do
Gitlab
::
ImportExport
::
Json
::
LegacyReader
::
File
.
new
(
path
,
relation_names:
reader
.
group_relation_names
)
end
let
(
:reader
)
do
Gitlab
::
ImportExport
::
Reader
.
new
(
shared:
shared
,
config:
Gitlab
::
ImportExport
::
Config
.
new
(
config:
Gitlab
::
ImportExport
.
legacy_group_config_file
).
to_h
)
end
let
(
:relation_tree_restorer
)
do
described_class
.
new
(
user:
user
,
shared:
shared
,
relation_reader:
relation_reader
,
object_builder:
Gitlab
::
ImportExport
::
Group
::
ObjectBuilder
,
members_mapper:
members_mapper
,
relation_factory:
Gitlab
::
ImportExport
::
Group
::
RelationFactory
,
reader:
reader
,
importable:
importable
,
importable_path:
nil
,
importable_attributes:
attributes
)
end
subject
{
relation_tree_restorer
.
restore
}
shared_examples
'logging of relations creation'
do
context
'when log_import_export_relation_creation feature flag is enabled'
do
before
do
stub_feature_flags
(
log_import_export_relation_creation:
group
)
end
it
'logs top-level relation creation'
do
expect
(
shared
.
logger
)
.
to
receive
(
:info
)
.
with
(
hash_including
(
message:
'[Project/Group Import] Created new object relation'
))
.
at_least
(
:once
)
subject
end
end
context
'when log_import_export_relation_creation feature flag is disabled'
do
before
do
stub_feature_flags
(
log_import_export_relation_creation:
false
)
end
it
'does not log top-level relation creation'
do
expect
(
shared
.
logger
)
.
to
receive
(
:info
)
.
with
(
hash_including
(
message:
'[Project/Group Import] Created new object relation'
))
.
never
subject
end
end
end
it
'restores group tree'
do
expect
(
subject
).
to
eq
(
true
)
end
include_examples
'logging of relations creation'
end
spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb
→
spec/lib/gitlab/import_export/
project/
relation_tree_restorer_spec.rb
View file @
e06142fc
...
...
@@ -9,20 +9,27 @@
require
'spec_helper'
RSpec
.
describe
Gitlab
::
ImportExport
::
RelationTreeRestorer
do
include_context
'relation tree restorer shared context'
RSpec
.
describe
Gitlab
::
ImportExport
::
Project
::
RelationTreeRestorer
do
let_it_be
(
:importable
,
reload:
true
)
do
create
(
:project
,
:builds_enabled
,
:issues_disabled
,
name:
'project'
,
path:
'project'
)
end
include_context
'relation tree restorer shared context'
do
let
(
:importable_name
)
{
'project'
}
end
let
(
:reader
)
{
Gitlab
::
ImportExport
::
Reader
.
new
(
shared:
shared
)
}
let
(
:relation_tree_restorer
)
do
described_class
.
new
(
user:
user
,
shared:
shared
,
relation_reader:
relation_reader
,
object_builder:
object_b
uilder
,
object_builder:
Gitlab
::
ImportExport
::
Project
::
ObjectB
uilder
,
members_mapper:
members_mapper
,
relation_factory:
relation_f
actory
,
relation_factory:
Gitlab
::
ImportExport
::
Project
::
RelationF
actory
,
reader:
reader
,
importable:
importable
,
importable_path:
importable_path
,
importable_path:
'project'
,
importable_attributes:
attributes
)
end
...
...
@@ -54,7 +61,7 @@ RSpec.describe Gitlab::ImportExport::RelationTreeRestorer do
end
it
'logs top-level relation creation'
do
expect
(
relation_tree_restorer
.
shared
.
logger
)
expect
(
shared
.
logger
)
.
to
receive
(
:info
)
.
with
(
hash_including
(
message:
'[Project/Group Import] Created new object relation'
))
.
at_least
(
:once
)
...
...
@@ -69,7 +76,7 @@ RSpec.describe Gitlab::ImportExport::RelationTreeRestorer do
end
it
'does not log top-level relation creation'
do
expect
(
relation_tree_restorer
.
shared
.
logger
)
expect
(
shared
.
logger
)
.
to
receive
(
:info
)
.
with
(
hash_including
(
message:
'[Project/Group Import] Created new object relation'
))
.
never
...
...
@@ -79,106 +86,65 @@ RSpec.describe Gitlab::ImportExport::RelationTreeRestorer do
end
end
context
'when restoring a project'
do
let_it_be
(
:importable
,
reload:
true
)
do
create
(
:project
,
:builds_enabled
,
:issues_disabled
,
name:
'project'
,
path:
'project'
)
context
'with legacy reader'
do
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/complex/project.json'
}
let
(
:relation_reader
)
do
Gitlab
::
ImportExport
::
Json
::
LegacyReader
::
File
.
new
(
path
,
relation_names:
reader
.
project_relation_names
,
allowed_path:
'project'
)
end
let
(
:importable_name
)
{
'project'
}
let
(
:importable_path
)
{
'project'
}
let
(
:object_builder
)
{
Gitlab
::
ImportExport
::
Project
::
ObjectBuilder
}
let
(
:relation_factory
)
{
Gitlab
::
ImportExport
::
Project
::
RelationFactory
}
let
(
:reader
)
{
Gitlab
::
ImportExport
::
Reader
.
new
(
shared:
shared
)
}
context
'using legacy reader'
do
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/complex/project.json'
}
let
(
:relation_reader
)
do
Gitlab
::
ImportExport
::
Json
::
LegacyReader
::
File
.
new
(
path
,
relation_names:
reader
.
project_relation_names
,
allowed_path:
'project'
)
end
let
(
:attributes
)
{
relation_reader
.
consume_attributes
(
'project'
)
}
it_behaves_like
'import project successfully'
let
(
:attributes
)
{
relation_reader
.
consume_attributes
(
'project'
)
}
context
'logging of relations creation'
do
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:importable
)
do
create
(
:project
,
:builds_enabled
,
:issues_disabled
,
name:
'project'
,
path:
'project'
,
group:
group
)
end
it_behaves_like
'import project successfully'
include_examples
'logging of relations creation'
context
'with logging of relations creation'
do
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:importable
)
do
create
(
:project
,
:builds_enabled
,
:issues_disabled
,
name:
'project'
,
path:
'project'
,
group:
group
)
end
end
context
'using ndjson reader'
do
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/complex/tree'
}
let
(
:relation_reader
)
{
Gitlab
::
ImportExport
::
Json
::
NdjsonReader
.
new
(
path
)
}
it_behaves_like
'import project successfully'
include_examples
'logging of relations creation'
end
end
context
'when inside a group'
do
let_it_be
(
:group
)
do
create
(
:group
,
:disabled_and_unoverridable
)
end
context
'with ndjson reader'
do
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/complex/tree'
}
let
(
:relation_reader
)
{
Gitlab
::
ImportExport
::
Json
::
NdjsonReader
.
new
(
path
)
}
before
do
importable
.
update!
(
shared_runners_enabled:
false
,
group:
group
)
end
it_behaves_like
'import project successfully'
it_behaves_like
'import project successfully'
context
'when inside a group'
do
let_it_be
(
:group
)
do
create
(
:group
,
:disabled_and_unoverridable
)
end
end
context
'with invalid relations'
do
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/project_with_invalid_relations/tree'
}
let
(
:relation_reader
)
{
Gitlab
::
ImportExport
::
Json
::
NdjsonReader
.
new
(
path
)
}
it
'logs the invalid relation and its errors'
do
expect
(
relation_tree_restorer
.
shared
.
logger
)
.
to
receive
(
:warn
)
.
with
(
error_messages:
"Title can't be blank. Title is invalid"
,
message:
'[Project/Group Import] Invalid object relation built'
,
relation_class:
'ProjectLabel'
,
relation_index:
0
,
relation_key:
'labels'
).
once
relation_tree_restorer
.
restore
before
do
importable
.
update!
(
shared_runners_enabled:
false
,
group:
group
)
end
end
end
context
'when restoring a group'
do
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:importable
)
{
create
(
:group
,
parent:
group
)
}
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/group_exports/no_children/group.json'
}
let
(
:importable_name
)
{
nil
}
let
(
:importable_path
)
{
nil
}
let
(
:object_builder
)
{
Gitlab
::
ImportExport
::
Group
::
ObjectBuilder
}
let
(
:relation_factory
)
{
Gitlab
::
ImportExport
::
Group
::
RelationFactory
}
let
(
:relation_reader
)
do
Gitlab
::
ImportExport
::
Json
::
LegacyReader
::
File
.
new
(
path
,
relation_names:
reader
.
group_relation_names
)
end
let
(
:reader
)
do
Gitlab
::
ImportExport
::
Reader
.
new
(
shared:
shared
,
config:
Gitlab
::
ImportExport
::
Config
.
new
(
config:
Gitlab
::
ImportExport
.
legacy_group_config_file
).
to_h
)
it_behaves_like
'import project successfully'
end
end
it
'restores group tree'
do
expect
(
subject
).
to
eq
(
true
)
context
'with invalid relations'
do
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/project_with_invalid_relations/tree'
}
let
(
:relation_reader
)
{
Gitlab
::
ImportExport
::
Json
::
NdjsonReader
.
new
(
path
)
}
it
'logs the invalid relation and its errors'
do
expect
(
shared
.
logger
)
.
to
receive
(
:warn
)
.
with
(
error_messages:
"Title can't be blank. Title is invalid"
,
message:
'[Project/Group Import] Invalid object relation built'
,
relation_class:
'ProjectLabel'
,
relation_index:
0
,
relation_key:
'labels'
).
once
relation_tree_restorer
.
restore
end
include_examples
'logging of relations creation'
end
end
spec/lib/gitlab/import_export/project/sample/relation_tree_restorer_spec.rb
View file @
e06142fc
...
...
@@ -10,19 +10,26 @@
require
'spec_helper'
RSpec
.
describe
Gitlab
::
ImportExport
::
Project
::
Sample
::
RelationTreeRestorer
do
include_context
'relation tree restorer shared context'
let_it_be
(
:importable
)
{
create
(
:project
,
:builds_enabled
,
:issues_disabled
,
name:
'project'
,
path:
'project'
)
}
include_context
'relation tree restorer shared context'
do
let
(
:importable_name
)
{
'project'
}
end
let
(
:reader
)
{
Gitlab
::
ImportExport
::
Reader
.
new
(
shared:
shared
)
}
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/sample_data/tree'
}
let
(
:relation_reader
)
{
Gitlab
::
ImportExport
::
Json
::
NdjsonReader
.
new
(
path
)
}
let
(
:sample_data_relation_tree_restorer
)
do
described_class
.
new
(
user:
user
,
shared:
shared
,
relation_reader:
relation_reader
,
object_builder:
object_b
uilder
,
object_builder:
Gitlab
::
ImportExport
::
Project
::
ObjectB
uilder
,
members_mapper:
members_mapper
,
relation_factory:
relation_f
actory
,
relation_factory:
Gitlab
::
ImportExport
::
Project
::
Sample
::
RelationF
actory
,
reader:
reader
,
importable:
importable
,
importable_path:
importable_path
,
importable_path:
'project'
,
importable_attributes:
attributes
)
end
...
...
@@ -69,32 +76,21 @@ RSpec.describe Gitlab::ImportExport::Project::Sample::RelationTreeRestorer do
end
end
context
'when restoring a project'
do
let
(
:importable
)
{
create
(
:project
,
:builds_enabled
,
:issues_disabled
,
name:
'project'
,
path:
'project'
)
}
let
(
:importable_name
)
{
'project'
}
let
(
:importable_path
)
{
'project'
}
let
(
:object_builder
)
{
Gitlab
::
ImportExport
::
Project
::
ObjectBuilder
}
let
(
:relation_factory
)
{
Gitlab
::
ImportExport
::
Project
::
Sample
::
RelationFactory
}
let
(
:reader
)
{
Gitlab
::
ImportExport
::
Reader
.
new
(
shared:
shared
)
}
let
(
:path
)
{
'spec/fixtures/lib/gitlab/import_export/sample_data/tree'
}
let
(
:relation_reader
)
{
Gitlab
::
ImportExport
::
Json
::
NdjsonReader
.
new
(
path
)
}
it
'initializes relation_factory with date_calculator as parameter'
do
expect
(
Gitlab
::
ImportExport
::
Project
::
Sample
::
RelationFactory
).
to
receive
(
:create
).
with
(
hash_including
(
:date_calculator
)).
at_least
(
:once
).
times
it
'initializes relation_factory with date_calculator as parameter'
do
expect
(
Gitlab
::
ImportExport
::
Project
::
Sample
::
RelationFactory
).
to
receive
(
:create
).
with
(
hash_including
(
:date_calculator
)).
at_least
(
:once
).
times
subject
end
subject
end
context
'when relation tree restorer is initialized'
do
it
'initializes date calculator with due dates'
do
expect
(
Gitlab
::
ImportExport
::
Project
::
Sample
::
DateCalculator
).
to
receive
(
:new
).
with
(
Array
)
context
'when relation tree restorer is initialized'
do
it
'initializes date calculator with due dates'
do
expect
(
Gitlab
::
ImportExport
::
Project
::
Sample
::
DateCalculator
).
to
receive
(
:new
).
with
(
Array
)
sample_data_relation_tree_restorer
end
sample_data_relation_tree_restorer
end
end
context
'using ndjson reader'
do
it_behaves_like
'import project successfully'
end
context
'using ndjson reader'
do
it_behaves_like
'import project successfully'
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment