1# frozen_string_literal: true 2 3FactoryBot.define do 4 factory :design_version, class: 'DesignManagement::Version' do 5 sha 6 issue { designs.first&.issue || association(:issue) } 7 author { issue&.author || association(:user) } 8 9 transient do 10 designs_count { 1 } 11 created_designs { [] } 12 modified_designs { [] } 13 deleted_designs { [] } 14 end 15 16 trait :importing do 17 issue { nil } 18 19 designs_count { 0 } 20 importing { true } 21 imported { false } 22 end 23 24 trait :imported do 25 importing { false } 26 imported { true } 27 end 28 29 after(:build) do |version, evaluator| 30 # By default all designs are created_designs, so just add them. 31 specific_designs = [].concat( 32 evaluator.created_designs, 33 evaluator.modified_designs, 34 evaluator.deleted_designs 35 ) 36 version.designs += specific_designs 37 38 unless evaluator.designs_count == 0 || version.designs.present? 39 version.designs << create(:design, issue: version.issue) 40 end 41 end 42 43 after :create do |version, evaluator| 44 # FactoryBot does not like methods, so we use lambdas instead 45 events = DesignManagement::Action.events 46 47 version.actions 48 .where(design_id: evaluator.modified_designs.map(&:id)) 49 .update_all(event: events[:modification]) 50 51 version.actions 52 .where(design_id: evaluator.deleted_designs.map(&:id)) 53 .update_all(event: events[:deletion]) 54 55 # Ensure version.issue == design.issue for all version.designs 56 version.designs.update_all(issue_id: version.issue_id) 57 version.designs.reload 58 59 needed = evaluator.designs_count 60 have = version.designs.size 61 62 create_list(:design, [0, needed - have].max, issue: version.issue).each do |d| 63 version.designs << d 64 end 65 66 version.actions.reset 67 end 68 69 # Use this trait to build versions with designs that are backed by Git LFS, committed 70 # to the repository, and with an LfsObject correctly created for it. 71 trait :with_lfs_file do 72 committed 73 74 transient do 75 raw_file { fixture_file_upload('spec/fixtures/dk.png', 'image/png') } 76 lfs_pointer { Gitlab::Git::LfsPointerFile.new(SecureRandom.random_bytes) } 77 file { lfs_pointer.pointer } 78 end 79 80 after :create do |version, evaluator| 81 lfs_object = create(:lfs_object, file: evaluator.raw_file, oid: evaluator.lfs_pointer.sha256, size: evaluator.lfs_pointer.size) 82 create(:lfs_objects_project, project: version.project, lfs_object: lfs_object, repository_type: :design) 83 end 84 end 85 86 # This trait is for versions that must be present in the git repository. 87 trait :committed do 88 transient do 89 file { File.join(Rails.root, 'spec/fixtures/dk.png') } 90 end 91 92 after :create do |version, evaluator| 93 project = version.issue.project 94 repository = project.design_repository 95 repository.create_if_not_exists 96 97 designs = version.designs_by_event 98 base_change = { content: evaluator.file } 99 100 actions = %w[modification deletion].flat_map { |k| designs.fetch(k, []) }.map do |design| 101 base_change.merge(action: :create, file_path: design.full_path) 102 end 103 104 if actions.present? 105 repository.multi_action( 106 evaluator.author, 107 branch_name: 'master', 108 message: "created #{actions.size} files", 109 actions: actions 110 ) 111 end 112 113 mapping = { 114 'creation' => :create, 115 'modification' => :update, 116 'deletion' => :delete 117 } 118 119 version_actions = designs.flat_map do |(event, designs)| 120 base = event == 'deletion' ? {} : base_change 121 designs.map do |design| 122 base.merge(action: mapping[event], file_path: design.full_path) 123 end 124 end 125 126 sha = repository.multi_action( 127 evaluator.author, 128 branch_name: 'master', 129 message: "edited #{version_actions.size} files", 130 actions: version_actions 131 ) 132 133 version.update!(sha: sha) 134 end 135 end 136 end 137end 138