summaryrefslogtreecommitdiff
path: root/lib/gitlab/import_export/project/tree_restorer.rb
blob: b1d647281abb0e9b09d5d5b8e278b7dac91f131a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# frozen_string_literal: true

module Gitlab
  module ImportExport
    module Project
      class TreeRestorer
        include Gitlab::Utils::StrongMemoize

        attr_reader :user
        attr_reader :shared
        attr_reader :project

        def initialize(user:, shared:, project:)
          @user = user
          @shared = shared
          @project = project
        end

        def restore
          unless relation_reader
            raise Gitlab::ImportExport::Error, 'invalid import format'
          end

          @project_attributes = relation_reader.consume_attributes(importable_path)
          @project_members = relation_reader.consume_relation(importable_path, 'project_members')
            .map(&:first)

          # ensure users are mapped before tree restoration
          # so that even if there is no content to associate
          # users with, they are still added to the project
          members_mapper.map

          if relation_tree_restorer.restore
            import_failure_service.with_retry(action: 'set_latest_merge_request_diff_ids!') do
              @project.merge_requests.set_latest_merge_request_diff_ids!
            end

            true
          else
            false
          end
        rescue => e
          @shared.error(e)
          false
        end

        private

        def relation_reader
          strong_memoize(:relation_reader) do
            [ndjson_relation_reader, legacy_relation_reader]
              .compact.find(&:exist?)
          end
        end

        def ndjson_relation_reader
          return unless Feature.enabled?(:project_import_ndjson, project.namespace, default_enabled: true)

          ImportExport::JSON::NdjsonReader.new(
            File.join(shared.export_path, 'tree')
          )
        end

        def legacy_relation_reader
          ImportExport::JSON::LegacyReader::File.new(
            File.join(shared.export_path, 'project.json'),
            relation_names: reader.project_relation_names,
            allowed_path: importable_path
          )
        end

        def relation_tree_restorer
          @relation_tree_restorer ||= relation_tree_restorer_class.new(
            user: @user,
            shared: @shared,
            relation_reader: relation_reader,
            object_builder: object_builder,
            members_mapper: members_mapper,
            relation_factory: relation_factory,
            reader: reader,
            importable: @project,
            importable_attributes: @project_attributes,
            importable_path: importable_path
          )
        end

        def relation_tree_restorer_class
          sample_data_template? ? Sample::SampleDataRelationTreeRestorer : RelationTreeRestorer
        end

        def sample_data_template?
          @project&.import_data&.data&.dig('sample_data')
        end

        def members_mapper
          @members_mapper ||= Gitlab::ImportExport::MembersMapper.new(exported_members: @project_members,
                                                                      user: @user,
                                                                      importable: @project)
        end

        def object_builder
          Project::ObjectBuilder
        end

        def relation_factory
          Project::RelationFactory
        end

        def reader
          @reader ||= Gitlab::ImportExport::Reader.new(shared: @shared)
        end

        def import_failure_service
          @import_failure_service ||= ImportFailureService.new(@project)
        end

        def importable_path
          "project"
        end
      end
    end
  end
end