refinement 0.2.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/VERSION +1 -1
- data/exe/refine +1 -0
- data/lib/cocoapods_plugin.rb +3 -3
- data/lib/refinement.rb +2 -0
- data/lib/refinement/analyzer.rb +65 -41
- data/lib/refinement/annotated_target.rb +10 -3
- data/lib/refinement/changeset.rb +20 -13
- data/lib/refinement/changeset/file_modification.rb +11 -4
- data/lib/refinement/cli.rb +3 -0
- data/lib/refinement/cocoapods_post_install_writer.rb +6 -0
- data/lib/refinement/used_path.rb +49 -9
- data/lib/refinement/version.rb +2 -0
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f99f7e0933bae18ddd8c4f6fbd14f3e182f6233a1244b1418ccf678b5c1e471
|
4
|
+
data.tar.gz: 451abebd764ff651e9489095bca0ce0fc4043965e81e962ca49df68e90341367
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f8348156cedae83212560898d95229be93c592347e052a82bd5a1bd3b13d76a7298703976f4e93799cd8d38543316409462d9c6ef564e1680bdde746bf084aa
|
7
|
+
data.tar.gz: 1109c4b167045b0a2ac2ba45aa036ec6b3d4aacf06726be393c68fe072ee49479d61d41c89a6a29ad927b1e419a3e7932f82acba25ccf02fe4a08efc0a8aaae6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Refinement Changes
|
2
2
|
|
3
|
+
## 0.3.1 (2019-08-09)
|
4
|
+
|
5
|
+
##### Bug Fixes
|
6
|
+
|
7
|
+
* Take into consideration product reference names when refinining.
|
8
|
+
|
9
|
+
|
10
|
+
## 0.3.0 (2019-08-09)
|
11
|
+
|
12
|
+
##### Bug Fixes
|
13
|
+
|
14
|
+
* Multiple YAML used keys paths for the same file will no longer cause the YAML
|
15
|
+
to be parsed multiple times.
|
16
|
+
|
17
|
+
|
3
18
|
## 0.2.2 (2019-04-08)
|
4
19
|
|
5
20
|
No changes.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/exe/refine
CHANGED
data/lib/cocoapods_plugin.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cocoapods'
|
2
4
|
|
3
5
|
Pod::Installer
|
@@ -7,9 +9,7 @@ Pod::Installer
|
|
7
9
|
|
8
10
|
return unless plugins.key?('refinement')
|
9
11
|
|
10
|
-
unless Gem::Version.create(Pod::VERSION) >= Gem::Version.create('1.6.0')
|
11
|
-
raise Pod::Informative, 'Refinement requires a CocoaPods version >= 1.6.0'
|
12
|
-
end
|
12
|
+
raise Pod::Informative, 'Refinement requires a CocoaPods version >= 1.6.0' unless Gem::Version.create(Pod::VERSION) >= Gem::Version.create('1.6.0')
|
13
13
|
|
14
14
|
require 'refinement/cocoapods_post_install_writer'
|
15
15
|
Pod::UI.message 'Writing refinement file' do
|
data/lib/refinement.rb
CHANGED
data/lib/refinement/analyzer.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Refinement
|
2
4
|
# Analyzes changes in a repository
|
3
5
|
# and determines how those changes impact the targets in Xcode projects in the workspace.
|
4
6
|
class Analyzer
|
5
|
-
attr_reader :
|
6
|
-
private :
|
7
|
+
attr_reader :changesets, :workspace_path, :augmenting_paths_yaml_files
|
8
|
+
private :changesets, :workspace_path, :augmenting_paths_yaml_files
|
7
9
|
|
8
|
-
# Initializes an analyzer with
|
9
|
-
# @param
|
10
|
+
# Initializes an analyzer with changesets, projects, and augmenting paths.
|
11
|
+
# @param changesets [Array<Changeset>]
|
10
12
|
# @param workspace_path [Pathname] path to a root workspace or project,
|
11
13
|
# must be `nil` if `projects` are specified explicitly
|
12
14
|
# @param projects [Array<Xcodeproj::Project>] projects to find targets in,
|
@@ -20,18 +22,18 @@ module Refinement
|
|
20
22
|
#
|
21
23
|
# @raise [ArgumentError] when conflicting arguments are given
|
22
24
|
#
|
23
|
-
def initialize(
|
25
|
+
def initialize(changesets:, workspace_path:, projects: nil,
|
24
26
|
augmenting_paths_yaml_files:, augmenting_paths_by_target: nil)
|
25
27
|
|
26
|
-
@
|
28
|
+
@changesets = changesets
|
27
29
|
|
28
30
|
raise ArgumentError, 'Can only specify one of workspace_path and projects' if workspace_path && projects
|
31
|
+
|
29
32
|
@workspace_path = workspace_path
|
30
33
|
@projects = projects
|
31
34
|
|
32
|
-
if augmenting_paths_yaml_files && augmenting_paths_by_target
|
33
|
-
|
34
|
-
end
|
35
|
+
raise ArgumentError, 'Can only specify one of augmenting_paths_yaml_files and augmenting_paths_by_target' if augmenting_paths_yaml_files && augmenting_paths_by_target
|
36
|
+
|
35
37
|
@augmenting_paths_yaml_files = augmenting_paths_yaml_files
|
36
38
|
@augmenting_paths_by_target = augmenting_paths_by_target
|
37
39
|
end
|
@@ -75,25 +77,38 @@ module Refinement
|
|
75
77
|
"Given: #{filter_scheme_for_build_action.inspect}."
|
76
78
|
end
|
77
79
|
|
78
|
-
if filter_when_scheme_has_changed
|
79
|
-
|
80
|
+
if !filter_when_scheme_has_changed &&
|
81
|
+
UsedPath.new(path: Pathname(scheme_path), inclusion_reason: 'scheme').find_in_changesets(changesets)
|
82
|
+
return scheme
|
83
|
+
end
|
84
|
+
|
85
|
+
changes_by_suite_name = Hash[annotate_targets!
|
86
|
+
.map { |at| [at.xcode_target.name, at.change_reason(level: change_level)] }]
|
80
87
|
|
81
|
-
|
82
|
-
.map { |at| [at.xcode_target.name, at.change_reason(level: change_level)] }]
|
88
|
+
doc = scheme.doc
|
83
89
|
|
84
|
-
|
90
|
+
xpaths = sections_to_filter.map { |section| "//*/#{section}/BuildableReference" }
|
91
|
+
xpaths.each do |xpath|
|
92
|
+
doc.get_elements(xpath).to_a.each do |buildable_reference|
|
93
|
+
suite_name = buildable_reference.attributes['BlueprintName']
|
94
|
+
if (change_reason = changes_by_suite_name[suite_name])
|
95
|
+
puts "#{suite_name} changed because #{change_reason}" if log_changes
|
96
|
+
next
|
97
|
+
end
|
98
|
+
puts "#{suite_name} did not change, removing from scheme" if log_changes
|
99
|
+
buildable_reference.parent.remove
|
100
|
+
end
|
101
|
+
end
|
85
102
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
next
|
93
|
-
end
|
94
|
-
puts "#{suite_name} did not change, removing from scheme" if log_changes
|
95
|
-
buildable_reference.parent.remove
|
103
|
+
if filter_scheme_for_build_action == :testing
|
104
|
+
doc.get_elements('//*/BuildActionEntry/BuildableReference').to_a.each do |buildable_reference|
|
105
|
+
suite_name = buildable_reference.attributes['BlueprintName']
|
106
|
+
if (change_reason = changes_by_suite_name[suite_name])
|
107
|
+
puts "#{suite_name} changed because #{change_reason}" if log_changes
|
108
|
+
next
|
96
109
|
end
|
110
|
+
puts "#{suite_name} did not change, setting to not build for testing" if log_changes
|
111
|
+
buildable_reference.parent.attributes['buildForTesting'] = 'NO'
|
97
112
|
end
|
98
113
|
end
|
99
114
|
|
@@ -110,6 +125,7 @@ module Refinement
|
|
110
125
|
.map do |annotated_target|
|
111
126
|
change_reason = annotated_target.change_reason(level: change_level)
|
112
127
|
next if !include_unchanged_targets && !change_reason
|
128
|
+
|
113
129
|
change_reason ||= 'did not change'
|
114
130
|
"\t#{annotated_target.xcode_target}: #{change_reason}"
|
115
131
|
end.compact
|
@@ -129,7 +145,7 @@ module Refinement
|
|
129
145
|
@augmenting_paths_by_target ||= begin
|
130
146
|
require 'yaml'
|
131
147
|
augmenting_paths_yaml_files.reduce({}) do |augmenting_paths_by_target, yaml_file|
|
132
|
-
yaml_file = Pathname(yaml_file).expand_path(
|
148
|
+
yaml_file = Pathname(yaml_file).expand_path(changesets.first.repository)
|
133
149
|
yaml = YAML.safe_load(yaml_file.read)
|
134
150
|
augmenting_paths_by_target.merge(yaml) do |_target_name, prior_paths, new_paths|
|
135
151
|
prior_paths + new_paths
|
@@ -141,19 +157,20 @@ module Refinement
|
|
141
157
|
# @return [Array<AnnotatedTarget>] targets in the given list of Xcode projects,
|
142
158
|
# annotated according to the given changeset
|
143
159
|
def annotated_targets
|
144
|
-
workspace_modification =
|
160
|
+
workspace_modification = find_workspace_modification_in_changesets
|
145
161
|
project_changes = Hash[projects.map do |project|
|
146
|
-
[project,
|
162
|
+
[project, find_project_modification_in_changesets(project: project) || workspace_modification]
|
147
163
|
end]
|
148
164
|
|
149
165
|
require 'tsort'
|
150
166
|
targets = projects.flat_map(&:targets)
|
151
167
|
targets_by_uuid = Hash[targets.map { |t| [t.uuid, t] }]
|
152
168
|
targets_by_name = Hash[targets.map { |t| [t.name, t] }]
|
153
|
-
targets_by_product_name =
|
169
|
+
targets_by_product_name = targets.each_with_object({}) do |t, h|
|
154
170
|
next unless t.respond_to?(:product_reference)
|
155
|
-
[File.basename(t.product_reference.path)
|
156
|
-
|
171
|
+
h[File.basename(t.product_reference.path)] = t
|
172
|
+
h[File.basename(t.product_reference.name)] = t if t.product_reference.name
|
173
|
+
end
|
157
174
|
|
158
175
|
find_dep = ->(td) { targets_by_uuid[td.native_target_uuid] || targets_by_name[td.name] }
|
159
176
|
target_deps = lambda do |target|
|
@@ -166,7 +183,7 @@ module Refinement
|
|
166
183
|
# yay auto-linking
|
167
184
|
if (phase = target.frameworks_build_phases)
|
168
185
|
phase.files_references.each do |fr|
|
169
|
-
if (dt = fr
|
186
|
+
if (dt = fr&.path && targets_by_product_name[File.basename(fr.path)])
|
170
187
|
target_dependencies << dt
|
171
188
|
end
|
172
189
|
end
|
@@ -181,7 +198,7 @@ module Refinement
|
|
181
198
|
)
|
182
199
|
|
183
200
|
targets.each_with_object({}) do |target, h|
|
184
|
-
change_reason = project_changes[target.project] ||
|
201
|
+
change_reason = project_changes[target.project] || find_target_modification_in_changesets(target: target)
|
185
202
|
|
186
203
|
h[target] = AnnotatedTarget.new(
|
187
204
|
target: target,
|
@@ -232,6 +249,7 @@ module Refinement
|
|
232
249
|
|
233
250
|
expand_build_settings = lambda do |s|
|
234
251
|
return [s] unless s =~ /\$(?:\{([_a-zA-Z0-0]+?)\}|\(([_a-zA-Z0-0]+?)\))/
|
252
|
+
|
235
253
|
match, key = Regexp.last_match.values_at(0, 1, 2).compact
|
236
254
|
substitutions = target.resolved_build_setting(key, true).values.compact.uniq
|
237
255
|
substitutions.flat_map do |sub|
|
@@ -242,6 +260,7 @@ module Refinement
|
|
242
260
|
target.build_configuration_list.build_configurations.each do |build_configuration|
|
243
261
|
ref = build_configuration.base_configuration_reference
|
244
262
|
next unless ref
|
263
|
+
|
245
264
|
yield UsedPath.new(path: ref.real_path,
|
246
265
|
inclusion_reason: "base configuration reference for #{build_configuration}")
|
247
266
|
end
|
@@ -249,6 +268,7 @@ module Refinement
|
|
249
268
|
target.build_phases.each do |build_phase|
|
250
269
|
build_phase.files_references.each do |fr|
|
251
270
|
next unless fr
|
271
|
+
|
252
272
|
yield UsedPath.new(path: fr.real_path,
|
253
273
|
inclusion_reason: "#{build_phase.display_name.downcase.chomp('s')} file")
|
254
274
|
end
|
@@ -257,9 +277,11 @@ module Refinement
|
|
257
277
|
target.shell_script_build_phases.each do |shell_script_build_phase|
|
258
278
|
%w[input_file_list_paths output_file_list_paths input_paths output_paths].each do |method|
|
259
279
|
next unless (paths = shell_script_build_phase.public_send(method))
|
280
|
+
|
260
281
|
file_type = method.tr('_', ' ').chomp('s')
|
261
282
|
paths.each do |config_path|
|
262
283
|
next unless config_path
|
284
|
+
|
263
285
|
expand_build_settings[config_path].each do |path|
|
264
286
|
path = Pathname(path).expand_path(target.project.project_dir)
|
265
287
|
yield UsedPath.new(path: path,
|
@@ -273,6 +295,7 @@ module Refinement
|
|
273
295
|
target.resolved_build_setting(build_setting, true).each_value do |paths|
|
274
296
|
Array(paths).each do |path|
|
275
297
|
next unless path
|
298
|
+
|
276
299
|
path = Pathname(path).expand_path(target.project.project_dir)
|
277
300
|
yield UsedPath.new(path: path, inclusion_reason: "#{build_setting} value")
|
278
301
|
end
|
@@ -283,11 +306,11 @@ module Refinement
|
|
283
306
|
# @return [FileModification,Nil] a modification to a file that is used by the given target, or `nil`
|
284
307
|
# if none if found
|
285
308
|
# @param target [Xcodeproj::Project::AbstractTarget]
|
286
|
-
def
|
309
|
+
def find_target_modification_in_changesets(target:)
|
287
310
|
augmenting_paths = used_paths_from_augmenting_paths_by_target[target.name]
|
288
|
-
|
289
|
-
Refinement.map_find(augmenting_paths, &
|
290
|
-
Refinement.map_find(target_each_file_path(target: target), &
|
311
|
+
find_in_changesets = ->(path) { path.find_in_changesets(changesets) }
|
312
|
+
Refinement.map_find(augmenting_paths, &find_in_changesets) ||
|
313
|
+
Refinement.map_find(target_each_file_path(target: target), &find_in_changesets)
|
291
314
|
end
|
292
315
|
|
293
316
|
# @yieldparam used_path [UsedPath] an absolute path that belongs to the given project
|
@@ -301,6 +324,7 @@ module Refinement
|
|
301
324
|
project.root_object.build_configuration_list.build_configurations.each do |build_configuration|
|
302
325
|
ref = build_configuration.base_configuration_reference
|
303
326
|
next unless ref
|
327
|
+
|
304
328
|
yield UsedPath.new(path: ref.real_path,
|
305
329
|
inclusion_reason: "base configuration reference for #{build_configuration}")
|
306
330
|
end
|
@@ -310,9 +334,9 @@ module Refinement
|
|
310
334
|
# if none if found
|
311
335
|
# @note This method does not take into account whatever file paths targets in the project may reference
|
312
336
|
# @param project [Xcodeproj::Project]
|
313
|
-
def
|
337
|
+
def find_project_modification_in_changesets(project:)
|
314
338
|
Refinement.map_find(project_each_file_path(project: project)) do |path|
|
315
|
-
path.
|
339
|
+
path.find_in_changesets(changesets)
|
316
340
|
end
|
317
341
|
end
|
318
342
|
|
@@ -320,17 +344,17 @@ module Refinement
|
|
320
344
|
# if none if found
|
321
345
|
# @note This method does not take into account whatever file paths projects or
|
322
346
|
# targets in the workspace path may reference
|
323
|
-
def
|
347
|
+
def find_workspace_modification_in_changesets
|
324
348
|
return unless workspace_path
|
325
349
|
|
326
350
|
UsedPath.new(path: workspace_path, inclusion_reason: 'workspace directory')
|
327
|
-
.
|
351
|
+
.find_in_changesets(changesets)
|
328
352
|
end
|
329
353
|
|
330
354
|
# @return [Hash<String,UsedPath>]
|
331
355
|
def used_paths_from_augmenting_paths_by_target
|
332
356
|
@used_paths_from_augmenting_paths_by_target ||= begin
|
333
|
-
repo =
|
357
|
+
repo = changesets.first.repository
|
334
358
|
used_paths_from_augmenting_paths_by_target =
|
335
359
|
augmenting_paths_by_target.each_with_object({}) do |(name, augmenting_paths), h|
|
336
360
|
h[name] = augmenting_paths.map do |augmenting_path|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Refinement
|
2
4
|
# A target, annotated with any changes
|
3
5
|
class AnnotatedTarget
|
@@ -45,15 +47,20 @@ module Refinement
|
|
45
47
|
when :full_transitive
|
46
48
|
direct_change_reason || Refinement.map_find(dependencies) do |dependency|
|
47
49
|
next unless (dependency_change_reason = dependency.change_reason(level: level))
|
50
|
+
|
48
51
|
"dependency #{dependency} changed because #{dependency_change_reason}"
|
49
52
|
end
|
50
53
|
when proc { |symbol, int| (symbol == :at_most_n_away) && int.is_a?(Integer) }
|
51
54
|
distance_from_target = level.last
|
52
|
-
raise ArgumentError, "level must be positive, not #{distance_from_target}" if distance_from_target
|
55
|
+
raise ArgumentError, "level must be positive, not #{distance_from_target}" if distance_from_target.negative?
|
56
|
+
|
53
57
|
change_reason = direct_change_reason
|
54
|
-
if distance_from_target
|
58
|
+
if distance_from_target.positive?
|
55
59
|
change_reason ||= Refinement.map_find(dependencies) do |dependency|
|
56
|
-
|
60
|
+
unless (dependency_change_reason = dependency.change_reason(level: [:at_most_n_away, level.last.pred]))
|
61
|
+
next
|
62
|
+
end
|
63
|
+
|
57
64
|
"dependency #{dependency} changed because #{dependency_change_reason}"
|
58
65
|
end
|
59
66
|
end
|
data/lib/refinement/changeset.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cocoapods/executable'
|
2
4
|
require 'set'
|
3
5
|
|
@@ -16,12 +18,15 @@ module Refinement
|
|
16
18
|
attr_reader :modified_paths
|
17
19
|
# @return [Hash<Pathname,FileModification>] modifications keyed by relative path
|
18
20
|
attr_reader :modified_absolute_paths
|
21
|
+
# @return [String] a desciption of the changeset
|
22
|
+
attr_reader :description
|
19
23
|
|
20
24
|
private :modifications, :modified_paths, :modified_absolute_paths
|
21
25
|
|
22
|
-
def initialize(repository:, modifications:)
|
26
|
+
def initialize(repository:, modifications:, description: nil)
|
23
27
|
@repository = repository
|
24
28
|
@modifications = self.class.add_directories(modifications).uniq.freeze
|
29
|
+
@description = description
|
25
30
|
|
26
31
|
@modified_paths = {}
|
27
32
|
@modifications
|
@@ -43,6 +48,7 @@ module Refinement
|
|
43
48
|
dirs = Set.new
|
44
49
|
add = lambda { |path|
|
45
50
|
break unless dirs.add?(path)
|
51
|
+
|
46
52
|
add[path.dirname]
|
47
53
|
}
|
48
54
|
modifications.each do |mod|
|
@@ -124,8 +130,10 @@ module Refinement
|
|
124
130
|
# @param keypath [Array]
|
125
131
|
def find_modification_for_yaml_keypath(absolute_path:, keypath:)
|
126
132
|
return unless (file_modification = find_modification_for_path(absolute_path: absolute_path))
|
133
|
+
|
127
134
|
diff = file_modification.yaml_diff(keypath)
|
128
135
|
return unless diff
|
136
|
+
|
129
137
|
[file_modification, diff]
|
130
138
|
end
|
131
139
|
|
@@ -140,18 +148,18 @@ module Refinement
|
|
140
148
|
diff = git!('diff', '--raw', '-z', merge_base, chdir: repository)
|
141
149
|
modifications = parse_raw_diff(diff, repository: repository, base_revision: merge_base).freeze
|
142
150
|
|
143
|
-
new(repository: repository, modifications: modifications)
|
151
|
+
new(repository: repository, modifications: modifications, description: "since #{base_revision}")
|
144
152
|
end
|
145
153
|
|
146
154
|
CHANGE_TYPES = {
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
+
'was added': 'A',
|
156
|
+
'was copied': 'C',
|
157
|
+
'was deleted': 'D',
|
158
|
+
'was modified': 'M',
|
159
|
+
'was renamed': 'R',
|
160
|
+
'changed type': 'T',
|
161
|
+
'is unmerged': 'U',
|
162
|
+
'changed in an unknown way': 'X'
|
155
163
|
}.freeze
|
156
164
|
private_constant :CHANGE_TYPES
|
157
165
|
|
@@ -206,9 +214,8 @@ module Refinement
|
|
206
214
|
def self.git!(command, *args, chdir:)
|
207
215
|
require 'open3'
|
208
216
|
out, err, status = Open3.capture3('git', command, *args, chdir: chdir.to_s)
|
209
|
-
unless status.success?
|
210
|
-
|
211
|
-
end
|
217
|
+
raise GitError, "Running git #{command} failed (#{status.to_s.gsub(/pid \d+\s*/, '')}):\n\n#{err}" unless status.success?
|
218
|
+
|
212
219
|
out
|
213
220
|
end
|
214
221
|
private_class_method :git!
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Refinement
|
2
4
|
class Changeset
|
3
5
|
# Represents a modification to a single file or directory on disk
|
@@ -51,12 +53,14 @@ module Refinement
|
|
51
53
|
# @visibility private
|
52
54
|
def ==(other)
|
53
55
|
return unless other.is_a?(FileModification)
|
56
|
+
|
54
57
|
(path == other.path) && (type == other.type) && prior_path == other.prior_path
|
55
58
|
end
|
56
59
|
|
57
60
|
# @visibility private
|
58
61
|
def eql?(other)
|
59
62
|
return unless other.is_a?(FileModification)
|
63
|
+
|
60
64
|
path.eql?(other.path) && type.eql?(other.type) && prior_path.eql?(other.prior_path)
|
61
65
|
end
|
62
66
|
|
@@ -68,9 +72,12 @@ module Refinement
|
|
68
72
|
def yaml_diff(keypath)
|
69
73
|
require 'yaml'
|
70
74
|
|
71
|
-
|
75
|
+
@cached_yaml ||= {}
|
76
|
+
|
77
|
+
dig_yaml = lambda do |yaml, path|
|
72
78
|
return yaml if DOES_NOT_EXIST == yaml
|
73
|
-
|
79
|
+
|
80
|
+
object = @cached_yaml[path] ||= YAML.safe_load(yaml, [Symbol])
|
74
81
|
if keypath.empty?
|
75
82
|
object
|
76
83
|
elsif object.respond_to?(:dig)
|
@@ -82,8 +89,8 @@ module Refinement
|
|
82
89
|
end
|
83
90
|
end
|
84
91
|
|
85
|
-
prior = dig_yaml[prior_contents]
|
86
|
-
current = dig_yaml[contents]
|
92
|
+
prior = dig_yaml[prior_contents, :prior]
|
93
|
+
current = dig_yaml[contents, :current]
|
87
94
|
|
88
95
|
require 'xcodeproj/differ'
|
89
96
|
|
data/lib/refinement/cli.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'claide'
|
2
4
|
|
3
5
|
module Refinement
|
@@ -48,6 +50,7 @@ module Refinement
|
|
48
50
|
puts analyzer.format_changes if @print_changes
|
49
51
|
|
50
52
|
return unless @scheme
|
53
|
+
|
51
54
|
analyzer.filtered_scheme(scheme_path: @scheme, log_changes: @print_scheme_changes, filter_scheme_for_build_action: @filter_scheme_for_build_action)
|
52
55
|
.save_as(@scheme.gsub(%r{\.(xcodeproj|xcworkspace)/.+}, '.\1'), File.basename(@scheme, '.xcscheme'), true)
|
53
56
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Refinement
|
2
4
|
# Called after CocoaPods installation to write an augmenting file that
|
3
5
|
# takes into account changes to Pod configuration,
|
@@ -101,6 +103,10 @@ module Refinement
|
|
101
103
|
inclusion_reason: 'CocoaPods lockfile',
|
102
104
|
yaml_keypath: ['SPEC CHECKSUMS', pod_target.pod_name] }
|
103
105
|
]
|
106
|
+
if pod_target.sandbox.predownloaded?(pod_target.pod_name)
|
107
|
+
paths << { path: 'Podfile.lock', inclusion_reason: 'Dependency external source', yaml_keypath: ['EXTERNAL SOURCES', pod_target.pod_name] }
|
108
|
+
paths << { path: 'Podfile.lock', inclusion_reason: 'Pod checkout options', yaml_keypath: ['CHECKOUT OPTIONS', pod_target.pod_name] }
|
109
|
+
end
|
104
110
|
spec_paths.each { |path| paths << { path: path, inclusion_reason: 'podspec' } }
|
105
111
|
|
106
112
|
Pod::Validator::FILE_PATTERNS.each do |pattern|
|
data/lib/refinement/used_path.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Refinement
|
2
4
|
# Represents a path that some target depends upon.
|
3
5
|
class UsedPath
|
@@ -17,7 +19,17 @@ module Refinement
|
|
17
19
|
# @return [Nil, String] If the path has been modified, a string explaining the modification
|
18
20
|
# @param changeset [Changeset] the changeset to search for a modification to this path
|
19
21
|
def find_in_changeset(changeset)
|
20
|
-
add_reason changeset.find_modification_for_path(absolute_path: path)
|
22
|
+
add_reason changeset.find_modification_for_path(absolute_path: path), changeset: changeset
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Nil, String] If the path has been modified, a string explaining the modification
|
26
|
+
# @param changesets [Array<Changeset>] the changesets to search for a modification to this path
|
27
|
+
def find_in_changesets(changesets)
|
28
|
+
raise ArgumentError, 'Must provide at least one changeset' if changesets.empty?
|
29
|
+
|
30
|
+
changesets.reduce(true) do |explanation, changeset|
|
31
|
+
explanation && find_in_changeset(changeset)
|
32
|
+
end
|
21
33
|
end
|
22
34
|
|
23
35
|
# @return [String]
|
@@ -31,10 +43,22 @@ module Refinement
|
|
31
43
|
# @return [Nil, String] A string suitable for user display that explains
|
32
44
|
# why the given modification means a target is modified
|
33
45
|
# @param modification [Nil, FileModification]
|
34
|
-
|
46
|
+
# @param changeset [Changeset]
|
47
|
+
def add_reason(modification, changeset:)
|
35
48
|
return unless modification
|
36
49
|
|
37
|
-
"#{modification.path} (#{inclusion_reason}) #{modification.type}"
|
50
|
+
add_changeset_description "#{modification.path} (#{inclusion_reason}) #{modification.type}", changeset: changeset
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [String] A string suitable for user display that explains
|
54
|
+
# why the given modification means a target is modified, including the description
|
55
|
+
# of the changeset that contains the modification
|
56
|
+
# @param description [String]
|
57
|
+
# @param changeset [Nil, Changeset]
|
58
|
+
def add_changeset_description(description, changeset:)
|
59
|
+
return description unless changeset&.description
|
60
|
+
|
61
|
+
description + " (#{changeset.description})"
|
38
62
|
end
|
39
63
|
|
40
64
|
# Represents a path to a YAML file that some target depends upon,
|
@@ -52,7 +76,7 @@ module Refinement
|
|
52
76
|
# (see UsedPath#find_in_changeset)
|
53
77
|
def find_in_changeset(changeset)
|
54
78
|
modification, _yaml_diff = changeset.find_modification_for_yaml_keypath(absolute_path: path, keypath: yaml_keypath)
|
55
|
-
add_reason modification
|
79
|
+
add_reason modification, changeset: changeset
|
56
80
|
end
|
57
81
|
|
58
82
|
# (see UsedPath#to_s)
|
@@ -63,7 +87,7 @@ module Refinement
|
|
63
87
|
private
|
64
88
|
|
65
89
|
# (see UsedPath#add_reason)
|
66
|
-
def add_reason(modification)
|
90
|
+
def add_reason(modification, changeset:)
|
67
91
|
return unless modification
|
68
92
|
|
69
93
|
keypath_string =
|
@@ -72,7 +96,7 @@ module Refinement
|
|
72
96
|
else
|
73
97
|
' @ ' + yaml_keypath.map { |path| path.to_s =~ /\A[a-zA-Z0-9_]+\z/ ? path : path.inspect }.join('.')
|
74
98
|
end
|
75
|
-
"#{modification.path}#{keypath_string} (#{inclusion_reason}) #{modification.type}"
|
99
|
+
add_changeset_description "#{modification.path}#{keypath_string} (#{inclusion_reason}) #{modification.type}", changeset: changeset
|
76
100
|
end
|
77
101
|
end
|
78
102
|
end
|
@@ -94,7 +118,16 @@ module Refinement
|
|
94
118
|
|
95
119
|
# (see UsedPath#find_in_changeset)
|
96
120
|
def find_in_changeset(changeset)
|
97
|
-
add_reason changeset.find_modification_for_glob(absolute_glob: glob)
|
121
|
+
add_reason changeset.find_modification_for_glob(absolute_glob: glob), changeset: changeset
|
122
|
+
end
|
123
|
+
|
124
|
+
# (see UsedPath#find_in_changesets)
|
125
|
+
def find_in_changesets(changesets)
|
126
|
+
raise ArgumentError, 'Must provide at least one changeset' if changesets.empty?
|
127
|
+
|
128
|
+
changesets.reduce(true) do |explanation, changeset|
|
129
|
+
explanation && find_in_changeset(changeset)
|
130
|
+
end
|
98
131
|
end
|
99
132
|
|
100
133
|
# (see UsedPath#to_s)
|
@@ -105,10 +138,17 @@ module Refinement
|
|
105
138
|
private
|
106
139
|
|
107
140
|
# (see UsedPath#add_reason)
|
108
|
-
def add_reason(modification)
|
141
|
+
def add_reason(modification, changeset:)
|
109
142
|
return unless modification
|
110
143
|
|
111
|
-
"#{modification.path} (#{inclusion_reason}) #{modification.type}"
|
144
|
+
add_changeset_description "#{modification.path} (#{inclusion_reason}) #{modification.type}", changeset: changeset
|
145
|
+
end
|
146
|
+
|
147
|
+
# (see UsedPath#add_changeset_description)
|
148
|
+
def add_changeset_description(description, changeset:)
|
149
|
+
return description unless changeset&.description
|
150
|
+
|
151
|
+
description + " (#{changeset.description})"
|
112
152
|
end
|
113
153
|
end
|
114
154
|
end
|
data/lib/refinement/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: refinement
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Giddins
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: xcodeproj
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '10.0'
|
47
|
-
description:
|
47
|
+
description:
|
48
48
|
email:
|
49
49
|
- segiddins@squareup.com
|
50
50
|
executables:
|
@@ -70,7 +70,7 @@ files:
|
|
70
70
|
homepage: https://github.com/square/refinement
|
71
71
|
licenses: []
|
72
72
|
metadata: {}
|
73
|
-
post_install_message:
|
73
|
+
post_install_message:
|
74
74
|
rdoc_options: []
|
75
75
|
require_paths:
|
76
76
|
- lib
|
@@ -78,15 +78,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
79
79
|
- - ">="
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '2.
|
81
|
+
version: '2.3'
|
82
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
83
|
requirements:
|
84
84
|
- - ">="
|
85
85
|
- !ruby/object:Gem::Version
|
86
86
|
version: '0'
|
87
87
|
requirements: []
|
88
|
-
rubygems_version: 3.0.
|
89
|
-
signing_key:
|
88
|
+
rubygems_version: 3.0.1
|
89
|
+
signing_key:
|
90
90
|
specification_version: 4
|
91
91
|
summary: Generates a list of Xcode targets to build & test as a result of a git diff.
|
92
92
|
test_files: []
|