summaryrefslogtreecommitdiff
path: root/spec/factories/design_management/versions.rb
blob: 247a385bd0e4b128822bd8d8308adf448358ec4c (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# frozen_string_literal: true

FactoryBot.define do
  factory :design_version, class: 'DesignManagement::Version' do
    sha
    issue { designs.first&.issue || association(:issue) }
    author { issue&.author || association(:user) }

    transient do
      designs_count { 1 }
      created_designs { [] }
      modified_designs { [] }
      deleted_designs { [] }
    end

    trait :importing do
      issue { nil }

      designs_count { 0 }
      importing { true }
      imported { false }
    end

    trait :imported do
      importing { false }
      imported { true }
    end

    after(:build) do |version, evaluator|
      # By default all designs are created_designs, so just add them.
      specific_designs = [].concat(
        evaluator.created_designs,
        evaluator.modified_designs,
        evaluator.deleted_designs
      )
      version.designs += specific_designs

      unless evaluator.designs_count == 0 || version.designs.present?
        version.designs << create(:design, issue: version.issue)
      end
    end

    after :create do |version, evaluator|
      # FactoryBot does not like methods, so we use lambdas instead
      events = DesignManagement::Action.events

      version.actions
        .where(design_id: evaluator.modified_designs.map(&:id))
        .update_all(event: events[:modification])

      version.actions
        .where(design_id: evaluator.deleted_designs.map(&:id))
        .update_all(event: events[:deletion])

      version.designs.reload
      # Ensure version.issue == design.issue for all version.designs
      version.designs.update_all(issue_id: version.issue_id)

      needed = evaluator.designs_count
      have = version.designs.size

      create_list(:design, [0, needed - have].max, issue: version.issue).each do |d|
        version.designs << d
      end

      version.actions.reset
    end

    # Use this trait to build versions with designs that are backed by Git LFS, committed
    # to the repository, and with an LfsObject correctly created for it.
    trait :with_lfs_file do
      committed

      transient do
        raw_file { fixture_file_upload('spec/fixtures/dk.png', 'image/png') }
        lfs_pointer { Gitlab::Git::LfsPointerFile.new(SecureRandom.random_bytes) }
        file { lfs_pointer.pointer }
      end

      after :create do |version, evaluator|
        lfs_object = create(:lfs_object, file: evaluator.raw_file, oid: evaluator.lfs_pointer.sha256, size: evaluator.lfs_pointer.size)
        create(:lfs_objects_project, project: version.project, lfs_object: lfs_object, repository_type: :design)
      end
    end

    # This trait is for versions that must be present in the git repository.
    trait :committed do
      transient do
        file { File.join(Rails.root, 'spec/fixtures/dk.png') }
      end

      after :create do |version, evaluator|
        project = version.issue.project
        repository = project.design_repository
        repository.create_if_not_exists

        designs = version.designs_by_event
        base_change = { content: evaluator.file }

        actions = %w[modification deletion].flat_map { |k| designs.fetch(k, []) }.map do |design|
          base_change.merge(action: :create, file_path: design.full_path)
        end

        if actions.present?
          repository.multi_action(
            evaluator.author,
            branch_name: 'master',
            message: "created #{actions.size} files",
            actions: actions
          )
        end

        mapping = {
          'creation' => :create,
          'modification' => :update,
          'deletion' => :delete
        }

        version_actions = designs.flat_map do |(event, designs)|
          base = event == 'deletion' ? {} : base_change
          designs.map do |design|
            base.merge(action: mapping[event], file_path: design.full_path)
          end
        end

        sha = repository.multi_action(
          evaluator.author,
          branch_name: 'master',
          message: "edited #{version_actions.size} files",
          actions: version_actions
        )

        version.update!(sha: sha)
      end
    end
  end
end