kennel 1.131.0 → 1.133.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: ac3eeb3c1ec0e2b03c7acbf2b2d7c68335207a7e79408775e9b876c6c4acd400
4
- data.tar.gz: db96fddb04bce543efcea1a505a1d360447161259e9e9fdd481acfe785bad194
3
+ metadata.gz: d3aff9df6291b4831989719092533b91416db67398fbd2f8b43d694ce2a758c6
4
+ data.tar.gz: 316279b5d6059c65281322e8d0dae8caeac665a48bba70c377c218febfd76fb9
5
5
  SHA512:
6
- metadata.gz: a710b2e2ae6932cf36bdd12fbb06c34f8b538944e693a484b294e7614b7d9941e7c2da498cf7cdcb56bda255a0b2c874383306437ee5b71456d900ae1e9a5c2f
7
- data.tar.gz: 90e767722863bb640f3bd96436937c390d40d8c8b868d3ee51a444ff6e042e36f03048cc1b5c9cec49d96207d53d99df6f529318658c3881fd9078ed55c2b7d8
6
+ metadata.gz: f54f29018a039ee2b5d8bf4bfb05b371af4551c102a0f349463faa6a380873b387d5f8229460bb6b991d30a21cd2cdbb14765c43400e983bc74d13822467d7bf
7
+ data.tar.gz: c893a9caa3a122f454cf7f654c4583df3397c985fa230f06ff9fcdaec07fb90b89be43a363eb5911483aad6bf9699971ea0664dcc0e4758fb61e833bce587008
data/lib/kennel/filter.rb CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  module Kennel
4
4
  class Filter
5
- attr_reader :project_filter, :tracking_id_filter
6
-
7
5
  def initialize
8
6
  # build early so we fail fast on invalid user input
9
7
  @tracking_id_filter = build_tracking_id_filter
@@ -18,8 +16,25 @@ module Kennel
18
16
  filter_resources(parts, :tracking_id, tracking_id_filter, "resources", "TRACKING_ID")
19
17
  end
20
18
 
19
+ def filtering?
20
+ !project_filter.nil?
21
+ end
22
+
23
+ def matches_project_id?(project_id)
24
+ !filtering? || project_filter.include?(project_id)
25
+ end
26
+
27
+ def matches_tracking_id?(tracking_id)
28
+ return true unless filtering?
29
+ return tracking_id_filter.include?(tracking_id) if tracking_id_filter
30
+
31
+ project_filter.include?(tracking_id.split(":").first)
32
+ end
33
+
21
34
  private
22
35
 
36
+ attr_reader :project_filter, :tracking_id_filter
37
+
23
38
  def build_project_filter
24
39
  project_names = ENV["PROJECT"]&.split(",")&.sort&.uniq
25
40
  tracking_project_names = tracking_id_filter&.map { |id| id.split(":", 2).first }&.sort&.uniq
@@ -22,7 +22,8 @@ module Kennel
22
22
  notify_audit: false,
23
23
  no_data_timeframe: nil, # this works out ok since if notify_no_data is on, it would never be nil
24
24
  groupby_simple_monitor: false,
25
- variables: nil
25
+ variables: nil,
26
+ on_missing_data: "default"
26
27
  }.freeze
27
28
  DEFAULT_ESCALATION_MESSAGE = ["", nil].freeze
28
29
  ALLOWED_PRIORITY_CLASSES = [NilClass, Integer].freeze
@@ -31,7 +32,7 @@ module Kennel
31
32
  settings(
32
33
  :query, :name, :message, :escalation_message, :critical, :type, :renotify_interval, :warning, :timeout_h, :evaluation_delay,
33
34
  :ok, :no_data_timeframe, :notify_no_data, :notify_audit, :tags, :critical_recovery, :warning_recovery, :require_full_window,
34
- :threshold_windows, :new_host_delay, :new_group_delay, :priority, :validate_using_links, :variables
35
+ :threshold_windows, :new_host_delay, :new_group_delay, :priority, :validate_using_links, :variables, :on_missing_data
35
36
  )
36
37
 
37
38
  defaults(
@@ -52,7 +53,8 @@ module Kennel
52
53
  warning_recovery: -> { nil },
53
54
  threshold_windows: -> { nil },
54
55
  priority: -> { MONITOR_DEFAULTS.fetch(:priority) },
55
- variables: -> { MONITOR_OPTION_DEFAULTS.fetch(:variables) }
56
+ variables: -> { MONITOR_OPTION_DEFAULTS.fetch(:variables) },
57
+ on_missing_data: -> { notify_no_data ? "show_and_notify_no_data" : "default" } # "default" is "evaluate as zero"
56
58
  )
57
59
 
58
60
  def build_json
@@ -123,6 +125,13 @@ module Kennel
123
125
  options[:renotify_statuses] = statuses
124
126
  end
125
127
 
128
+ # for events: on_missing_data cannot be used with notify_no_data or no_data_timeframe
129
+ if data.fetch(:type) == "event-v2 alert"
130
+ options[:on_missing_data] = on_missing_data
131
+ options[:notify_no_data] = false # cannot set nil or it's an endless update loop
132
+ options.delete :no_data_timeframe
133
+ end
134
+
126
135
  data
127
136
  end
128
137
 
@@ -35,7 +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}]+".freeze
38
+ ALLOWED_KENNEL_ID_SEGMENT = /[#{ALLOWED_KENNEL_ID_CHARS}]+/
39
+ ALLOWED_KENNEL_ID_FULL = "#{ALLOWED_KENNEL_ID_SEGMENT}:#{ALLOWED_KENNEL_ID_SEGMENT}".freeze
39
40
  ALLOWED_KENNEL_ID_REGEX = /\A#{ALLOWED_KENNEL_ID_FULL}\z/
40
41
 
41
42
  settings :id, :kennel_id
@@ -35,13 +35,16 @@ module Kennel
35
35
  end
36
36
 
37
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}/*"] }
42
- else
43
- Dir["generated/**/*"] # also includes folders so we clean up empty directories
38
+ paths = Dir["generated/**/*"]
39
+
40
+ if filter.filtering?
41
+ paths.select! do |path|
42
+ tracking_id = path.split("/")[1..2].to_a.join(":")
43
+ filter.matches_tracking_id?(tracking_id)
44
+ end
44
45
  end
46
+
47
+ paths
45
48
  end
46
49
 
47
50
  def path_for_tracking_id(tracking_id)
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kennel
4
+ class Syncer
5
+ module MatchedExpected
6
+ class << self
7
+ def partition(expected, actual)
8
+ lookup_map = matching_expected_lookup_map(expected)
9
+ unmatched_expected = Set.new(expected) # for efficient deletion
10
+ unmatched_actual = []
11
+ matched = []
12
+ actual.each do |a|
13
+ e = matching_expected(a, lookup_map)
14
+ if e && unmatched_expected.delete?(e)
15
+ matched << [e, a]
16
+ else
17
+ unmatched_actual << a
18
+ end
19
+ end.compact
20
+ [matched, unmatched_expected.to_a, unmatched_actual]
21
+ end
22
+
23
+ private
24
+
25
+ # index list by all the thing we look up by: tracking id and actual id
26
+ def matching_expected_lookup_map(expected)
27
+ expected.each_with_object({}) do |e, all|
28
+ keys = [e.tracking_id]
29
+ keys << "#{e.class.api_resource}:#{e.id}" if e.id
30
+ keys.compact.each do |key|
31
+ raise "Lookup #{key} is duplicated" if all[key]
32
+ all[key] = e
33
+ end
34
+ end
35
+ end
36
+
37
+ def matching_expected(a, map)
38
+ klass = a.fetch(:klass)
39
+ map["#{klass.api_resource}:#{a.fetch(:id)}"] || map[a.fetch(:tracking_id)]
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kennel
4
+ class Syncer
5
+ class PlanDisplayer
6
+ def initialize
7
+ @attribute_differ = AttributeDiffer.new
8
+ end
9
+
10
+ def display(internal_plan)
11
+ Kennel.out.puts "Plan:"
12
+ if internal_plan.empty?
13
+ Kennel.out.puts Console.color(:green, "Nothing to do")
14
+ else
15
+ print_changes "Create", internal_plan.creates, :green
16
+ print_changes "Update", internal_plan.updates, :yellow
17
+ print_changes "Delete", internal_plan.deletes, :red
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def print_changes(step, list, color)
24
+ return if list.empty?
25
+ list.each do |item|
26
+ Kennel.out.puts Console.color(color, "#{step} #{item.api_resource} #{item.tracking_id}")
27
+ if item.class::TYPE == :update
28
+ item.diff.each { |args| Kennel.out.puts @attribute_differ.format(*args) } # only for update
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../id_map"
4
+
5
+ module Kennel
6
+ class Syncer
7
+ class Resolver
8
+ def initialize(expected:, filter:)
9
+ @id_map = IdMap.new
10
+ @filter = filter
11
+
12
+ # mark everything as new
13
+ expected.each do |e|
14
+ id_map.set(e.class.api_resource, e.tracking_id, IdMap::NEW)
15
+ if e.class.api_resource == "synthetics/tests"
16
+ id_map.set(Kennel::Models::Monitor.api_resource, e.tracking_id, IdMap::NEW)
17
+ end
18
+ end
19
+ end
20
+
21
+ def add_actual(actual)
22
+ # override resources that exist with their id
23
+ actual.each do |a|
24
+ # ignore when not managed by kennel
25
+ next unless tracking_id = a.fetch(:tracking_id)
26
+
27
+ # ignore when deleted from the codebase
28
+ # (when running with filters we cannot see the other resources in the codebase)
29
+ api_resource = a.fetch(:klass).api_resource
30
+ next if !id_map.get(api_resource, tracking_id) && filter.matches_tracking_id?(tracking_id)
31
+
32
+ id_map.set(api_resource, tracking_id, a.fetch(:id))
33
+ if a.fetch(:klass).api_resource == "synthetics/tests"
34
+ id_map.set(Kennel::Models::Monitor.api_resource, tracking_id, a.fetch(:monitor_id))
35
+ end
36
+ end
37
+ end
38
+
39
+ def resolve_as_much_as_possible(expected)
40
+ expected.each do |e|
41
+ e.resolve_linked_tracking_ids!(id_map, force: false)
42
+ end
43
+ end
44
+
45
+ # loop over items until everything is resolved or crash when we get stuck
46
+ # this solves cases like composite monitors depending on each other or monitor->monitor slo->slo monitor chains
47
+ def each_resolved(list)
48
+ list = list.dup
49
+ loop do
50
+ return if list.empty?
51
+ list.reject! do |item|
52
+ if resolved?(item.expected)
53
+ yield item
54
+ true
55
+ else
56
+ false
57
+ end
58
+ end ||
59
+ assert_resolved(list[0].expected) # resolve something or show a circular dependency error
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ attr_reader :id_map, :filter
66
+
67
+ # TODO: optimize by storing an instance variable if already resolved
68
+ def resolved?(e)
69
+ assert_resolved e
70
+ true
71
+ rescue UnresolvableIdError
72
+ false
73
+ end
74
+
75
+ # raises UnresolvableIdError when not resolved
76
+ def assert_resolved(e)
77
+ e.resolve_linked_tracking_ids!(id_map, force: true)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kennel
4
+ class Syncer
5
+ module Types
6
+ class PlannedChange
7
+ def initialize(klass, tracking_id)
8
+ @klass = klass
9
+ @tracking_id = tracking_id
10
+ end
11
+
12
+ def api_resource
13
+ klass.api_resource
14
+ end
15
+
16
+ def url(id = nil)
17
+ klass.url(id || self.id)
18
+ end
19
+
20
+ def change(id = nil)
21
+ Change.new(self.class::TYPE, api_resource, tracking_id, id)
22
+ end
23
+
24
+ attr_reader :klass, :tracking_id
25
+ end
26
+
27
+ class PlannedCreate < PlannedChange
28
+ TYPE = :create
29
+
30
+ def initialize(expected)
31
+ super(expected.class, expected.tracking_id)
32
+ @expected = expected
33
+ end
34
+
35
+ attr_reader :expected
36
+ end
37
+
38
+ class PlannedUpdate < PlannedChange
39
+ TYPE = :update
40
+
41
+ def initialize(expected, actual, diff)
42
+ super(expected.class, expected.tracking_id)
43
+ @expected = expected
44
+ @actual = actual
45
+ @diff = diff
46
+ @id = actual.fetch(:id)
47
+ end
48
+
49
+ def change
50
+ super(id)
51
+ end
52
+
53
+ attr_reader :expected, :actual, :diff, :id
54
+ end
55
+
56
+ class PlannedDelete < PlannedChange
57
+ TYPE = :delete
58
+
59
+ def initialize(actual)
60
+ super(actual.fetch(:klass), actual.fetch(:tracking_id))
61
+ @actual = actual
62
+ @id = actual.fetch(:id)
63
+ end
64
+
65
+ def change
66
+ super(id)
67
+ end
68
+
69
+ attr_reader :actual, :id
70
+ end
71
+ end
72
+ end
73
+ end
data/lib/kennel/syncer.rb CHANGED
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "./syncer/matched_expected"
4
+ require_relative "./syncer/plan_displayer"
5
+ require_relative "./syncer/resolver"
6
+ require_relative "./syncer/types"
7
+
3
8
  module Kennel
4
9
  class Syncer
5
10
  DELETE_ORDER = ["dashboard", "slo", "monitor", "synthetics/tests"].freeze # dashboards references monitors + slos, slos reference monitors
@@ -15,13 +20,12 @@ module Kennel
15
20
 
16
21
  Change = Struct.new(:type, :api_resource, :tracking_id, :id)
17
22
 
18
- def initialize(api, expected, actual, strict_imports: true, project_filter: nil, tracking_id_filter: nil)
23
+ def initialize(api, expected, actual, filter:, strict_imports: true)
19
24
  @api = api
20
25
  @strict_imports = strict_imports
21
- @project_filter = project_filter
22
- @tracking_id_filter = tracking_id_filter
26
+ @filter = filter
23
27
 
24
- @resolver = Resolver.new(expected: expected, project_filter: @project_filter, tracking_id_filter: @tracking_id_filter)
28
+ @resolver = Resolver.new(expected: expected, filter: filter)
25
29
 
26
30
  internal_plan = calculate_changes(expected: expected, actual: actual)
27
31
  validate_changes(internal_plan)
@@ -81,7 +85,7 @@ module Kennel
81
85
 
82
86
  private
83
87
 
84
- attr_reader :resolver, :internal_plan
88
+ attr_reader :filter, :resolver, :internal_plan
85
89
 
86
90
  def calculate_changes(expected:, actual:)
87
91
  @warnings = []
@@ -101,7 +105,7 @@ module Kennel
101
105
  # Refuse to "adopt" existing items into kennel while running with a filter (i.e. on a branch).
102
106
  # Without this, we'd adopt an item, then the next CI run would delete it
103
107
  # (instead of "unadopting" it).
104
- e.add_tracking_id unless @project_filter && a.fetch(:tracking_id).nil?
108
+ e.add_tracking_id unless filter.filtering? && a.fetch(:tracking_id).nil?
105
109
  id = a.fetch(:id)
106
110
  diff = e.diff(a)
107
111
  a[:id] = id
@@ -150,233 +154,11 @@ module Kennel
150
154
  end
151
155
 
152
156
  def filter_actual!(actual)
153
- if @tracking_id_filter
154
- actual.select! do |a|
155
- tracking_id = a.fetch(:tracking_id)
156
- !tracking_id || @tracking_id_filter.include?(tracking_id)
157
- end
158
- elsif @project_filter
159
- project_prefixes = @project_filter.map { |p| "#{p}:" }
160
- actual.select! do |a|
161
- tracking_id = a.fetch(:tracking_id)
162
- !tracking_id || tracking_id.start_with?(*project_prefixes)
163
- end
164
- end
165
- end
166
-
167
- class PlanDisplayer
168
- def initialize
169
- @attribute_differ = AttributeDiffer.new
170
- end
171
-
172
- def display(internal_plan)
173
- Kennel.out.puts "Plan:"
174
- if internal_plan.empty?
175
- Kennel.out.puts Console.color(:green, "Nothing to do")
176
- else
177
- print_changes "Create", internal_plan.creates, :green
178
- print_changes "Update", internal_plan.updates, :yellow
179
- print_changes "Delete", internal_plan.deletes, :red
180
- end
181
- end
182
-
183
- private
184
-
185
- def print_changes(step, list, color)
186
- return if list.empty?
187
- list.each do |item|
188
- Kennel.out.puts Console.color(color, "#{step} #{item.api_resource} #{item.tracking_id}")
189
- if item.class::TYPE == :update
190
- item.diff.each { |args| Kennel.out.puts @attribute_differ.format(*args) } # only for update
191
- end
192
- end
193
- end
194
- end
195
-
196
- class Resolver
197
- def initialize(expected:, project_filter:, tracking_id_filter:)
198
- @id_map = IdMap.new
199
- @project_filter = project_filter
200
- @tracking_id_filter = tracking_id_filter
201
-
202
- # mark everything as new
203
- expected.each do |e|
204
- id_map.set(e.class.api_resource, e.tracking_id, IdMap::NEW)
205
- if e.class.api_resource == "synthetics/tests"
206
- id_map.set(Kennel::Models::Monitor.api_resource, e.tracking_id, IdMap::NEW)
207
- end
208
- end
209
- end
210
-
211
- def add_actual(actual)
212
- # override resources that exist with their id
213
- project_prefixes = project_filter&.map { |p| "#{p}:" }
214
-
215
- actual.each do |a|
216
- # ignore when not managed by kennel
217
- next unless tracking_id = a.fetch(:tracking_id)
218
-
219
- # ignore when deleted from the codebase
220
- # (when running with filters we cannot see the other resources in the codebase)
221
- api_resource = a.fetch(:klass).api_resource
222
- next if
223
- !id_map.get(api_resource, tracking_id) &&
224
- (!project_prefixes || tracking_id.start_with?(*project_prefixes)) &&
225
- (!tracking_id_filter || tracking_id_filter.include?(tracking_id))
226
-
227
- id_map.set(api_resource, tracking_id, a.fetch(:id))
228
- if a.fetch(:klass).api_resource == "synthetics/tests"
229
- id_map.set(Kennel::Models::Monitor.api_resource, tracking_id, a.fetch(:monitor_id))
230
- end
231
- end
232
- end
233
-
234
- def resolve_as_much_as_possible(expected)
235
- expected.each do |e|
236
- e.resolve_linked_tracking_ids!(id_map, force: false)
237
- end
238
- end
239
-
240
- # loop over items until everything is resolved or crash when we get stuck
241
- # this solves cases like composite monitors depending on each other or monitor->monitor slo->slo monitor chains
242
- def each_resolved(list)
243
- list = list.dup
244
- loop do
245
- return if list.empty?
246
- list.reject! do |item|
247
- if resolved?(item.expected)
248
- yield item
249
- true
250
- else
251
- false
252
- end
253
- end ||
254
- assert_resolved(list[0].expected) # resolve something or show a circular dependency error
255
- end
256
- end
257
-
258
- private
259
-
260
- attr_reader :id_map, :project_filter, :tracking_id_filter
261
-
262
- # TODO: optimize by storing an instance variable if already resolved
263
- def resolved?(e)
264
- assert_resolved e
265
- true
266
- rescue UnresolvableIdError
267
- false
268
- end
269
-
270
- # raises UnresolvableIdError when not resolved
271
- def assert_resolved(e)
272
- e.resolve_linked_tracking_ids!(id_map, force: true)
273
- end
274
- end
275
-
276
- module MatchedExpected
277
- class << self
278
- def partition(expected, actual)
279
- lookup_map = matching_expected_lookup_map(expected)
280
- unmatched_expected = Set.new(expected) # for efficient deletion
281
- unmatched_actual = []
282
- matched = []
283
- actual.each do |a|
284
- e = matching_expected(a, lookup_map)
285
- if e && unmatched_expected.delete?(e)
286
- matched << [e, a]
287
- else
288
- unmatched_actual << a
289
- end
290
- end.compact
291
- [matched, unmatched_expected.to_a, unmatched_actual]
292
- end
293
-
294
- private
295
-
296
- # index list by all the thing we look up by: tracking id and actual id
297
- def matching_expected_lookup_map(expected)
298
- expected.each_with_object({}) do |e, all|
299
- keys = [e.tracking_id]
300
- keys << "#{e.class.api_resource}:#{e.id}" if e.id
301
- keys.compact.each do |key|
302
- raise "Lookup #{key} is duplicated" if all[key]
303
- all[key] = e
304
- end
305
- end
306
- end
307
-
308
- def matching_expected(a, map)
309
- klass = a.fetch(:klass)
310
- map["#{klass.api_resource}:#{a.fetch(:id)}"] || map[a.fetch(:tracking_id)]
311
- end
312
- end
313
- end
314
-
315
- module Types
316
- class PlannedChange
317
- def initialize(klass, tracking_id)
318
- @klass = klass
319
- @tracking_id = tracking_id
320
- end
321
-
322
- def api_resource
323
- klass.api_resource
324
- end
325
-
326
- def url(id = nil)
327
- klass.url(id || self.id)
328
- end
329
-
330
- def change(id = nil)
331
- Change.new(self.class::TYPE, api_resource, tracking_id, id)
332
- end
333
-
334
- attr_reader :klass, :tracking_id
335
- end
336
-
337
- class PlannedCreate < PlannedChange
338
- TYPE = :create
339
-
340
- def initialize(expected)
341
- super(expected.class, expected.tracking_id)
342
- @expected = expected
343
- end
344
-
345
- attr_reader :expected
346
- end
347
-
348
- class PlannedUpdate < PlannedChange
349
- TYPE = :update
350
-
351
- def initialize(expected, actual, diff)
352
- super(expected.class, expected.tracking_id)
353
- @expected = expected
354
- @actual = actual
355
- @diff = diff
356
- @id = actual.fetch(:id)
357
- end
358
-
359
- def change
360
- super(id)
361
- end
362
-
363
- attr_reader :expected, :actual, :diff, :id
364
- end
365
-
366
- class PlannedDelete < PlannedChange
367
- TYPE = :delete
368
-
369
- def initialize(actual)
370
- super(actual.fetch(:klass), actual.fetch(:tracking_id))
371
- @actual = actual
372
- @id = actual.fetch(:id)
373
- end
374
-
375
- def change
376
- super(id)
377
- end
157
+ return unless filter.filtering? # minor optimization
378
158
 
379
- attr_reader :actual, :id
159
+ actual.select! do |a|
160
+ tracking_id = a.fetch(:tracking_id)
161
+ tracking_id.nil? || filter.matches_tracking_id?(tracking_id)
380
162
  end
381
163
  end
382
164
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.131.0"
3
+ VERSION = "1.133.0"
4
4
  end
data/lib/kennel.rb CHANGED
@@ -92,9 +92,8 @@ module Kennel
92
92
  preload
93
93
  Syncer.new(
94
94
  api, generated, definitions,
95
- strict_imports: strict_imports,
96
- project_filter: filter.project_filter,
97
- tracking_id_filter: filter.tracking_id_filter
95
+ filter: filter,
96
+ strict_imports: strict_imports
98
97
  )
99
98
  end
100
99
  end
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.131.0
4
+ version: 1.133.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-09 00:00:00.000000000 Z
11
+ date: 2023-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -112,6 +112,10 @@ files:
112
112
  - lib/kennel/string_utils.rb
113
113
  - lib/kennel/subclass_tracking.rb
114
114
  - lib/kennel/syncer.rb
115
+ - lib/kennel/syncer/matched_expected.rb
116
+ - lib/kennel/syncer/plan_displayer.rb
117
+ - lib/kennel/syncer/resolver.rb
118
+ - lib/kennel/syncer/types.rb
115
119
  - lib/kennel/tasks.rb
116
120
  - lib/kennel/template_variables.rb
117
121
  - lib/kennel/unmuted_alerts.rb