kennel 1.128.0 → 1.129.0

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: 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