kennel 1.128.0 → 1.129.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d27f0b47987630640f1d58181bc98360714dc4b39827ea7282d1445496e3d315
4
- data.tar.gz: a2dbe1c762943b8859134772f39e3f0af0f4e7e2c5c1a60c2de980574de84714
3
+ metadata.gz: c7690d961a150ea0ba0649edcab513c22ec828988fec2ab631636497274305c7
4
+ data.tar.gz: c5bc7244c4168466f5167e5c322f3a2cdb8e6b9b8ec23a2d12fb343a7648ae06
5
5
  SHA512:
6
- metadata.gz: 6c16b16c0914e6c436424c431eec9b5b0ff5dcb92195096973e1807c75375e34f16094c4935c28de6a0797ebb8d5cc5a8e86a9c38f4a778df65598ede58ad348
7
- data.tar.gz: d885678eb185f3fa404d8c42c64f3c7f22250da1537ecec556d5f9728fe9a6aa7d7fb889f9c8d637c4f29787864f05ec5a51c5abb90023fde1c71a0110a24dd5
6
+ metadata.gz: 51b47377a8cf688dafd17600b543cc1734eb8511a6ed1b627d8b1180bf70fc66c86f9d4a8e4b2a3ff5e7223edf366e5483d983d9465c5907aaa07f5b9c36ef46
7
+ data.tar.gz: 698c23a4de558382467342b90e7d3eac143a0279653efe9f1b711b3e114a37d8d72f4a9c5d97e652a6646007298f5e93f296c1125caaa4c498195089b0cac730
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "diff/lcs"
4
+
5
+ module Kennel
6
+ class AttributeDiffer
7
+ def initialize
8
+ # min '2' because: -1 makes no sense, 0 does not work with * 2 math, 1 says '1 lines'
9
+ @max_diff_lines = [Integer(ENV.fetch("MAX_DIFF_LINES", "50")), 2].max
10
+ super
11
+ end
12
+
13
+ def format(type, field, old, new = nil)
14
+ multiline = false
15
+ if type == "+"
16
+ temp = pretty_inspect(new)
17
+ new = pretty_inspect(old)
18
+ old = temp
19
+ elsif old.is_a?(String) && new.is_a?(String) && (old.include?("\n") || new.include?("\n"))
20
+ multiline = true
21
+ else # ~ and -
22
+ old = pretty_inspect(old)
23
+ new = pretty_inspect(new)
24
+ end
25
+
26
+ message =
27
+ if multiline
28
+ " #{type}#{field}\n" +
29
+ multiline_diff(old, new).map { |l| " #{l}" }.join("\n")
30
+ elsif (old + new).size > 100
31
+ " #{type}#{field}\n" \
32
+ " #{old} ->\n" \
33
+ " #{new}"
34
+ else
35
+ " #{type}#{field} #{old} -> #{new}"
36
+ end
37
+
38
+ truncate(message)
39
+ end
40
+
41
+ private
42
+
43
+ # display diff for multi-line strings
44
+ # must stay readable when color is off too
45
+ def multiline_diff(old, new)
46
+ Diff::LCS.sdiff(old.split("\n", -1), new.split("\n", -1)).flat_map do |diff|
47
+ case diff.action
48
+ when "-"
49
+ Utils.color(:red, "- #{diff.old_element}")
50
+ when "+"
51
+ Utils.color(:green, "+ #{diff.new_element}")
52
+ when "!"
53
+ [
54
+ Utils.color(:red, "- #{diff.old_element}"),
55
+ Utils.color(:green, "+ #{diff.new_element}")
56
+ ]
57
+ else
58
+ " #{diff.old_element}"
59
+ end
60
+ end
61
+ end
62
+
63
+ def truncate(message)
64
+ warning = Utils.color(
65
+ :magenta,
66
+ " (Diff for this item truncated after #{@max_diff_lines} lines. " \
67
+ "Rerun with MAX_DIFF_LINES=#{@max_diff_lines * 2} to see more)"
68
+ )
69
+ Utils.truncate_lines(message, to: @max_diff_lines, warning: warning)
70
+ end
71
+
72
+ # TODO: use awesome-print or similar, but it has too many monkey-patches
73
+ # https://github.com/amazing-print/amazing_print/issues/36
74
+ def pretty_inspect(object)
75
+ string = object.inspect.dup
76
+ string.gsub!(/:([a-z_]+)=>/, "\\1: ")
77
+ 10.times do
78
+ string.gsub!(/{(\S.*?\S)}/, "{ \\1 }") || break
79
+ end
80
+ string
81
+ end
82
+ end
83
+ end
@@ -189,7 +189,7 @@ module Kennel
189
189
 
190
190
  # important to the front and rest deterministic
191
191
  def sort_hash(hash)
192
- Hash[hash.sort_by { |k, _| [SORT_ORDER.index(k) || 999, k] }]
192
+ hash.sort_by { |k, _| [SORT_ORDER.index(k) || 999, k] }.to_h
193
193
  end
194
194
  end
195
195
  end
@@ -35,8 +35,8 @@ module Kennel
35
35
  :klass, :tracking_id # added by syncer.rb
36
36
  ].freeze
37
37
  ALLOWED_KENNEL_ID_CHARS = "a-zA-Z_\\d.-"
38
- ALLOWED_KENNEL_ID_FULL = "[#{ALLOWED_KENNEL_ID_CHARS}]+:[#{ALLOWED_KENNEL_ID_CHARS}]+"
39
- ALLOWED_KENNEL_ID_REGEX = /\A#{ALLOWED_KENNEL_ID_FULL}\z/.freeze
38
+ ALLOWED_KENNEL_ID_FULL = "[#{ALLOWED_KENNEL_ID_CHARS}]+:[#{ALLOWED_KENNEL_ID_CHARS}]+".freeze
39
+ ALLOWED_KENNEL_ID_REGEX = /\A#{ALLOWED_KENNEL_ID_FULL}\z/
40
40
 
41
41
  settings :id, :kennel_id
42
42
 
@@ -52,7 +52,7 @@ module Kennel
52
52
  end
53
53
 
54
54
  def api_resource_map
55
- subclasses.map { |s| [s.api_resource, s] }.to_h
55
+ subclasses.to_h { |s| [s.api_resource, s] }
56
56
  end
57
57
 
58
58
  def parse_tracking_id(a)
@@ -98,6 +98,8 @@ module Kennel
98
98
 
99
99
  self.class.send(:normalize, expected, actual)
100
100
 
101
+ return [] if actual == expected # Hashdiff is slow, this is fast
102
+
101
103
  # strict: ignore Integer vs Float
102
104
  # similarity: show diff when not 100% similar
103
105
  # use_lcs: saner output
@@ -3,8 +3,7 @@ module Kennel
3
3
  module Models
4
4
  class SyntheticTest < Record
5
5
  TRACKING_FIELD = :message
6
- DEFAULTS = {
7
- }.freeze
6
+ DEFAULTS = {}.freeze
8
7
  READONLY_ATTRIBUTES = superclass::READONLY_ATTRIBUTES + [:status, :monitor_id]
9
8
  LOCATIONS = ["aws:ca-central-1", "aws:eu-north-1", "aws:eu-west-1", "aws:eu-west-3", "aws:eu-west-2", "aws:ap-south-1", "aws:us-west-2", "aws:us-west-1", "aws:sa-east-1", "aws:us-east-2", "aws:ap-northeast-1", "aws:ap-northeast-2", "aws:eu-central-1", "aws:ap-southeast-2", "aws:ap-southeast-1"].freeze
10
9
 
@@ -8,13 +8,9 @@ module Kennel
8
8
 
9
9
  def write(parts)
10
10
  Progress.progress "Storing" do
11
- if filter.tracking_id_filter
12
- write_changed(parts)
13
- else
14
- old = old_paths
15
- used = write_changed(parts)
16
- (old - used).uniq.each { |p| FileUtils.rm_rf(p) }
17
- end
11
+ existing = existing_files_and_folders
12
+ used = write_changed(parts)
13
+ FileUtils.rm_rf(existing - used)
18
14
  end
19
15
  end
20
16
 
@@ -26,31 +22,36 @@ module Kennel
26
22
  used = []
27
23
 
28
24
  Utils.parallel(parts, max: 2) do |part|
29
- path = "generated/#{part.tracking_id.tr("/", ":").sub(":", "/")}.json"
25
+ path = path_for_tracking_id(part.tracking_id)
30
26
 
31
- used << File.dirname(path) # only 1 level of sub folders, so this is enough
27
+ used << File.dirname(path) # we have 1 level of sub folders, so this is enough
32
28
  used << path
33
29
 
34
- payload = part.as_json.merge(api_resource: part.class.api_resource)
35
- write_file_if_necessary(path, JSON.pretty_generate(payload) << "\n")
30
+ content = part.as_json.merge(api_resource: part.class.api_resource)
31
+ write_file_if_necessary(path, content)
36
32
  end
37
33
 
38
34
  used
39
35
  end
40
36
 
41
- def directories_to_clean_up
42
- if filter.project_filter
43
- filter.project_filter.map { |project| "generated/#{project}" }
37
+ def existing_files_and_folders
38
+ if filter.tracking_id_filter
39
+ filter.tracking_id_filter.map { |tracking_id| path_for_tracking_id(tracking_id) }
40
+ elsif filter.project_filter
41
+ filter.project_filter.flat_map { |project| Dir["generated/#{project}/*"] }
44
42
  else
45
- ["generated"]
43
+ Dir["generated/**/*"] # also includes folders so we clean up empty directories
46
44
  end
47
45
  end
48
46
 
49
- def old_paths
50
- Dir["{#{directories_to_clean_up.join(",")}}/**/*"]
47
+ def path_for_tracking_id(tracking_id)
48
+ "generated/#{tracking_id.tr("/", ":").sub(":", "/")}.json"
51
49
  end
52
50
 
53
51
  def write_file_if_necessary(path, content)
52
+ # NOTE: always generating is faster than JSON.load-ing and comparing
53
+ content = JSON.pretty_generate(content) << "\n"
54
+
54
55
  # 99% case
55
56
  begin
56
57
  return if File.read(path) == content
data/lib/kennel/syncer.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "diff/lcs"
4
-
5
3
  module Kennel
6
4
  class Syncer
7
5
  DELETE_ORDER = ["dashboard", "slo", "monitor", "synthetics/tests"].freeze # dashboards references monitors + slos, slos reference monitors
@@ -10,35 +8,41 @@ module Kennel
10
8
  Plan = Struct.new(:changes, keyword_init: true)
11
9
  Change = Struct.new(:type, :api_resource, :tracking_id, :id)
12
10
 
13
- def initialize(api, expected, actual, kennel:, project_filter: nil, tracking_id_filter: nil)
11
+ def initialize(api, expected, actual, strict_imports: true, project_filter: nil, tracking_id_filter: nil)
14
12
  @api = api
15
- @kennel = kennel
13
+ @expected = Set.new expected # need Set to speed up deletion
14
+ @actual = actual
15
+ @strict_imports = strict_imports
16
16
  @project_filter = project_filter
17
17
  @tracking_id_filter = tracking_id_filter
18
- @expected = Set.new expected # need set to speed up deletion
19
- @actual = actual
20
- calculate_diff
21
- validate_plan
18
+
19
+ @attribute_differ = AttributeDiffer.new
20
+
21
+ calculate_changes
22
+ validate_changes
22
23
  prevent_irreversible_partial_updates
24
+
25
+ @warnings.each { |message| Kennel.out.puts Utils.color(:yellow, "Warning: #{message}") }
23
26
  end
24
27
 
25
28
  def plan
29
+ Plan.new(
30
+ changes:
31
+ @create.map { |_id, e, _a| Change.new(:create, e.class.api_resource, e.tracking_id, nil) } +
32
+ @update.map { |id, e, _a| Change.new(:update, e.class.api_resource, e.tracking_id, id) } +
33
+ @delete.map { |id, _e, a| Change.new(:delete, a.fetch(:klass).api_resource, a.fetch(:tracking_id), id) }
34
+ )
35
+ end
36
+
37
+ def print_plan
26
38
  Kennel.out.puts "Plan:"
27
39
  if noop?
28
40
  Kennel.out.puts Utils.color(:green, "Nothing to do")
29
41
  else
30
- @warnings.each { |message| Kennel.out.puts Utils.color(:yellow, "Warning: #{message}") }
31
- print_plan "Create", @create, :green
32
- print_plan "Update", @update, :yellow
33
- print_plan "Delete", @delete, :red
42
+ print_changes "Create", @create, :green
43
+ print_changes "Update", @update, :yellow
44
+ print_changes "Delete", @delete, :red
34
45
  end
35
-
36
- Plan.new(
37
- changes:
38
- @create.map { |_id, e, _a| Change.new(:create, e.class.api_resource, e.tracking_id, nil) } +
39
- @update.map { |id, e, _a| Change.new(:update, e.class.api_resource, e.tracking_id, id) } +
40
- @delete.map { |id, _e, a| Change.new(:delete, a.fetch(:klass).api_resource, a.fetch(:tracking_id), id) }
41
- )
42
46
  end
43
47
 
44
48
  def confirm
@@ -83,8 +87,6 @@ module Kennel
83
87
 
84
88
  private
85
89
 
86
- attr_reader :kennel
87
-
88
90
  # loop over items until everything is resolved or crash when we get stuck
89
91
  # this solves cases like composite monitors depending on each other or monitor->monitor slo->slo monitor chains
90
92
  def each_resolved(list)
@@ -120,58 +122,67 @@ module Kennel
120
122
  @create.empty? && @update.empty? && @delete.empty?
121
123
  end
122
124
 
123
- def calculate_diff
125
+ def calculate_changes
124
126
  @warnings = []
125
- @update = []
126
- @delete = []
127
127
  @id_map = IdMap.new
128
128
 
129
129
  Progress.progress "Diffing" do
130
130
  populate_id_map @expected, @actual
131
131
  filter_actual! @actual
132
132
  resolve_linked_tracking_ids! @expected # resolve dependencies to avoid diff
133
+ @expected.each(&:add_tracking_id) # avoid diff with actual, which has tracking_id
133
134
 
134
- @expected.each(&:add_tracking_id) # avoid diff with actual
135
+ # see which expected match the actual
136
+ matching, unmatched_expected, unmatched_actual = partition_matched_expected
137
+ validate_expected_id_not_missing unmatched_expected
138
+ fill_details! matching # need details to diff later
135
139
 
136
- lookup_map = matching_expected_lookup_map
137
- items = @actual.map do |a|
138
- e = matching_expected(a, lookup_map)
139
- if e && @expected.delete?(e)
140
- [e, a]
141
- else
142
- [nil, a]
143
- end
144
- end
140
+ # update matching if needed
141
+ @update = matching.map do |e, a|
142
+ id = a.fetch(:id)
143
+ diff = e.diff(a)
144
+ [id, e, a, diff] if diff.any?
145
+ end.compact
145
146
 
146
- # fill details of things we need to compare
147
- details = items.map { |e, a| a if e && e.class.api_resource == "dashboard" }.compact
148
- @api.fill_details! "dashboard", details
147
+ # delete previously managed
148
+ @delete = unmatched_actual.map { |a| [a.fetch(:id), nil, a] if a.fetch(:tracking_id) }.compact
149
149
 
150
- # pick out things to update or delete
151
- items.each do |e, a|
152
- id = a.fetch(:id)
153
- if e
154
- diff = e.diff(a) # slow ...
155
- if diff.any?
156
- @update << [id, e, a, diff]
157
- end
158
- elsif a.fetch(:tracking_id) # was previously managed
159
- @delete << [id, nil, a]
160
- end
161
- end
150
+ # unmatched expected need to be created
151
+ @create = unmatched_expected.map { |e| [nil, e] }
162
152
 
163
- ensure_all_ids_found
164
- @create = @expected.map { |e| [nil, e] }
153
+ # order to avoid deadlocks
165
154
  @delete.sort_by! { |_, _, a| DELETE_ORDER.index a.fetch(:klass).api_resource }
166
155
  @update.sort_by! { |_, e, _| DELETE_ORDER.index e.class.api_resource } # slo needs to come before slo alert
167
156
  end
168
157
  end
169
158
 
170
- def ensure_all_ids_found
171
- @expected.each do |e|
159
+ def partition_matched_expected
160
+ lookup_map = matching_expected_lookup_map
161
+ unmatched_expected = @expected.dup
162
+ unmatched_actual = []
163
+ matched = []
164
+ @actual.each do |a|
165
+ e = matching_expected(a, lookup_map)
166
+ if e && unmatched_expected.delete?(e)
167
+ matched << [e, a]
168
+ else
169
+ unmatched_actual << a
170
+ end
171
+ end.compact
172
+ [matched, unmatched_expected, unmatched_actual]
173
+ end
174
+
175
+ # fill details of things we need to compare
176
+ def fill_details!(details_needed)
177
+ details_needed = details_needed.map { |e, a| a if e && e.class.api_resource == "dashboard" }.compact
178
+ @api.fill_details! "dashboard", details_needed
179
+ end
180
+
181
+ def validate_expected_id_not_missing(expected)
182
+ expected.each do |e|
172
183
  next unless id = e.id
173
184
  resource = e.class.api_resource
174
- if kennel.strict_imports
185
+ if @strict_imports
175
186
  raise "Unable to find existing #{resource} with id #{id}\nIf the #{resource} was deleted, remove the `id: -> { #{id} }` line."
176
187
  else
177
188
  @warnings << "#{resource} #{e.tracking_id} specifies id #{id}, but no such #{resource} exists. 'id' will be ignored. Remove the `id: -> { #{id} }` line."
@@ -196,79 +207,18 @@ module Kennel
196
207
  map["#{klass.api_resource}:#{a.fetch(:id)}"] || map[a.fetch(:tracking_id)]
197
208
  end
198
209
 
199
- def print_plan(step, list, color)
210
+ def print_changes(step, list, color)
200
211
  return if list.empty?
201
212
  list.each do |_, e, a, diff|
202
213
  klass = (e ? e.class : a.fetch(:klass))
203
214
  Kennel.out.puts Utils.color(color, "#{step} #{klass.api_resource} #{e&.tracking_id || a.fetch(:tracking_id)}")
204
- print_diff(diff) if diff # only for update
205
- end
206
- end
207
-
208
- def print_diff(diff)
209
- diff.each do |type, field, old, new|
210
- use_diff = false
211
- if type == "+"
212
- temp = Utils.pretty_inspect(new)
213
- new = Utils.pretty_inspect(old)
214
- old = temp
215
- elsif old.is_a?(String) && new.is_a?(String) && (old.include?("\n") || new.include?("\n"))
216
- use_diff = true
217
- else # ~ and -
218
- old = Utils.pretty_inspect(old)
219
- new = Utils.pretty_inspect(new)
220
- end
221
-
222
- message =
223
- if use_diff
224
- " #{type}#{field}\n" +
225
- diff(old, new).map { |l| " #{l}" }.join("\n")
226
- elsif (old + new).size > 100
227
- " #{type}#{field}\n" \
228
- " #{old} ->\n" \
229
- " #{new}"
230
- else
231
- " #{type}#{field} #{old} -> #{new}"
232
- end
233
-
234
- Kennel.out.puts truncate_diff(message)
235
- end
236
- end
237
-
238
- # display diff for multi-line strings
239
- # must stay readable when color is off too
240
- def diff(old, new)
241
- Diff::LCS.sdiff(old.split("\n", -1), new.split("\n", -1)).flat_map do |diff|
242
- case diff.action
243
- when "-"
244
- Utils.color(:red, "- #{diff.old_element}")
245
- when "+"
246
- Utils.color(:green, "+ #{diff.new_element}")
247
- when "!"
248
- [
249
- Utils.color(:red, "- #{diff.old_element}"),
250
- Utils.color(:green, "+ #{diff.new_element}")
251
- ]
252
- else
253
- " #{diff.old_element}"
254
- end
215
+ diff&.each { |args| Kennel.out.puts @attribute_differ.format(*args) } # only for update
255
216
  end
256
217
  end
257
218
 
258
- def truncate_diff(message)
259
- # min '2' because: -1 makes no sense, 0 does not work with * 2 math, 1 says '1 lines'
260
- @max_diff_lines ||= [Integer(ENV.fetch("MAX_DIFF_LINES", "50")), 2].max
261
- warning = Utils.color(
262
- :magenta,
263
- " (Diff for this item truncated after #{@max_diff_lines} lines. " \
264
- "Rerun with MAX_DIFF_LINES=#{@max_diff_lines * 2} to see more)"
265
- )
266
- Utils.truncate_lines(message, to: @max_diff_lines, warning: warning)
267
- end
268
-
269
219
  # We've already validated the desired objects ('generated') in isolation.
270
220
  # Now that we have made the plan, we can perform some more validation.
271
- def validate_plan
221
+ def validate_changes
272
222
  @update.each do |_, expected, actuals, diffs|
273
223
  expected.validate_update!(actuals, diffs)
274
224
  end
@@ -276,11 +226,10 @@ module Kennel
276
226
 
277
227
  # - do not add tracking-id when working with existing ids on a branch,
278
228
  # so resource do not get deleted when running an update on master (for example merge->CI)
279
- # - make sure the diff is clean, by kicking out the now noop-update
280
229
  # - ideally we'd never add tracking in the first place, but when adding tracking we do not know the diff yet
281
230
  def prevent_irreversible_partial_updates
282
- return unless @project_filter
283
- @update.select! do |_, e, _, diff|
231
+ return unless @project_filter # full update, so we are not on a branch
232
+ @update.select! do |_, e, _, diff| # ensure clean diff, by removing noop-update
284
233
  next true unless e.id # safe to add tracking when not having id
285
234
 
286
235
  diff.select! do |field_diff|
@@ -293,7 +242,7 @@ module Kennel
293
242
  actual != field_diff[3] # discard diff if now nothing changes
294
243
  end
295
244
 
296
- !diff.empty?
245
+ diff.any?
297
246
  end
298
247
  end
299
248
 
data/lib/kennel/utils.rb CHANGED
@@ -5,6 +5,7 @@ module Kennel
5
5
 
6
6
  class TeeIO < IO
7
7
  def initialize(ios)
8
+ super(0) # called with fake file descriptor 0, so we can call super and get a proper class
8
9
  @ios = ios
9
10
  end
10
11
 
@@ -150,17 +151,6 @@ module Kennel
150
151
  end
151
152
  end
152
153
 
153
- # TODO: use awesome-print or similar, but it has too many monkey-patches
154
- # https://github.com/amazing-print/amazing_print/issues/36
155
- def pretty_inspect(object)
156
- string = object.inspect.dup
157
- string.gsub!(/:([a-z_]+)=>/, "\\1: ")
158
- 10.times do
159
- string.gsub!(/{(\S.*?\S)}/, "{ \\1 }") || break
160
- end
161
- string
162
- end
163
-
164
154
  def inline_resource_metadata(resource, klass)
165
155
  resource[:klass] = klass
166
156
  resource[:tracking_id] = klass.parse_tracking_id(resource)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.128.0"
3
+ VERSION = "1.129.0"
4
4
  end
data/lib/kennel.rb CHANGED
@@ -10,6 +10,7 @@ require "kennel/progress"
10
10
  require "kennel/filter"
11
11
  require "kennel/parts_serializer"
12
12
  require "kennel/projects_provider"
13
+ require "kennel/attribute_differ"
13
14
  require "kennel/syncer"
14
15
  require "kennel/id_map"
15
16
  require "kennel/api"
@@ -42,7 +43,6 @@ module Kennel
42
43
  UnresolvableIdError = Class.new(StandardError)
43
44
  DisallowedUpdateError = Class.new(StandardError)
44
45
  GenerationAbortedError = Class.new(StandardError)
45
- UpdateResult = Struct.new(:plan, :update, keyword_init: true)
46
46
 
47
47
  class << self
48
48
  attr_accessor :out, :err
@@ -52,12 +52,12 @@ module Kennel
52
52
  self.err = $stderr
53
53
 
54
54
  class Engine
55
+ attr_accessor :strict_imports
56
+
55
57
  def initialize
56
58
  @strict_imports = true
57
59
  end
58
60
 
59
- attr_accessor :strict_imports
60
-
61
61
  # start generation and download in parallel to make planning faster
62
62
  def preload
63
63
  Utils.parallel([:generated, :definitions]) { |m| send m, plain: true }
@@ -65,16 +65,17 @@ module Kennel
65
65
 
66
66
  def generate
67
67
  parts = generated
68
- parts_serializer.write(parts) if ENV["STORE"] != "false" # quicker when debugging
68
+ PartsSerializer.new(filter: filter).write(parts) if ENV["STORE"] != "false" # quicker when debugging
69
69
  parts
70
70
  end
71
71
 
72
72
  def plan
73
+ syncer.print_plan
73
74
  syncer.plan
74
75
  end
75
76
 
76
77
  def update
77
- syncer.plan
78
+ syncer.print_plan
78
79
  syncer.update if syncer.confirm
79
80
  end
80
81
 
@@ -87,7 +88,12 @@ module Kennel
87
88
  def syncer
88
89
  @syncer ||= begin
89
90
  preload
90
- Syncer.new(api, generated, definitions, kennel: self, project_filter: filter.project_filter, tracking_id_filter: filter.tracking_id_filter)
91
+ Syncer.new(
92
+ api, generated, definitions,
93
+ strict_imports: strict_imports,
94
+ project_filter: filter.project_filter,
95
+ tracking_id_filter: filter.tracking_id_filter
96
+ )
91
97
  end
92
98
  end
93
99
 
@@ -95,18 +101,10 @@ module Kennel
95
101
  @api ||= Api.new
96
102
  end
97
103
 
98
- def projects_provider
99
- @projects_provider ||= ProjectsProvider.new
100
- end
101
-
102
- def parts_serializer
103
- @parts_serializer ||= PartsSerializer.new(filter: filter)
104
- end
105
-
106
104
  def generated(**kwargs)
107
105
  @generated ||= begin
108
106
  parts = Progress.progress "Finding parts", **kwargs do
109
- projects = projects_provider.projects
107
+ projects = ProjectsProvider.new.projects
110
108
  projects = filter.filter_projects projects
111
109
 
112
110
  parts = Utils.parallel(projects, &:validated_parts).flatten(1)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kennel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.128.0
4
+ version: 1.129.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-06 00:00:00.000000000 Z
11
+ date: 2022-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -80,7 +80,7 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '2.4'
83
- description:
83
+ description:
84
84
  email: michael@grosser.it
85
85
  executables: []
86
86
  extensions: []
@@ -89,6 +89,7 @@ files:
89
89
  - Readme.md
90
90
  - lib/kennel.rb
91
91
  - lib/kennel/api.rb
92
+ - lib/kennel/attribute_differ.rb
92
93
  - lib/kennel/file_cache.rb
93
94
  - lib/kennel/filter.rb
94
95
  - lib/kennel/github_reporter.rb
@@ -119,7 +120,7 @@ homepage: https://github.com/grosser/kennel
119
120
  licenses:
120
121
  - MIT
121
122
  metadata: {}
122
- post_install_message:
123
+ post_install_message:
123
124
  rdoc_options: []
124
125
  require_paths:
125
126
  - lib
@@ -127,15 +128,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
128
  requirements:
128
129
  - - ">="
129
130
  - !ruby/object:Gem::Version
130
- version: 2.6.0
131
+ version: 3.1.0
131
132
  required_rubygems_version: !ruby/object:Gem::Requirement
132
133
  requirements:
133
134
  - - ">="
134
135
  - !ruby/object:Gem::Version
135
136
  version: '0'
136
137
  requirements: []
137
- rubygems_version: 3.0.3
138
- signing_key:
138
+ rubygems_version: 3.3.26
139
+ signing_key:
139
140
  specification_version: 4
140
141
  summary: Keep datadog monitors/dashboards/etc in version control, avoid chaotic management
141
142
  via UI