kintsugi 0.4.3 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +33 -0
- data/.github/workflows/{ci.yml → tests.yml} +2 -1
- data/.rubocop.yml +3 -0
- data/bin/kintsugi +3 -29
- data/kintsugi.gemspec +1 -0
- data/lib/kintsugi/apply_change_to_project.rb +264 -132
- data/lib/kintsugi/cli.rb +2 -1
- data/lib/kintsugi/merge.rb +146 -0
- data/lib/kintsugi/version.rb +1 -1
- data/lib/kintsugi/xcodeproj_extensions.rb +122 -0
- data/lib/kintsugi.rb +29 -148
- data/spec/kintsugi_apply_change_to_project_spec.rb +549 -52
- data/spec/kintsugi_integration_spec.rb +148 -0
- data/spec/spec_helper.rb +3 -0
- metadata +22 -5
| @@ -5,6 +5,7 @@ | |
| 5 5 | 
             
            require "xcodeproj"
         | 
| 6 6 |  | 
| 7 7 | 
             
            require_relative "utils"
         | 
| 8 | 
            +
            require_relative "error"
         | 
| 8 9 | 
             
            require_relative "xcodeproj_extensions"
         | 
| 9 10 |  | 
| 10 11 | 
             
            module Kintsugi
         | 
| @@ -28,26 +29,28 @@ module Kintsugi | |
| 28 29 | 
             
                      puts "Warning: Main group doesn't exist, ignoring changes to it."
         | 
| 29 30 | 
             
                    else
         | 
| 30 31 | 
             
                      apply_change_to_component(project.root_object, "mainGroup",
         | 
| 31 | 
            -
                                                change["rootObject"]["mainGroup"])
         | 
| 32 | 
            +
                                                change["rootObject"]["mainGroup"], "rootObject")
         | 
| 32 33 | 
             
                    end
         | 
| 33 34 | 
             
                  end
         | 
| 34 35 |  | 
| 35 36 | 
             
                  unless change["rootObject"]["projectReferences"].nil?
         | 
| 36 37 | 
             
                    apply_change_to_component(project.root_object, "projectReferences",
         | 
| 37 | 
            -
                                              change["rootObject"]["projectReferences"])
         | 
| 38 | 
            +
                                              change["rootObject"]["projectReferences"], "rootObject")
         | 
| 38 39 | 
             
                  end
         | 
| 39 40 |  | 
| 40 41 | 
             
                  apply_change_to_component(project, "rootObject",
         | 
| 41 42 | 
             
                                            change["rootObject"].reject { |key|
         | 
| 42 43 | 
             
                                              %w[mainGroup projectReferences].include?(key)
         | 
| 43 | 
            -
                                            })
         | 
| 44 | 
            +
                                            }, "")
         | 
| 44 45 | 
             
                end
         | 
| 45 46 |  | 
| 46 47 | 
             
                private
         | 
| 47 48 |  | 
| 48 | 
            -
                def apply_change_to_component(parent_component, change_name, change)
         | 
| 49 | 
            +
                def apply_change_to_component(parent_component, change_name, change, parent_change_path)
         | 
| 49 50 | 
             
                  return if change_name == "displayName"
         | 
| 50 51 |  | 
| 52 | 
            +
                  change_path = parent_change_path.empty? ? change_name : "#{parent_change_path}/#{change_name}"
         | 
| 53 | 
            +
             | 
| 51 54 | 
             
                  attribute_name = attribute_name_from_change_name(change_name)
         | 
| 52 55 | 
             
                  if simple_attribute?(parent_component, attribute_name)
         | 
| 53 56 | 
             
                    apply_change_to_simple_attribute(parent_component, attribute_name, change)
         | 
| @@ -61,7 +64,7 @@ module Kintsugi | |
| 61 64 | 
             
                    component = child_component(parent_component, change_name)
         | 
| 62 65 |  | 
| 63 66 | 
             
                    if component.nil?
         | 
| 64 | 
            -
                      add_missing_component_if_valid(parent_component, change_name, change)
         | 
| 67 | 
            +
                      add_missing_component_if_valid(parent_component, change_name, change, change_path)
         | 
| 65 68 | 
             
                      return
         | 
| 66 69 | 
             
                    end
         | 
| 67 70 | 
             
                  end
         | 
| @@ -75,11 +78,12 @@ module Kintsugi | |
| 75 78 |  | 
| 76 79 | 
             
                  (change[:added] || []).each do |added_change|
         | 
| 77 80 | 
             
                    is_object_list = component.is_a?(Xcodeproj::Project::ObjectList)
         | 
| 78 | 
            -
                    add_child_to_component(is_object_list ? parent_component : component, added_change | 
| 81 | 
            +
                    add_child_to_component(is_object_list ? parent_component : component, added_change,
         | 
| 82 | 
            +
                                           change_path)
         | 
| 79 83 | 
             
                  end
         | 
| 80 84 |  | 
| 81 85 | 
             
                  subchanges_of_change(change).each do |subchange_name, subchange|
         | 
| 82 | 
            -
                    apply_change_to_component(component, subchange_name, subchange)
         | 
| 86 | 
            +
                    apply_change_to_component(component, subchange_name, subchange, change_path)
         | 
| 83 87 | 
             
                  end
         | 
| 84 88 | 
             
                end
         | 
| 85 89 |  | 
| @@ -92,16 +96,16 @@ module Kintsugi | |
| 92 96 | 
             
                end
         | 
| 93 97 |  | 
| 94 98 | 
             
                def attribute_name_from_change_name(change_name)
         | 
| 95 | 
            -
                  if change_name | 
| 99 | 
            +
                  if %w[fileEncoding repositoryURL].include?(change_name)
         | 
| 96 100 | 
             
                    change_name.to_sym
         | 
| 97 101 | 
             
                  else
         | 
| 98 102 | 
             
                    Xcodeproj::Project::Object::CaseConverter.convert_to_ruby(change_name)
         | 
| 99 103 | 
             
                  end
         | 
| 100 104 | 
             
                end
         | 
| 101 105 |  | 
| 102 | 
            -
                def add_missing_component_if_valid(parent_component, change_name, change)
         | 
| 106 | 
            +
                def add_missing_component_if_valid(parent_component, change_name, change, change_path)
         | 
| 103 107 | 
             
                  if change[:added] && change.compact.count == 1
         | 
| 104 | 
            -
                    add_child_to_component(parent_component, change[:added])
         | 
| 108 | 
            +
                    add_child_to_component(parent_component, change[:added], change_path)
         | 
| 105 109 | 
             
                    return
         | 
| 106 110 | 
             
                  end
         | 
| 107 111 |  | 
| @@ -111,10 +115,7 @@ module Kintsugi | |
| 111 115 |  | 
| 112 116 | 
             
                def replace_component_with_new_type(parent_component, name_in_parent_component, change)
         | 
| 113 117 | 
             
                  old_component = parent_component.send(name_in_parent_component)
         | 
| 114 | 
            -
             | 
| 115 | 
            -
                  new_component = parent_component.project.new(
         | 
| 116 | 
            -
                    Module.const_get("Xcodeproj::Project::#{change["isa"][:added]}")
         | 
| 117 | 
            -
                  )
         | 
| 118 | 
            +
                  new_component = component_of_new_type(parent_component, change, old_component)
         | 
| 118 119 |  | 
| 119 120 | 
             
                  copy_attributes_to_new_component(old_component, new_component)
         | 
| 120 121 |  | 
| @@ -122,6 +123,27 @@ module Kintsugi | |
| 122 123 | 
             
                  new_component
         | 
| 123 124 | 
             
                end
         | 
| 124 125 |  | 
| 126 | 
            +
                def component_of_new_type(parent_component, change, old_component)
         | 
| 127 | 
            +
                  if change["isa"][:added] == "PBXFileReference"
         | 
| 128 | 
            +
                    path = (change["path"] && change["path"][:added]) || old_component.path
         | 
| 129 | 
            +
                    case parent_component
         | 
| 130 | 
            +
                    when Xcodeproj::Project::XCBuildConfiguration
         | 
| 131 | 
            +
                      parent_component.base_configuration_reference = find_file(parent_component.project, path)
         | 
| 132 | 
            +
                      return parent_component.base_configuration_reference
         | 
| 133 | 
            +
                    when Xcodeproj::Project::PBXNativeTarget
         | 
| 134 | 
            +
                      parent_component.product_reference = find_file(parent_component.project, path)
         | 
| 135 | 
            +
                      return parent_component.product_reference
         | 
| 136 | 
            +
                    when Xcodeproj::Project::PBXBuildFile
         | 
| 137 | 
            +
                      parent_component.file_ref = find_file(parent_component.project, path)
         | 
| 138 | 
            +
                      return parent_component.file_ref
         | 
| 139 | 
            +
                    end
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                  parent_component.project.new(
         | 
| 143 | 
            +
                    Module.const_get("Xcodeproj::Project::#{change["isa"][:added]}")
         | 
| 144 | 
            +
                  )
         | 
| 145 | 
            +
                end
         | 
| 146 | 
            +
             | 
| 125 147 | 
             
                def copy_attributes_to_new_component(old_component, new_component)
         | 
| 126 148 | 
             
                  # The change won't describe the attributes that haven't changed, therefore the attributes
         | 
| 127 149 | 
             
                  # are copied to the new component.
         | 
| @@ -164,15 +186,8 @@ module Kintsugi | |
| 164 186 | 
             
                end
         | 
| 165 187 |  | 
| 166 188 | 
             
                def simple_attribute_value_with_change(old_value, change)
         | 
| 167 | 
            -
                   | 
| 168 | 
            -
             | 
| 169 | 
            -
                  if change.key?(:removed)
         | 
| 170 | 
            -
                    new_value = apply_removal_to_simple_attribute(old_value, change[:removed], change[:added])
         | 
| 171 | 
            -
                  end
         | 
| 172 | 
            -
             | 
| 173 | 
            -
                  if change.key?(:added)
         | 
| 174 | 
            -
                    new_value = apply_addition_to_simple_attribute(old_value, change[:added])
         | 
| 175 | 
            -
                  end
         | 
| 189 | 
            +
                  type = simple_attribute_type(old_value, change[:removed], change[:added])
         | 
| 190 | 
            +
                  new_value = new_simple_attribute_value(type, old_value, change[:removed], change[:added])
         | 
| 176 191 |  | 
| 177 192 | 
             
                  subchanges_of_change(change).each do |subchange_name, subchange_value|
         | 
| 178 193 | 
             
                    new_value = new_value || old_value || {}
         | 
| @@ -183,13 +198,67 @@ module Kintsugi | |
| 183 198 | 
             
                  new_value
         | 
| 184 199 | 
             
                end
         | 
| 185 200 |  | 
| 186 | 
            -
                def  | 
| 187 | 
            -
                   | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
             | 
| 201 | 
            +
                def simple_attribute_type(old_value, removed_change, added_change)
         | 
| 202 | 
            +
                  types = [old_value.class, removed_change.class, added_change.class]
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                  if types.include?(Hash)
         | 
| 205 | 
            +
                    unless types.to_set.subset?([Hash, NilClass].to_set)
         | 
| 206 | 
            +
                      raise MergeError, "Cannot apply changes because the types are not compatible. Existing " \
         | 
| 207 | 
            +
                        "value: '#{old_value}', removed change: '#{removed_change}', added change: " \
         | 
| 208 | 
            +
                        "'#{added_change}'"
         | 
| 209 | 
            +
                    end
         | 
| 210 | 
            +
                    Hash
         | 
| 211 | 
            +
                  elsif types.include?(Array)
         | 
| 212 | 
            +
                    unless types.to_set.subset?([Array, String, NilClass].to_set)
         | 
| 213 | 
            +
                      raise MergeError, "Cannot apply changes because the types are not compatible. Existing " \
         | 
| 214 | 
            +
                        "value: '#{old_value}', removed change: '#{removed_change}', added change: " \
         | 
| 215 | 
            +
                        "'#{added_change}'"
         | 
| 216 | 
            +
                    end
         | 
| 217 | 
            +
                    Array
         | 
| 218 | 
            +
                  elsif types.include?(String)
         | 
| 219 | 
            +
                    unless types.to_set.subset?([String, NilClass].to_set)
         | 
| 220 | 
            +
                      raise MergeError, "Cannot apply changes because the types are not compatible. Existing " \
         | 
| 221 | 
            +
                        "value: '#{old_value}', removed change: '#{removed_change}', added change: " \
         | 
| 222 | 
            +
                        "'#{added_change}'"
         | 
| 223 | 
            +
                    end
         | 
| 224 | 
            +
                    String
         | 
| 225 | 
            +
                  else
         | 
| 226 | 
            +
                    raise MergeError, "Unsupported types of all of the values. Existing value: " \
         | 
| 227 | 
            +
                      "'#{old_value}', removed change: '#{removed_change}', added change: '#{added_change}'"
         | 
| 228 | 
            +
                  end
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                def new_simple_attribute_value(type, old_value, removed_change, added_change)
         | 
| 232 | 
            +
                  if type == Hash
         | 
| 233 | 
            +
                    new_hash_simple_attribute_value(old_value, removed_change, added_change)
         | 
| 234 | 
            +
                  elsif type == Array
         | 
| 235 | 
            +
                    new_array_simple_attribute_value(old_value, removed_change, added_change)
         | 
| 236 | 
            +
                  elsif type == String
         | 
| 237 | 
            +
                    new_string_simple_attribute_value(old_value, removed_change, added_change)
         | 
| 238 | 
            +
                  else
         | 
| 239 | 
            +
                    raise MergeError, "Unsupported types of all of the values. Existing value: " \
         | 
| 240 | 
            +
                      "'#{old_value}', removed change: '#{removed_change}', added change: '#{added_change}'"
         | 
| 241 | 
            +
                  end
         | 
| 242 | 
            +
                end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                def new_hash_simple_attribute_value(old_value, removed_change, added_change)
         | 
| 245 | 
            +
                  return added_change if ((old_value || {}).to_a - (removed_change || {}).to_a).empty?
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                  # First apply the added change to see if there are any conflicts with it.
         | 
| 248 | 
            +
                  new_value = (old_value || {}).merge(added_change || {})
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                  unless (old_value.to_a - new_value.to_a).empty?
         | 
| 251 | 
            +
                    raise MergeError, "New hash #{change} contains values that conflict with old hash " \
         | 
| 252 | 
            +
                      "#{old_value}"
         | 
| 253 | 
            +
                  end
         | 
| 254 | 
            +
             | 
| 255 | 
            +
                  if removed_change.nil?
         | 
| 256 | 
            +
                    return new_value
         | 
| 257 | 
            +
                  end
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                  new_value
         | 
| 260 | 
            +
                    .reject do |key, value|
         | 
| 261 | 
            +
                      if value != removed_change[key] && value != (added_change || {})[key]
         | 
| 193 262 | 
             
                        raise MergeError, "Trying to remove value '#{removed_change[key]}' of hash with key " \
         | 
| 194 263 | 
             
                          "'#{key}' but it changed to #{value}. This is considered a conflict that should be " \
         | 
| 195 264 | 
             
                          "resolved manually."
         | 
| @@ -197,41 +266,31 @@ module Kintsugi | |
| 197 266 |  | 
| 198 267 | 
             
                      removed_change.key?(key)
         | 
| 199 268 | 
             
                    end
         | 
| 200 | 
            -
             | 
| 201 | 
            -
                    if old_value != removed_change && !old_value.nil? && added_change != old_value
         | 
| 202 | 
            -
                      raise MergeError, "Trying to remove value '#{removed_change}', but the existing value " \
         | 
| 203 | 
            -
                        "is '#{old_value}'. This is considered a conflict that should be resolved manually."
         | 
| 204 | 
            -
                    end
         | 
| 269 | 
            +
                end
         | 
| 205 270 |  | 
| 206 | 
            -
             | 
| 207 | 
            -
                   | 
| 208 | 
            -
                     | 
| 209 | 
            -
                   | 
| 210 | 
            -
             | 
| 271 | 
            +
                def new_array_simple_attribute_value(old_value, removed_change, added_change)
         | 
| 272 | 
            +
                  if old_value.is_a?(String)
         | 
| 273 | 
            +
                    old_value = [old_value]
         | 
| 274 | 
            +
                  end
         | 
| 275 | 
            +
                  if removed_change.is_a?(String)
         | 
| 276 | 
            +
                    removed_change = [removed_change]
         | 
| 277 | 
            +
                  end
         | 
| 278 | 
            +
                  if added_change.is_a?(String)
         | 
| 279 | 
            +
                    added_change = [added_change]
         | 
| 211 280 | 
             
                  end
         | 
| 212 | 
            -
                end
         | 
| 213 281 |  | 
| 214 | 
            -
             | 
| 215 | 
            -
                  case change
         | 
| 216 | 
            -
                  when Array
         | 
| 217 | 
            -
                    (old_value || []) + change
         | 
| 218 | 
            -
                  when Hash
         | 
| 219 | 
            -
                    old_value ||= {}
         | 
| 220 | 
            -
                    new_value = old_value.merge(change)
         | 
| 282 | 
            +
                  return added_change if ((old_value || []) - (removed_change || [])).empty?
         | 
| 221 283 |  | 
| 222 | 
            -
             | 
| 223 | 
            -
             | 
| 224 | 
            -
                        "#{old_value}"
         | 
| 225 | 
            -
                    end
         | 
| 284 | 
            +
                  (old_value || []) + (added_change || []) - (removed_change || [])
         | 
| 285 | 
            +
                end
         | 
| 226 286 |  | 
| 227 | 
            -
             | 
| 228 | 
            -
                   | 
| 229 | 
            -
                     | 
| 230 | 
            -
             | 
| 231 | 
            -
                    nil
         | 
| 232 | 
            -
                  else
         | 
| 233 | 
            -
                    raise MergeError, "Unsupported change #{change} of type #{change.class}"
         | 
| 287 | 
            +
                def new_string_simple_attribute_value(old_value, removed_change, added_change)
         | 
| 288 | 
            +
                  if old_value != removed_change && !old_value.nil? && added_change != old_value
         | 
| 289 | 
            +
                    raise MergeError, "Trying to remove value '#{removed_change || "nil"}', but the existing " \
         | 
| 290 | 
            +
                      "value is '#{old_value}'. This is considered a conflict that should be resolved manually."
         | 
| 234 291 | 
             
                  end
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                  added_change
         | 
| 235 294 | 
             
                end
         | 
| 236 295 |  | 
| 237 296 | 
             
                def remove_component(component, change)
         | 
| @@ -260,56 +319,94 @@ module Kintsugi | |
| 260 319 | 
             
                  end
         | 
| 261 320 | 
             
                end
         | 
| 262 321 |  | 
| 263 | 
            -
                def add_child_to_component(component, change)
         | 
| 322 | 
            +
                def add_child_to_component(component, change, component_change_path)
         | 
| 323 | 
            +
                  change_path = "#{component_change_path}/#{change["displayName"]}"
         | 
| 324 | 
            +
             | 
| 264 325 | 
             
                  if change["ProjectRef"] && change["ProductGroup"]
         | 
| 265 | 
            -
                    add_subproject_reference(component, change)
         | 
| 326 | 
            +
                    add_subproject_reference(component, change, change_path)
         | 
| 266 327 | 
             
                    return
         | 
| 267 328 | 
             
                  end
         | 
| 268 329 |  | 
| 269 330 | 
             
                  case change["isa"]
         | 
| 270 331 | 
             
                  when "PBXNativeTarget"
         | 
| 271 | 
            -
                    add_target(component, change)
         | 
| 332 | 
            +
                    add_target(component, change, change_path)
         | 
| 272 333 | 
             
                  when "PBXAggregateTarget"
         | 
| 273 | 
            -
                    add_aggregate_target(component, change)
         | 
| 334 | 
            +
                    add_aggregate_target(component, change, change_path)
         | 
| 274 335 | 
             
                  when "PBXFileReference"
         | 
| 275 | 
            -
                    add_file_reference(component, change)
         | 
| 336 | 
            +
                    add_file_reference(component, change, change_path)
         | 
| 276 337 | 
             
                  when "PBXGroup"
         | 
| 277 | 
            -
                    add_group(component, change)
         | 
| 338 | 
            +
                    add_group(component, change, change_path)
         | 
| 278 339 | 
             
                  when "PBXContainerItemProxy"
         | 
| 279 | 
            -
                    add_container_item_proxy(component, change)
         | 
| 340 | 
            +
                    add_container_item_proxy(component, change, change_path)
         | 
| 280 341 | 
             
                  when "PBXTargetDependency"
         | 
| 281 | 
            -
                    add_target_dependency(component, change)
         | 
| 342 | 
            +
                    add_target_dependency(component, change, change_path)
         | 
| 282 343 | 
             
                  when "PBXBuildFile"
         | 
| 283 | 
            -
                    add_build_file(component, change)
         | 
| 344 | 
            +
                    add_build_file(component, change, change_path)
         | 
| 284 345 | 
             
                  when "XCConfigurationList"
         | 
| 285 | 
            -
                    add_build_configuration_list(component, change)
         | 
| 346 | 
            +
                    add_build_configuration_list(component, change, change_path)
         | 
| 286 347 | 
             
                  when "XCBuildConfiguration"
         | 
| 287 | 
            -
                    add_build_configuration(component, change)
         | 
| 348 | 
            +
                    add_build_configuration(component, change, change_path)
         | 
| 288 349 | 
             
                  when "PBXHeadersBuildPhase"
         | 
| 289 | 
            -
                    add_headers_build_phase(component, change)
         | 
| 350 | 
            +
                    add_headers_build_phase(component, change, change_path)
         | 
| 290 351 | 
             
                  when "PBXSourcesBuildPhase"
         | 
| 291 | 
            -
                    add_sources_build_phase(component, change)
         | 
| 352 | 
            +
                    add_sources_build_phase(component, change, change_path)
         | 
| 292 353 | 
             
                  when "PBXCopyFilesBuildPhase"
         | 
| 293 | 
            -
                    add_copy_files_build_phase(component, change)
         | 
| 354 | 
            +
                    add_copy_files_build_phase(component, change, change_path)
         | 
| 294 355 | 
             
                  when "PBXShellScriptBuildPhase"
         | 
| 295 | 
            -
                    add_shell_script_build_phase(component, change)
         | 
| 356 | 
            +
                    add_shell_script_build_phase(component, change, change_path)
         | 
| 296 357 | 
             
                  when "PBXFrameworksBuildPhase"
         | 
| 297 | 
            -
                    add_frameworks_build_phase(component, change)
         | 
| 358 | 
            +
                    add_frameworks_build_phase(component, change, change_path)
         | 
| 298 359 | 
             
                  when "PBXResourcesBuildPhase"
         | 
| 299 | 
            -
                    add_resources_build_phase(component, change)
         | 
| 360 | 
            +
                    add_resources_build_phase(component, change, change_path)
         | 
| 300 361 | 
             
                  when "PBXBuildRule"
         | 
| 301 | 
            -
                    add_build_rule(component, change)
         | 
| 362 | 
            +
                    add_build_rule(component, change, change_path)
         | 
| 302 363 | 
             
                  when "PBXVariantGroup"
         | 
| 303 | 
            -
                    add_variant_group(component, change)
         | 
| 364 | 
            +
                    add_variant_group(component, change, change_path)
         | 
| 304 365 | 
             
                  when "PBXReferenceProxy"
         | 
| 305 | 
            -
                    add_reference_proxy(component, change)
         | 
| 366 | 
            +
                    add_reference_proxy(component, change, change_path)
         | 
| 367 | 
            +
                  when "XCSwiftPackageProductDependency"
         | 
| 368 | 
            +
                    add_swift_package_product_dependency(component, change, change_path)
         | 
| 369 | 
            +
                  when "XCRemoteSwiftPackageReference"
         | 
| 370 | 
            +
                    add_remote_swift_package_reference(component, change, change_path)
         | 
| 306 371 | 
             
                  else
         | 
| 307 372 | 
             
                    raise MergeError, "Trying to add unsupported component type #{change["isa"]}. Full " \
         | 
| 308 373 | 
             
                      "component change is: #{change}"
         | 
| 309 374 | 
             
                  end
         | 
| 310 375 | 
             
                end
         | 
| 311 376 |  | 
| 312 | 
            -
                def  | 
| 377 | 
            +
                def add_remote_swift_package_reference(containing_component, change, change_path)
         | 
| 378 | 
            +
                  remote_swift_package_reference =
         | 
| 379 | 
            +
                    containing_component.project.new(Xcodeproj::Project::XCRemoteSwiftPackageReference)
         | 
| 380 | 
            +
                  add_attributes_to_component(remote_swift_package_reference, change, change_path)
         | 
| 381 | 
            +
             | 
| 382 | 
            +
                  case containing_component
         | 
| 383 | 
            +
                  when Xcodeproj::Project::XCSwiftPackageProductDependency
         | 
| 384 | 
            +
                    containing_component.package = remote_swift_package_reference
         | 
| 385 | 
            +
                  when Xcodeproj::Project::PBXProject
         | 
| 386 | 
            +
                    containing_component.package_references << remote_swift_package_reference
         | 
| 387 | 
            +
                  else
         | 
| 388 | 
            +
                    raise MergeError, "Trying to add remote swift package reference to an unsupported " \
         | 
| 389 | 
            +
                      "component type #{containing_component.isa}. Change is: #{change}"
         | 
| 390 | 
            +
                  end
         | 
| 391 | 
            +
                end
         | 
| 392 | 
            +
             | 
| 393 | 
            +
                def add_swift_package_product_dependency(containing_component, change, change_path)
         | 
| 394 | 
            +
                  swift_package_product_dependency =
         | 
| 395 | 
            +
                    containing_component.project.new(Xcodeproj::Project::XCSwiftPackageProductDependency)
         | 
| 396 | 
            +
                  add_attributes_to_component(swift_package_product_dependency, change, change_path)
         | 
| 397 | 
            +
             | 
| 398 | 
            +
                  case containing_component
         | 
| 399 | 
            +
                  when Xcodeproj::Project::PBXBuildFile
         | 
| 400 | 
            +
                    containing_component.product_ref = swift_package_product_dependency
         | 
| 401 | 
            +
                  when Xcodeproj::Project::PBXNativeTarget
         | 
| 402 | 
            +
                    containing_component.package_product_dependencies << swift_package_product_dependency
         | 
| 403 | 
            +
                  else
         | 
| 404 | 
            +
                    raise MergeError, "Trying to add swift package product dependency to an unsupported " \
         | 
| 405 | 
            +
                      "component type #{containing_component.isa}. Change is: #{change}"
         | 
| 406 | 
            +
                  end
         | 
| 407 | 
            +
                end
         | 
| 408 | 
            +
             | 
| 409 | 
            +
                def add_reference_proxy(containing_component, change, change_path)
         | 
| 313 410 | 
             
                  case containing_component
         | 
| 314 411 | 
             
                  when Xcodeproj::Project::PBXBuildFile
         | 
| 315 412 | 
             
                    # If there are two file references that refer to the same file, one with a build file and
         | 
| @@ -331,74 +428,78 @@ module Kintsugi | |
| 331 428 | 
             
                  when Xcodeproj::Project::PBXGroup
         | 
| 332 429 | 
             
                    reference_proxy = containing_component.project.new(Xcodeproj::Project::PBXReferenceProxy)
         | 
| 333 430 | 
             
                    containing_component << reference_proxy
         | 
| 334 | 
            -
                    add_attributes_to_component(reference_proxy, change)
         | 
| 431 | 
            +
                    add_attributes_to_component(reference_proxy, change, change_path)
         | 
| 335 432 | 
             
                  else
         | 
| 336 433 | 
             
                    raise MergeError, "Trying to add reference proxy to an unsupported component type " \
         | 
| 337 434 | 
             
                      "#{containing_component.isa}. Change is: #{change}"
         | 
| 338 435 | 
             
                  end
         | 
| 339 436 | 
             
                end
         | 
| 340 437 |  | 
| 341 | 
            -
                def add_variant_group(containing_component, change)
         | 
| 438 | 
            +
                def add_variant_group(containing_component, change, change_path)
         | 
| 342 439 | 
             
                  case containing_component
         | 
| 343 440 | 
             
                  when Xcodeproj::Project::PBXBuildFile
         | 
| 344 441 | 
             
                    containing_component.file_ref =
         | 
| 345 442 | 
             
                      find_variant_group(containing_component.project, change["displayName"])
         | 
| 346 443 | 
             
                  when Xcodeproj::Project::PBXGroup, Xcodeproj::Project::PBXVariantGroup
         | 
| 444 | 
            +
                    unless adding_files_and_groups_allowed?(change_path)
         | 
| 445 | 
            +
                      return
         | 
| 446 | 
            +
                    end
         | 
| 447 | 
            +
             | 
| 347 448 | 
             
                    variant_group = containing_component.project.new(Xcodeproj::Project::PBXVariantGroup)
         | 
| 348 449 | 
             
                    containing_component.children << variant_group
         | 
| 349 | 
            -
                    add_attributes_to_component(variant_group, change)
         | 
| 450 | 
            +
                    add_attributes_to_component(variant_group, change, change_path)
         | 
| 350 451 | 
             
                  else
         | 
| 351 452 | 
             
                    raise MergeError, "Trying to add variant group to an unsupported component type " \
         | 
| 352 453 | 
             
                      "#{containing_component.isa}. Change is: #{change}"
         | 
| 353 454 | 
             
                  end
         | 
| 354 455 | 
             
                end
         | 
| 355 456 |  | 
| 356 | 
            -
                def add_build_rule(target, change)
         | 
| 457 | 
            +
                def add_build_rule(target, change, change_path)
         | 
| 357 458 | 
             
                  build_rule = target.project.new(Xcodeproj::Project::PBXBuildRule)
         | 
| 358 459 | 
             
                  target.build_rules << build_rule
         | 
| 359 | 
            -
                  add_attributes_to_component(build_rule, change)
         | 
| 460 | 
            +
                  add_attributes_to_component(build_rule, change, change_path)
         | 
| 360 461 | 
             
                end
         | 
| 361 462 |  | 
| 362 | 
            -
                def add_shell_script_build_phase(target, change)
         | 
| 463 | 
            +
                def add_shell_script_build_phase(target, change, change_path)
         | 
| 363 464 | 
             
                  build_phase = target.new_shell_script_build_phase(change["displayName"])
         | 
| 364 | 
            -
                  add_attributes_to_component(build_phase, change)
         | 
| 465 | 
            +
                  add_attributes_to_component(build_phase, change, change_path)
         | 
| 365 466 | 
             
                end
         | 
| 366 467 |  | 
| 367 | 
            -
                def add_headers_build_phase(target, change)
         | 
| 368 | 
            -
                  add_attributes_to_component(target.headers_build_phase, change)
         | 
| 468 | 
            +
                def add_headers_build_phase(target, change, change_path)
         | 
| 469 | 
            +
                  add_attributes_to_component(target.headers_build_phase, change, change_path)
         | 
| 369 470 | 
             
                end
         | 
| 370 471 |  | 
| 371 | 
            -
                def add_sources_build_phase(target, change)
         | 
| 372 | 
            -
                  add_attributes_to_component(target.source_build_phase, change)
         | 
| 472 | 
            +
                def add_sources_build_phase(target, change, change_path)
         | 
| 473 | 
            +
                  add_attributes_to_component(target.source_build_phase, change, change_path)
         | 
| 373 474 | 
             
                end
         | 
| 374 475 |  | 
| 375 | 
            -
                def add_frameworks_build_phase(target, change)
         | 
| 376 | 
            -
                  add_attributes_to_component(target.frameworks_build_phase, change)
         | 
| 476 | 
            +
                def add_frameworks_build_phase(target, change, change_path)
         | 
| 477 | 
            +
                  add_attributes_to_component(target.frameworks_build_phase, change, change_path)
         | 
| 377 478 | 
             
                end
         | 
| 378 479 |  | 
| 379 | 
            -
                def add_resources_build_phase(target, change)
         | 
| 380 | 
            -
                  add_attributes_to_component(target.resources_build_phase, change)
         | 
| 480 | 
            +
                def add_resources_build_phase(target, change, change_path)
         | 
| 481 | 
            +
                  add_attributes_to_component(target.resources_build_phase, change, change_path)
         | 
| 381 482 | 
             
                end
         | 
| 382 483 |  | 
| 383 | 
            -
                def add_copy_files_build_phase(target, change)
         | 
| 484 | 
            +
                def add_copy_files_build_phase(target, change, change_path)
         | 
| 384 485 | 
             
                  copy_files_phase_name = change["displayName"] == "CopyFiles" ? nil : change["displayName"]
         | 
| 385 486 | 
             
                  copy_files_phase = target.new_copy_files_build_phase(copy_files_phase_name)
         | 
| 386 487 |  | 
| 387 | 
            -
                  add_attributes_to_component(copy_files_phase, change)
         | 
| 488 | 
            +
                  add_attributes_to_component(copy_files_phase, change, change_path)
         | 
| 388 489 | 
             
                end
         | 
| 389 490 |  | 
| 390 | 
            -
                def add_build_configuration_list(target, change)
         | 
| 491 | 
            +
                def add_build_configuration_list(target, change, change_path)
         | 
| 391 492 | 
             
                  target.build_configuration_list = target.project.new(Xcodeproj::Project::XCConfigurationList)
         | 
| 392 | 
            -
                  add_attributes_to_component(target.build_configuration_list, change)
         | 
| 493 | 
            +
                  add_attributes_to_component(target.build_configuration_list, change, change_path)
         | 
| 393 494 | 
             
                end
         | 
| 394 495 |  | 
| 395 | 
            -
                def add_build_configuration(configuration_list, change)
         | 
| 496 | 
            +
                def add_build_configuration(configuration_list, change, change_path)
         | 
| 396 497 | 
             
                  build_configuration = configuration_list.project.new(Xcodeproj::Project::XCBuildConfiguration)
         | 
| 397 498 | 
             
                  configuration_list.build_configurations << build_configuration
         | 
| 398 | 
            -
                  add_attributes_to_component(build_configuration, change)
         | 
| 499 | 
            +
                  add_attributes_to_component(build_configuration, change, change_path)
         | 
| 399 500 | 
             
                end
         | 
| 400 501 |  | 
| 401 | 
            -
                def add_build_file(build_phase, change)
         | 
| 502 | 
            +
                def add_build_file(build_phase, change, change_path)
         | 
| 402 503 | 
             
                  if change["fileRef"].nil?
         | 
| 403 504 | 
             
                    puts "Warning: Trying to add a build file without any file reference to build phase " \
         | 
| 404 505 | 
             
                      "'#{build_phase}'"
         | 
| @@ -407,7 +508,7 @@ module Kintsugi | |
| 407 508 |  | 
| 408 509 | 
             
                  build_file = build_phase.project.new(Xcodeproj::Project::PBXBuildFile)
         | 
| 409 510 | 
             
                  build_phase.files << build_file
         | 
| 410 | 
            -
                  add_attributes_to_component(build_file, change)
         | 
| 511 | 
            +
                  add_attributes_to_component(build_file, change, change_path)
         | 
| 411 512 | 
             
                end
         | 
| 412 513 |  | 
| 413 514 | 
             
                def find_variant_group(project, display_name)
         | 
| @@ -416,7 +517,7 @@ module Kintsugi | |
| 416 517 | 
             
                  end
         | 
| 417 518 | 
             
                end
         | 
| 418 519 |  | 
| 419 | 
            -
                def add_target_dependency(target, change)
         | 
| 520 | 
            +
                def add_target_dependency(target, change, change_path)
         | 
| 420 521 | 
             
                  target_dependency = find_target(target.project, change["displayName"])
         | 
| 421 522 |  | 
| 422 523 | 
             
                  if target_dependency
         | 
| @@ -427,14 +528,14 @@ module Kintsugi | |
| 427 528 | 
             
                  target_dependency = target.project.new(Xcodeproj::Project::PBXTargetDependency)
         | 
| 428 529 |  | 
| 429 530 | 
             
                  target.dependencies << target_dependency
         | 
| 430 | 
            -
                  add_attributes_to_component(target_dependency, change)
         | 
| 531 | 
            +
                  add_attributes_to_component(target_dependency, change, change_path)
         | 
| 431 532 | 
             
                end
         | 
| 432 533 |  | 
| 433 534 | 
             
                def find_target(project, display_name)
         | 
| 434 535 | 
             
                  project.targets.find { |target| target.display_name == display_name }
         | 
| 435 536 | 
             
                end
         | 
| 436 537 |  | 
| 437 | 
            -
                def add_container_item_proxy(component, change)
         | 
| 538 | 
            +
                def add_container_item_proxy(component, change, change_path)
         | 
| 438 539 | 
             
                  container_proxy = component.project.new(Xcodeproj::Project::PBXContainerItemProxy)
         | 
| 439 540 | 
             
                  container_proxy.container_portal = find_containing_project_uuid(component.project, change)
         | 
| 440 541 |  | 
| @@ -447,7 +548,8 @@ module Kintsugi | |
| 447 548 | 
             
                    raise MergeError, "Trying to add container item proxy to an unsupported component type " \
         | 
| 448 549 | 
             
                      "#{containing_component.isa}. Change is: #{change}"
         | 
| 449 550 | 
             
                  end
         | 
| 450 | 
            -
                  add_attributes_to_component(container_proxy, change,  | 
| 551 | 
            +
                  add_attributes_to_component(container_proxy, change, change_path,
         | 
| 552 | 
            +
                                              ignore_keys: ["containerPortal"])
         | 
| 451 553 | 
             
                end
         | 
| 452 554 |  | 
| 453 555 | 
             
                def find_containing_project_uuid(project, container_item_proxy_change)
         | 
| @@ -478,16 +580,22 @@ module Kintsugi | |
| 478 580 | 
             
                  container_item_proxies.first.container_portal
         | 
| 479 581 | 
             
                end
         | 
| 480 582 |  | 
| 481 | 
            -
                def add_subproject_reference(root_object, project_reference_change)
         | 
| 583 | 
            +
                def add_subproject_reference(root_object, project_reference_change, change_path)
         | 
| 482 584 | 
             
                  filter_subproject_without_project_references = lambda do |file_reference|
         | 
| 483 585 | 
             
                    root_object.project_references.find do |project_reference|
         | 
| 484 586 | 
             
                      project_reference.project_ref.uuid == file_reference.uuid
         | 
| 485 587 | 
             
                    end.nil?
         | 
| 486 588 | 
             
                  end
         | 
| 487 589 | 
             
                  subproject_reference =
         | 
| 488 | 
            -
                    find_file(root_object.project, project_reference_change["ProjectRef"],
         | 
| 590 | 
            +
                    find_file(root_object.project, project_reference_change["ProjectRef"]["path"],
         | 
| 489 591 | 
             
                              file_filter: filter_subproject_without_project_references)
         | 
| 490 592 |  | 
| 593 | 
            +
                  unless subproject_reference
         | 
| 594 | 
            +
                    raise MergeError, "No file reference was found for project reference with change " \
         | 
| 595 | 
            +
                      "#{project_reference_change}. This might mean that the file used to exist in the " \
         | 
| 596 | 
            +
                      "project the but was removed at some point"
         | 
| 597 | 
            +
                  end
         | 
| 598 | 
            +
             | 
| 491 599 | 
             
                  attribute =
         | 
| 492 600 | 
             
                    Xcodeproj::Project::PBXProject.references_by_keys_attributes
         | 
| 493 601 | 
             
                                                  .find { |attrb| attrb.name == :project_references }
         | 
| @@ -498,7 +606,7 @@ module Kintsugi | |
| 498 606 | 
             
                  updated_project_reference_change =
         | 
| 499 607 | 
             
                    change_with_updated_subproject_uuid(project_reference_change, subproject_reference.uuid)
         | 
| 500 608 | 
             
                  add_attributes_to_component(project_reference, updated_project_reference_change,
         | 
| 501 | 
            -
                                              ignore_keys: ["ProjectRef"])
         | 
| 609 | 
            +
                                              change_path, ignore_keys: ["ProjectRef"])
         | 
| 502 610 | 
             
                end
         | 
| 503 611 |  | 
| 504 612 | 
             
                def change_with_updated_subproject_uuid(change, subproject_reference_uuid)
         | 
| @@ -510,19 +618,19 @@ module Kintsugi | |
| 510 618 | 
             
                  new_change
         | 
| 511 619 | 
             
                end
         | 
| 512 620 |  | 
| 513 | 
            -
                def add_target(root_object, change)
         | 
| 621 | 
            +
                def add_target(root_object, change, change_path)
         | 
| 514 622 | 
             
                  target = root_object.project.new(Xcodeproj::Project::PBXNativeTarget)
         | 
| 515 623 | 
             
                  root_object.project.targets << target
         | 
| 516 | 
            -
                  add_attributes_to_component(target, change)
         | 
| 624 | 
            +
                  add_attributes_to_component(target, change, change_path)
         | 
| 517 625 | 
             
                end
         | 
| 518 626 |  | 
| 519 | 
            -
                def add_aggregate_target(root_object, change)
         | 
| 627 | 
            +
                def add_aggregate_target(root_object, change, change_path)
         | 
| 520 628 | 
             
                  target = root_object.project.new(Xcodeproj::Project::PBXAggregateTarget)
         | 
| 521 629 | 
             
                  root_object.project.targets << target
         | 
| 522 | 
            -
                  add_attributes_to_component(target, change)
         | 
| 630 | 
            +
                  add_attributes_to_component(target, change, change_path)
         | 
| 523 631 | 
             
                end
         | 
| 524 632 |  | 
| 525 | 
            -
                def add_file_reference(containing_component, change)
         | 
| 633 | 
            +
                def add_file_reference(containing_component, change, change_path)
         | 
| 526 634 | 
             
                  # base configuration reference and product reference always reference a file that exists
         | 
| 527 635 | 
             
                  # inside a group, therefore in these cases the file is searched for.
         | 
| 528 636 | 
             
                  # In the case of group and variant group, the file can't exist in another group, therefore a
         | 
| @@ -530,25 +638,41 @@ module Kintsugi | |
| 530 638 | 
             
                  case containing_component
         | 
| 531 639 | 
             
                  when Xcodeproj::Project::XCBuildConfiguration
         | 
| 532 640 | 
             
                    containing_component.base_configuration_reference =
         | 
| 533 | 
            -
                      find_file(containing_component.project, change)
         | 
| 641 | 
            +
                      find_file(containing_component.project, change["path"])
         | 
| 534 642 | 
             
                  when Xcodeproj::Project::PBXNativeTarget
         | 
| 535 | 
            -
                    containing_component.product_reference = | 
| 643 | 
            +
                    containing_component.product_reference =
         | 
| 644 | 
            +
                      find_file(containing_component.project, change["path"])
         | 
| 536 645 | 
             
                  when Xcodeproj::Project::PBXBuildFile
         | 
| 537 | 
            -
                    containing_component.file_ref = find_file(containing_component.project, change)
         | 
| 646 | 
            +
                    containing_component.file_ref = find_file(containing_component.project, change["path"])
         | 
| 538 647 | 
             
                  when Xcodeproj::Project::PBXGroup, Xcodeproj::Project::PBXVariantGroup
         | 
| 648 | 
            +
                    unless adding_files_and_groups_allowed?(change_path)
         | 
| 649 | 
            +
                      return
         | 
| 650 | 
            +
                    end
         | 
| 651 | 
            +
             | 
| 539 652 | 
             
                    file_reference = containing_component.project.new(Xcodeproj::Project::PBXFileReference)
         | 
| 540 653 | 
             
                    containing_component.children << file_reference
         | 
| 541 654 |  | 
| 542 | 
            -
                    # For some reason, `include_in_index` is set to `1` by | 
| 655 | 
            +
                    # For some reason, `include_in_index` is set to `1` and `source_tree` to `SDKROOT` by
         | 
| 656 | 
            +
                    # default.
         | 
| 543 657 | 
             
                    file_reference.include_in_index = nil
         | 
| 544 | 
            -
                     | 
| 658 | 
            +
                    file_reference.source_tree = nil
         | 
| 659 | 
            +
                    add_attributes_to_component(file_reference, change, change_path)
         | 
| 545 660 | 
             
                  else
         | 
| 546 661 | 
             
                    raise MergeError, "Trying to add file reference to an unsupported component type " \
         | 
| 547 662 | 
             
                      "#{containing_component.isa}. Change is: #{change}"
         | 
| 548 663 | 
             
                  end
         | 
| 549 664 | 
             
                end
         | 
| 550 665 |  | 
| 551 | 
            -
                def  | 
| 666 | 
            +
                def adding_files_and_groups_allowed?(change_path)
         | 
| 667 | 
            +
                  change_path.start_with?("rootObject/mainGroup") ||
         | 
| 668 | 
            +
                    change_path.start_with?("rootObject/projectReferences")
         | 
| 669 | 
            +
                end
         | 
| 670 | 
            +
             | 
| 671 | 
            +
                def add_group(containing_component, change, change_path)
         | 
| 672 | 
            +
                  unless adding_files_and_groups_allowed?(change_path)
         | 
| 673 | 
            +
                    return
         | 
| 674 | 
            +
                  end
         | 
| 675 | 
            +
             | 
| 552 676 | 
             
                  case containing_component
         | 
| 553 677 | 
             
                  when Xcodeproj::Project::ObjectDictionary
         | 
| 554 678 | 
             
                    # It is assumed that an `ObjectDictionary` always represents a project reference.
         | 
| @@ -562,25 +686,29 @@ module Kintsugi | |
| 562 686 | 
             
                      "#{containing_component.isa}. Change is: #{change}"
         | 
| 563 687 | 
             
                  end
         | 
| 564 688 |  | 
| 565 | 
            -
                  add_attributes_to_component(new_group, change)
         | 
| 689 | 
            +
                  add_attributes_to_component(new_group, change, change_path)
         | 
| 566 690 | 
             
                end
         | 
| 567 691 |  | 
| 568 | 
            -
                def add_attributes_to_component(component, change, ignore_keys: [])
         | 
| 692 | 
            +
                def add_attributes_to_component(component, change, change_path, ignore_keys: [])
         | 
| 569 693 | 
             
                  change.each do |change_name, change_value|
         | 
| 570 694 | 
             
                    next if (%w[isa displayName] + ignore_keys).include?(change_name)
         | 
| 571 695 |  | 
| 572 696 | 
             
                    attribute_name = attribute_name_from_change_name(change_name)
         | 
| 573 697 | 
             
                    if simple_attribute?(component, attribute_name)
         | 
| 574 | 
            -
                       | 
| 698 | 
            +
                      simple_attribute_change = {
         | 
| 699 | 
            +
                        added: change_value,
         | 
| 700 | 
            +
                        removed: simple_attribute_default_value(component, attribute_name)
         | 
| 701 | 
            +
                      }
         | 
| 702 | 
            +
                      apply_change_to_simple_attribute(component, attribute_name, simple_attribute_change)
         | 
| 575 703 | 
             
                      next
         | 
| 576 704 | 
             
                    end
         | 
| 577 705 |  | 
| 578 706 | 
             
                    case change_value
         | 
| 579 707 | 
             
                    when Hash
         | 
| 580 | 
            -
                      add_child_to_component(component, change_value)
         | 
| 708 | 
            +
                      add_child_to_component(component, change_value, change_path)
         | 
| 581 709 | 
             
                    when Array
         | 
| 582 710 | 
             
                      change_value.each do |added_attribute_element|
         | 
| 583 | 
            -
                        add_child_to_component(component, added_attribute_element)
         | 
| 711 | 
            +
                        add_child_to_component(component, added_attribute_element, change_path)
         | 
| 584 712 | 
             
                      end
         | 
| 585 713 | 
             
                    else
         | 
| 586 714 | 
             
                      raise MergeError, "Trying to add attribute of unsupported type '#{change_value.class}' " \
         | 
| @@ -589,16 +717,20 @@ module Kintsugi | |
| 589 717 | 
             
                  end
         | 
| 590 718 | 
             
                end
         | 
| 591 719 |  | 
| 592 | 
            -
                def  | 
| 720 | 
            +
                def simple_attribute_default_value(component, attribute_name)
         | 
| 721 | 
            +
                  component.simple_attributes.find do |attribute|
         | 
| 722 | 
            +
                    attribute.name == attribute_name
         | 
| 723 | 
            +
                  end.default_value
         | 
| 724 | 
            +
                end
         | 
| 725 | 
            +
             | 
| 726 | 
            +
                def find_file(project, path, file_filter: ->(_) { true })
         | 
| 593 727 | 
             
                  file_references = project.files.select do |file_reference|
         | 
| 594 | 
            -
                    file_reference.path ==  | 
| 728 | 
            +
                    file_reference.path == path && file_filter.call(file_reference)
         | 
| 595 729 | 
             
                  end
         | 
| 596 730 | 
             
                  if file_references.length > 1
         | 
| 597 | 
            -
                    puts "Debug: Found more than one matching file with path " | 
| 598 | 
            -
                      "'#{file_reference_change["path"]}'. Using the first one."
         | 
| 731 | 
            +
                    puts "Debug: Found more than one matching file with path '#{path}'. Using the first one."
         | 
| 599 732 | 
             
                  elsif file_references.empty?
         | 
| 600 | 
            -
                    puts "Debug: No file reference found for file with path " | 
| 601 | 
            -
                      "'#{file_reference_change["path"]}'."
         | 
| 733 | 
            +
                    puts "Debug: No file reference found for file with path '#{path}'."
         | 
| 602 734 | 
             
                    return
         | 
| 603 735 | 
             
                  end
         | 
| 604 736 |  |