kintsugi 0.3.0 → 0.4.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8ebc10e7941cd3b92850cefb1d5fc0d0046b178b0b3e6bdc929833ff9474302f
4
- data.tar.gz: 5cddf2267408f4361862e68f7391783626c6bf7f536962d0c0021b559c0cc637
3
+ metadata.gz: 35d23332d5548a077db178c966f44413a314276628404a7a9e70d7e2ae45da96
4
+ data.tar.gz: ea35a4c7587ddb9243103d4c249050900505e630beb8a3764ad7e083360db320
5
5
  SHA512:
6
- metadata.gz: b052e5047b603307043b708d804678094ac38ee4e392a3de1d5f94b1ca37a552ff5999320a1168f976f803620cb2072e44712dd49a6fc87d929e666248b64ccf
7
- data.tar.gz: 213fea0a670e021ae68dae8669e216da4fc19039e71e059e6c33b57adbc753ae824e28d1a5d6b806527215b057a8fd354481c8772794337d73daa88e6c884300
6
+ metadata.gz: c9731d92243eff91a6a33ae674a936e274c1cfc58979ceedae1248bdb0d6602fbc51d0c192e6f982aa1a150f1fcc2874d0a0255f11ed9aaa68abefae81212ee7
7
+ data.tar.gz: a96ac801a8ea82a2893d41b25fc7a7fdfd928fba280f6f837c83a49b7b02358d124fcac6d2bd377230f3ab14d3f5f16d8b4de3c9524a1c96cf2ffff927377233
data/README.md CHANGED
@@ -40,15 +40,22 @@ And see the magic happen! :sparkles:
40
40
 
41
41
  ### Git merge driver
42
42
 
43
- To use Kintsugi as a Git merge driver, follow these steps:
43
+ You can setup Kintsugi to automatically resolve conflicts that occur in `pbxproj` files when such conflicts occur.
44
44
 
45
- - Add it as driver to Git config file by running the following:
45
+ #### Automatic install
46
+
47
+ Run `kintsugi install-driver`. This will install Kintsugi as a merge driver globally. Note that Kintsugi needs to be in your `PATH`.
48
+
49
+ ❗ Do not install with bundler because the installation might succeed even if Kintsugi is not in `PATH`.
50
+
51
+ #### Manual install
52
+
53
+ - Add Kintsugi as driver to Git config file by running the following:
46
54
  ```sh
47
55
  git config merge.kintsugi.name "Kintsugi driver" # Or any other name you prefer
48
- git config merge.kintsugi.driver "kintsugi driver %O %A %B %P"
56
+ git config merge.kintsugi.driver "<path_to_kintsugi> driver %O %A %B %P"
49
57
  ```
50
58
 
51
- `kintsugi` should be in your `PATH`.
52
59
  Run `git config` with `--global` to add this to the global config file.
53
60
 
54
61
  - Add the following line to the `.gitattributes` file at the root of the repository:
@@ -65,7 +72,11 @@ See our [Contribution guidelines](./CONTRIBUTING.md).
65
72
 
66
73
  ## Alternatives
67
74
 
68
- - [XcodeGen](https://github.com/yonaskolb/XcodeGen): You can commit this JSON file into Git instead of the `.pbxproj` file. Then resolving conflicts is much easier.
75
+ All of the alternatives below allow you to generate your Xcode projects based on a spec or manifest. You commit these files to git, and can even remove the `.xcodeproj` files from git.
76
+
77
+ - [XcodeGen](https://github.com/yonaskolb/XcodeGen)
78
+ - [Tuist](https://github.com/tuist)
79
+ - [Xcake](https://github.com/igor-makarov/xcake)
69
80
 
70
81
  ## Copyright
71
82
 
data/bin/kintsugi CHANGED
@@ -6,6 +6,7 @@
6
6
 
7
7
  require "kintsugi"
8
8
  require_relative "../lib/kintsugi/cli"
9
+ require_relative "../lib/kintsugi/error"
9
10
 
10
11
  def parse_options!(command, argv)
11
12
  options = {}
@@ -28,4 +29,11 @@ command =
28
29
  end
29
30
 
30
31
  options = parse_options!(command, ARGV)
31
- command.action.call(options, ARGV, command.option_parser)
32
+
33
+ begin
34
+ command.action.call(options, ARGV)
35
+ rescue ArgumentError => e
36
+ puts "#{e.class}: #{e}"
37
+ rescue Kintsugi::MergeError => e
38
+ puts e
39
+ end
data/kintsugi.gemspec CHANGED
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.test_files = spec.files.grep(%r{^(spec)/})
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_dependency "xcodeproj", "1.19.0"
25
+ spec.add_dependency "xcodeproj", ">= 1.19.0", "<= 1.21.0"
26
26
 
27
27
  spec.add_development_dependency "rake", "~> 13.0"
28
28
  spec.add_development_dependency "rspec", "~> 3.9"
@@ -167,7 +167,7 @@ module Kintsugi
167
167
  new_value = nil
168
168
 
169
169
  if change.key?(:removed)
170
- new_value = apply_removal_to_simple_attribute(old_value, change[:removed])
170
+ new_value = apply_removal_to_simple_attribute(old_value, change[:removed], change[:added])
171
171
  end
172
172
 
173
173
  if change.key?(:added)
@@ -183,30 +183,31 @@ module Kintsugi
183
183
  new_value
184
184
  end
185
185
 
186
- def apply_removal_to_simple_attribute(old_value, change)
187
- case change
186
+ def apply_removal_to_simple_attribute(old_value, removed_change, added_change)
187
+ case removed_change
188
188
  when Array
189
- (old_value || []) - change
189
+ (old_value || []) - removed_change
190
190
  when Hash
191
191
  (old_value || {}).reject do |key, value|
192
- if value != change[key]
193
- raise "Trying to remove value #{change[key]} of hash with key #{key} but it changed " \
194
- "to #{value}. This is considered a conflict that should be resolved manually."
192
+ if value != removed_change[key] && added_change[key] != value
193
+ raise MergeError, "Trying to remove value '#{removed_change[key]}' of hash with key " \
194
+ "'#{key}' but it changed to #{value}. This is considered a conflict that should be " \
195
+ "resolved manually."
195
196
  end
196
197
 
197
- change.key?(key)
198
+ removed_change.key?(key)
198
199
  end
199
200
  when String
200
- if old_value != change && !old_value.nil?
201
- raise "Trying to remove value #{change}, but the existing value is #{old_value}. This " \
202
- "is considered a conflict that should be resolved manually."
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."
203
204
  end
204
205
 
205
206
  nil
206
207
  when nil
207
208
  nil
208
209
  else
209
- raise "Unsupported change #{change} of type #{change.class}"
210
+ raise MergeError, "Unsupported change #{removed_change} of type #{removed_change.class}"
210
211
  end
211
212
  end
212
213
 
@@ -219,7 +220,8 @@ module Kintsugi
219
220
  new_value = old_value.merge(change)
220
221
 
221
222
  unless (old_value.to_a - new_value.to_a).empty?
222
- raise "New hash #{change} contains values that conflict with old hash #{old_value}"
223
+ raise MergeError, "New hash #{change} contains values that conflict with old hash " \
224
+ "#{old_value}"
223
225
  end
224
226
 
225
227
  new_value
@@ -228,14 +230,15 @@ module Kintsugi
228
230
  when nil
229
231
  nil
230
232
  else
231
- raise "Unsupported change #{change} of type #{change.class}"
233
+ raise MergeError, "Unsupported change #{change} of type #{change.class}"
232
234
  end
233
235
  end
234
236
 
235
237
  def remove_component(component, change)
236
238
  if component.to_tree_hash != change
237
- raise "Trying to remove an object that changed since then. This is considered a conflict " \
238
- "that should be resolved manually. Name of the object is: '#{component.display_name}'"
239
+ raise MergeError, "Trying to remove an object that changed since then. This is " \
240
+ "considered a conflict that should be resolved manually. Name of the object is: " \
241
+ "'#{component.display_name}'"
239
242
  end
240
243
 
241
244
  if change["isa"] == "PBXFileReference"
@@ -301,8 +304,8 @@ module Kintsugi
301
304
  when "PBXReferenceProxy"
302
305
  add_reference_proxy(component, change)
303
306
  else
304
- raise "Trying to add unsupported component type #{change["isa"]}. Full component change " \
305
- "is: #{change}"
307
+ raise MergeError, "Trying to add unsupported component type #{change["isa"]}. Full " \
308
+ "component change is: #{change}"
306
309
  end
307
310
  end
308
311
 
@@ -330,7 +333,7 @@ module Kintsugi
330
333
  containing_component << reference_proxy
331
334
  add_attributes_to_component(reference_proxy, change)
332
335
  else
333
- raise "Trying to add reference proxy to an unsupported component type " \
336
+ raise MergeError, "Trying to add reference proxy to an unsupported component type " \
334
337
  "#{containing_component.isa}. Change is: #{change}"
335
338
  end
336
339
  end
@@ -345,7 +348,7 @@ module Kintsugi
345
348
  containing_component.children << variant_group
346
349
  add_attributes_to_component(variant_group, change)
347
350
  else
348
- raise "Trying to add variant group to an unsupported component type " \
351
+ raise MergeError, "Trying to add variant group to an unsupported component type " \
349
352
  "#{containing_component.isa}. Change is: #{change}"
350
353
  end
351
354
  end
@@ -441,7 +444,7 @@ module Kintsugi
441
444
  when "PBXReferenceProxy"
442
445
  component.remote_ref = container_proxy
443
446
  else
444
- raise "Trying to add container item proxy to an unsupported component type " \
447
+ raise MergeError, "Trying to add container item proxy to an unsupported component type " \
445
448
  "#{containing_component.isa}. Change is: #{change}"
446
449
  end
447
450
  add_attributes_to_component(container_proxy, change, ignore_keys: ["containerPortal"])
@@ -540,7 +543,7 @@ module Kintsugi
540
543
  file_reference.include_in_index = nil
541
544
  add_attributes_to_component(file_reference, change)
542
545
  else
543
- raise "Trying to add file reference to an unsupported component type " \
546
+ raise MergeError, "Trying to add file reference to an unsupported component type " \
544
547
  "#{containing_component.isa}. Change is: #{change}"
545
548
  end
546
549
  end
@@ -555,8 +558,8 @@ module Kintsugi
555
558
  new_group = containing_component.project.new(Xcodeproj::Project::PBXGroup)
556
559
  containing_component.children << new_group
557
560
  else
558
- raise "Trying to add group to an unsupported component type #{containing_component.isa}. " \
559
- "Change is: #{change}"
561
+ raise MergeError, "Trying to add group to an unsupported component type " \
562
+ "#{containing_component.isa}. Change is: #{change}"
560
563
  end
561
564
 
562
565
  add_attributes_to_component(new_group, change)
@@ -580,8 +583,8 @@ module Kintsugi
580
583
  add_child_to_component(component, added_attribute_element)
581
584
  end
582
585
  else
583
- raise "Trying to add attribute of unsupported type '#{change_value.class}' to " \
584
- "object #{component}. Attribute name is '#{change_name}'"
586
+ raise MergeError, "Trying to add attribute of unsupported type '#{change_value.class}' " \
587
+ "to object #{component}. Attribute name is '#{change_name}'"
585
588
  end
586
589
  end
587
590
  end
data/lib/kintsugi/cli.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  # Created by Ben Yohay.
3
3
  # frozen_string_literal: true
4
4
 
5
+ require "fileutils"
5
6
  require "optparse"
6
7
 
7
8
  require_relative "version"
@@ -12,12 +13,14 @@ module Kintsugi
12
13
  # Subcommands of Kintsugi CLI.
13
14
  attr_reader :subcommands
14
15
 
15
- # Root command Kintsugi CLI.
16
+ # Root command of Kintsugi CLI.
16
17
  attr_reader :root_command
17
18
 
18
19
  def initialize
19
20
  @subcommands = {
20
- "driver" => create_driver_subcommand
21
+ "driver" => create_driver_subcommand,
22
+ "install-driver" => create_install_driver_subcommand,
23
+ "uninstall-driver" => create_uninstall_driver_subcommand
21
24
  }.freeze
22
25
  @root_command = create_root_command
23
26
  end
@@ -27,7 +30,7 @@ module Kintsugi
27
30
  Command = Struct.new(:option_parser, :action, :description, keyword_init: true)
28
31
 
29
32
  def create_driver_subcommand
30
- driver_option_parser =
33
+ option_parser =
31
34
  OptionParser.new do |opts|
32
35
  opts.banner = "Usage: kintsugi driver BASE OURS THEIRS ORIGINAL_FILE_PATH\n" \
33
36
  "Uses Kintsugi as a Git merge driver. Parameters " \
@@ -40,7 +43,7 @@ module Kintsugi
40
43
  end
41
44
  end
42
45
 
43
- driver_action = lambda { |_, arguments, option_parser|
46
+ driver_action = lambda { |_, arguments|
44
47
  if arguments.count != 4
45
48
  puts "Incorrect number of arguments to 'driver' subcommand\n\n"
46
49
  puts option_parser
@@ -50,14 +53,115 @@ module Kintsugi
50
53
  }
51
54
 
52
55
  Command.new(
53
- option_parser: driver_option_parser,
56
+ option_parser: option_parser,
54
57
  action: driver_action,
55
58
  description: "3-way merge compatible with Git merge driver"
56
59
  )
57
60
  end
58
61
 
62
+ def create_install_driver_subcommand
63
+ option_parser =
64
+ OptionParser.new do |opts|
65
+ opts.banner = "Usage: kintsugi install-driver\n" \
66
+ "Installs Kintsugi as a Git merge driver globally. "
67
+
68
+ opts.on("-h", "--help", "Prints this help") do
69
+ puts opts
70
+ exit
71
+ end
72
+ end
73
+
74
+ action = lambda { |_, arguments|
75
+ if arguments.count != 0
76
+ puts "Incorrect number of arguments to 'install-driver' subcommand\n\n"
77
+ puts option_parser
78
+ exit(1)
79
+ end
80
+
81
+ if `which kintsugi`.chomp.empty?
82
+ puts "Can only install Kintsugi globally if Kintsugi is in your PATH"
83
+ exit(1)
84
+ end
85
+
86
+ install_kintsugi_driver_globally
87
+ puts "Done! 🪄"
88
+ }
89
+
90
+ Command.new(
91
+ option_parser: option_parser,
92
+ action: action,
93
+ description: "Installs Kintsugi as a Git merge driver globally"
94
+ )
95
+ end
96
+
97
+ def install_kintsugi_driver_globally
98
+ `git config --global merge.kintsugi.name "Kintsugi driver"`
99
+ `git config --global merge.kintsugi.driver "kintsugi driver %O %A %B %P"`
100
+
101
+ attributes_file_path = global_attributes_file_path
102
+ FileUtils.mkdir_p(File.dirname(attributes_file_path))
103
+
104
+ merge_using_kintsugi_line = "'*.pbxproj merge=kintsugi'"
105
+ `grep -sqxF #{merge_using_kintsugi_line} "#{attributes_file_path}" \
106
+ || echo #{merge_using_kintsugi_line} >> "#{attributes_file_path}"`
107
+ end
108
+
109
+ def global_attributes_file_path
110
+ # The logic to decide the path to the global attributes file is described at:
111
+ # https://git-scm.com/docs/gitattributes.
112
+ config_attributes_file_path = `git config --global core.attributesfile`
113
+ return config_attributes_file_path unless config_attributes_file_path.empty?
114
+
115
+ if ENV["XDG_CONFIG_HOME"].nil? || ENV["XDG_CONFIG_HOME"].empty?
116
+ File.join(ENV["HOME"], ".config/git/attributes")
117
+ else
118
+ File.join(ENV["XDG_CONFIG_HOME"], "git/attributes")
119
+ end
120
+ end
121
+
122
+ def create_uninstall_driver_subcommand
123
+ option_parser =
124
+ OptionParser.new do |opts|
125
+ opts.banner = "Usage: kintsugi uninstall-driver\n" \
126
+ "Uninstalls Kintsugi as a Git merge driver that was previously installed globally."
127
+
128
+ opts.on("-h", "--help", "Prints this help") do
129
+ puts opts
130
+ exit
131
+ end
132
+ end
133
+
134
+ action = lambda { |_, arguments|
135
+ if arguments.count != 0
136
+ puts "Incorrect number of arguments to 'uninstall-driver' subcommand\n\n"
137
+ puts option_parser
138
+ exit(1)
139
+ end
140
+
141
+ uninstall_kintsugi_driver_globally
142
+ puts "Done!"
143
+ }
144
+
145
+ Command.new(
146
+ option_parser: option_parser,
147
+ action: action,
148
+ description: "Uninstalls Kintsugi as a Git merge driver that was previously installed " \
149
+ "globally."
150
+ )
151
+ end
152
+
153
+ def uninstall_kintsugi_driver_globally
154
+ `git config --global --unset merge.kintsugi.name`
155
+ `git config --global --unset merge.kintsugi.driver`
156
+
157
+ attributes_file_path = global_attributes_file_path
158
+ return unless File.exist?(attributes_file_path)
159
+
160
+ `sed -i '' '/\*.pbxproj\ merge=kintsugi/d' "#{attributes_file_path}"`
161
+ end
162
+
59
163
  def create_root_command
60
- root_option_parser = OptionParser.new do |opts|
164
+ option_parser = OptionParser.new do |opts|
61
165
  opts.banner = "Kintsugi, version #{Version::STRING}\n" \
62
166
  "Copyright (c) 2021 Lightricks\n\n" \
63
167
  "Usage: kintsugi <pbxproj_filepath> [options]\n" \
@@ -77,13 +181,10 @@ module Kintsugi
77
181
  exit
78
182
  end
79
183
 
80
- subcommands_descriptions = @subcommands.map do |command_name, command|
81
- " #{command_name}: #{command.description}"
82
- end.join("\n")
83
- opts.on_tail("\nSUBCOMMANDS\n#{subcommands_descriptions}")
184
+ opts.on_tail("\nSUBCOMMANDS\n#{subcommands_descriptions(subcommands)}")
84
185
  end
85
186
 
86
- root_action = lambda { |options, arguments, option_parser|
187
+ root_action = lambda { |options, arguments|
87
188
  if arguments.count != 1
88
189
  puts "Incorrect number of arguments\n\n"
89
190
  puts option_parser
@@ -96,10 +197,18 @@ module Kintsugi
96
197
  }
97
198
 
98
199
  Command.new(
99
- option_parser: root_option_parser,
200
+ option_parser: option_parser,
100
201
  action: root_action,
101
202
  description: nil
102
203
  )
103
204
  end
205
+
206
+ def subcommands_descriptions(subcommands)
207
+ longest_subcommand_length = subcommands.keys.map(&:length).max + 4
208
+ format_string = " %-#{longest_subcommand_length}s%s"
209
+ subcommands.map do |command_name, command|
210
+ format(format_string, "#{command_name}:", command.description)
211
+ end.join("\n")
212
+ end
104
213
  end
105
214
  end
@@ -0,0 +1,9 @@
1
+ # Copyright (c) 2021 Lightricks. All rights reserved.
2
+ # Created by Ben Yohay.
3
+ # frozen_string_literal: true
4
+
5
+ module Kintsugi
6
+ # Raised when an error occurred while Kintsugi tried to resolve conflicts.
7
+ class MergeError < RuntimeError
8
+ end
9
+ end
@@ -3,6 +3,6 @@
3
3
  module Kintsugi
4
4
  # This module holds the Kintsugi version information.
5
5
  module Version
6
- STRING = "0.3.0"
6
+ STRING = "0.4.2"
7
7
  end
8
8
  end
data/lib/kintsugi.rb CHANGED
@@ -9,6 +9,7 @@ require "xcodeproj"
9
9
 
10
10
  require_relative "kintsugi/xcodeproj_extensions"
11
11
  require_relative "kintsugi/apply_change_to_project"
12
+ require_relative "kintsugi/error"
12
13
 
13
14
  module Kintsugi
14
15
  class << self
@@ -21,11 +22,11 @@ module Kintsugi
21
22
  # Path to where the changes to apply to the project are written in JSON format.
22
23
  #
23
24
  # @raise [ArgumentError]
24
- # If the file extension is not `pbxproj` or the file doesn't exist
25
+ # If the file extension is not `pbxproj`, or the file doesn't exist, or if no rebase,
26
+ # cherry-pick, or merge is in progress
25
27
  #
26
- # @raise [RuntimeError]
27
- # If no rebase, cherry-pick, or merge is in progress, or the project file couldn't be
28
- # opened, or there was an error applying the change to the project.
28
+ # @raise [MergeError]
29
+ # If there was an error applying the change to the project.
29
30
  #
30
31
  # @return [void]
31
32
  def resolve_conflicts(project_file_path, changes_output_path)
@@ -59,7 +60,7 @@ module Kintsugi
59
60
  # @param [String] original_project_path
60
61
  # Path to the original path of the file.
61
62
  #
62
- # @raise [RuntimeError]
63
+ # @raise [MergeError]
63
64
  # If there was an error applying the change to the project.
64
65
  #
65
66
  # @return [void]
@@ -104,8 +105,8 @@ module Kintsugi
104
105
 
105
106
  Dir.chdir(File.dirname(project_file_path)) do
106
107
  unless file_has_base_ours_and_theirs_versions?(project_file_path)
107
- raise ArgumentError, "File '#{project_file_path}' doesn't have conflicts, or a 3-way " \
108
- "merge is not possible."
108
+ raise ArgumentError, "File '#{project_file_path}' doesn't have conflicts, " \
109
+ "or a 3-way merge is not possible."
109
110
  end
110
111
  end
111
112
  end
@@ -138,7 +139,7 @@ module Kintsugi
138
139
  def file_has_version_in_stage_numbers?(file_path, stage_numbers)
139
140
  file_absolute_path = File.absolute_path(file_path)
140
141
  actual_stage_numbers =
141
- `git ls-files -u -- #{file_absolute_path}`.split("\n").map do |git_file_status|
142
+ `git ls-files -u -- "#{file_absolute_path}"`.split("\n").map do |git_file_status|
142
143
  git_file_status.split[2]
143
144
  end
144
145
  (stage_numbers - actual_stage_numbers.map(&:to_i)).empty?
@@ -176,6 +176,23 @@ describe Kintsugi, :apply_change_to_project do
176
176
  expect(base_project).to be_equivalent_to_project(theirs_project)
177
177
  end
178
178
 
179
+ it "changes simple attribute of a file that has a build file" do
180
+ target = base_project.new_target("com.apple.product-type.library.static", "bar", :ios)
181
+ file_reference = base_project.main_group.find_file_by_path(filepath)
182
+ target.frameworks_build_phase.add_file_reference(file_reference)
183
+ base_project.save
184
+
185
+ theirs_project = create_copy_of_project(base_project.path, "theirs")
186
+ file_reference = theirs_project.main_group.find_file_by_path(filepath)
187
+ file_reference.include_in_index = "4"
188
+
189
+ changes_to_apply = get_diff(theirs_project, base_project)
190
+
191
+ described_class.apply_change_to_project(base_project, changes_to_apply)
192
+
193
+ expect(base_project).to be_equivalent_to_project(theirs_project)
194
+ end
195
+
179
196
  it "removes build files of a removed file" do
180
197
  target = base_project.new_target("com.apple.product-type.library.static", "foo", :ios)
181
198
  target.source_build_phase.add_file_reference(
@@ -845,6 +862,24 @@ describe Kintsugi, :apply_change_to_project do
845
862
  expect(ours_project).to be_equivalent_to_project(theirs_project)
846
863
  end
847
864
 
865
+ it "doesn't throw if existing attribute target change is same as added change" do
866
+ base_project.root_object.attributes["TargetAttributes"] = {"foo" => "1140"}
867
+ base_project.save
868
+
869
+ theirs_project = create_copy_of_project(base_project.path, "theirs")
870
+ theirs_project.root_object.attributes["TargetAttributes"]["foo"] = "1111"
871
+
872
+ ours_project = create_copy_of_project(base_project.path, "ours")
873
+ ours_project.root_object.attributes["TargetAttributes"]["foo"] = "1111"
874
+
875
+ changes_to_apply = get_diff(theirs_project, base_project)
876
+
877
+ described_class.apply_change_to_project(ours_project, changes_to_apply)
878
+ ours_project.save
879
+
880
+ expect(ours_project).to be_equivalent_to_project(theirs_project)
881
+ end
882
+
848
883
  it "identifies subproject added at separate times when adding a product to the subproject" do
849
884
  framework_filename = "baz"
850
885
 
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kintsugi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Yohay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-27 00:00:00.000000000 Z
11
+ date: 2022-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xcodeproj
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 1.19.0
20
+ - - "<="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.21.0
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - '='
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: 1.19.0
30
+ - - "<="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.21.0
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: rake
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -117,6 +123,7 @@ files:
117
123
  - lib/kintsugi.rb
118
124
  - lib/kintsugi/apply_change_to_project.rb
119
125
  - lib/kintsugi/cli.rb
126
+ - lib/kintsugi/error.rb
120
127
  - lib/kintsugi/utils.rb
121
128
  - lib/kintsugi/version.rb
122
129
  - lib/kintsugi/xcodeproj_extensions.rb