kennel 1.145.1 → 1.147.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: e3043dcfb11f7d16c0ac340a1dc5d94488f801f52a75ed5946c7ec514a116f8d
4
- data.tar.gz: 98b4a64f1b659bde487a5d18a5674b9b3c0022e45bbe48bf9150963fcf289e68
3
+ metadata.gz: 7aa3215e281ade43456180bbdbe048939052d0238b1303705842cad7145b5457
4
+ data.tar.gz: ae9ec09767652ff2839da017731f7f7487e237cbea81d9cebb89f39351bd7cca
5
5
  SHA512:
6
- metadata.gz: e5fee59bdac78be8f4797f3a6ff12117f19cbddf709fb9c1a4d66cc7b39f199ef451d0b014b4556ddedcf5f30285448c554c6bf5168d9bdb54a53beb2d1bf139
7
- data.tar.gz: b0fba5079b184ed126d23a61d6b30daf3d9190665582f56e332a60909f832efa883a078d68f3cee3879ceaf9a2e461b729fc25d2fbada563e9f283c2456eab4a
6
+ metadata.gz: 0064bfa8723de2680d8a7dfd2d050018a040015efa8e57646039cbb825fb3278bbdf29ea8f60de4dc617d61b0ddc69bac4fa050fc125c10be413d1900eca7556
7
+ data.tar.gz: 5a1dc95851d870c5d00ab6d2b17c357572b44ab058ae87d486e6b4786797211fede1e6ef7dc935fc2e743f0ada6a942556f8222a4dc4b931047ffb7dbb07dc74
@@ -160,7 +160,7 @@ module Kennel
160
160
  bad = Kennel::Utils.all_keys(data).grep_v(Symbol).sort.uniq
161
161
  return if bad.empty?
162
162
  invalid!(
163
- :hash_keys_must_be_symbols,
163
+ OptionalValidations::UNIGNORABLE,
164
164
  "Only use Symbols as hash keys to avoid permanent diffs when updating.\n" \
165
165
  "Change these keys to be symbols (usually 'foo' => 1 --> 'foo': 1)\n" \
166
166
  "#{bad.map(&:inspect).join("\n")}"
@@ -18,7 +18,7 @@ module Kennel
18
18
  end
19
19
 
20
20
  def invalid!(tag, message)
21
- validation_errors << ValidationMessage.new(tag || OptionalValidations::UNIGNORABLE, message)
21
+ validation_errors << ValidationMessage.new(tag, message)
22
22
  end
23
23
 
24
24
  def self.valid?(parts)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ module Kennel
3
+ class Syncer
4
+ Plan = Struct.new(:creates, :updates, :deletes) do
5
+ attr_writer :changes
6
+
7
+ def changes
8
+ @changes || (deletes + creates + updates).map(&:change) # roughly ordered in the way that update works
9
+ end
10
+
11
+ def empty?
12
+ (creates + updates + deletes).empty?
13
+ end
14
+ end
15
+
16
+ Change = Struct.new(:type, :api_resource, :tracking_id, :id)
17
+ end
18
+ end
@@ -2,19 +2,19 @@
2
2
 
3
3
  module Kennel
4
4
  class Syncer
5
- class PlanDisplayer
5
+ class PlanPrinter
6
6
  def initialize
7
7
  @attribute_differ = AttributeDiffer.new
8
8
  end
9
9
 
10
- def display(internal_plan)
10
+ def print(plan)
11
11
  Kennel.out.puts "Plan:"
12
- if internal_plan.empty?
12
+ if plan.empty?
13
13
  Kennel.out.puts Console.color(:green, "Nothing to do")
14
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
15
+ print_changes "Create", plan.creates, :green
16
+ print_changes "Update", plan.updates, :yellow
17
+ print_changes "Delete", plan.deletes, :red
18
18
  end
19
19
  end
20
20
 
data/lib/kennel/syncer.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "./syncer/matched_expected"
4
- require_relative "./syncer/plan_displayer"
4
+ require_relative "./syncer/plan"
5
+ require_relative "./syncer/plan_printer"
5
6
  require_relative "./syncer/resolver"
6
7
  require_relative "./syncer/types"
7
8
 
@@ -10,15 +11,7 @@ module Kennel
10
11
  DELETE_ORDER = ["dashboard", "slo", "monitor", "synthetics/tests"].freeze # dashboards references monitors + slos, slos reference monitors
11
12
  LINE_UP = "\e[1A\033[K" # go up and clear
12
13
 
13
- Plan = Struct.new(:changes, keyword_init: true)
14
-
15
- InternalPlan = Struct.new(:creates, :updates, :deletes) do
16
- def empty?
17
- creates.empty? && updates.empty? && deletes.empty?
18
- end
19
- end
20
-
21
- Change = Struct.new(:type, :api_resource, :tracking_id, :id)
14
+ attr_reader :plan
22
15
 
23
16
  def initialize(api, expected, actual, filter:, strict_imports: true)
24
17
  @api = api
@@ -26,27 +19,16 @@ module Kennel
26
19
  @filter = filter
27
20
 
28
21
  @resolver = Resolver.new(expected: expected, filter: filter)
29
-
30
- internal_plan = calculate_changes(expected: expected, actual: actual)
31
- validate_changes(internal_plan)
32
- @internal_plan = internal_plan
33
-
34
- @warnings.each { |message| Kennel.out.puts Console.color(:yellow, "Warning: #{message}") }
35
- end
36
-
37
- def plan
38
- ip = @internal_plan
39
- Plan.new(
40
- changes: (ip.creates + ip.updates + ip.deletes).map(&:change)
41
- )
22
+ @plan = Plan.new(*calculate_changes(expected: expected, actual: actual))
23
+ validate_changes
42
24
  end
43
25
 
44
26
  def print_plan
45
- PlanDisplayer.new.display(internal_plan)
27
+ PlanPrinter.new.print(plan)
46
28
  end
47
29
 
48
30
  def confirm
49
- return false if internal_plan.empty?
31
+ return false if plan.empty?
50
32
  return true if ENV["CI"] || !Kennel.in.tty? || !Kennel.err.tty?
51
33
  Console.ask?("Execute Plan ?")
52
34
  end
@@ -54,7 +36,7 @@ module Kennel
54
36
  def update
55
37
  changes = []
56
38
 
57
- internal_plan.deletes.each do |item|
39
+ plan.deletes.each do |item|
58
40
  message = "#{item.api_resource} #{item.tracking_id} #{item.id}"
59
41
  Kennel.out.puts "Deleting #{message}"
60
42
  @api.delete item.api_resource, item.id
@@ -62,34 +44,39 @@ module Kennel
62
44
  Kennel.out.puts "#{LINE_UP}Deleted #{message}"
63
45
  end
64
46
 
65
- resolver.each_resolved internal_plan.creates do |item|
66
- message = "#{item.api_resource} #{item.tracking_id}"
67
- Kennel.out.puts "Creating #{message}"
68
- reply = @api.create item.api_resource, item.expected.as_json
69
- id = reply.fetch(:id)
70
- changes << item.change(id)
71
- resolver.add_actual [reply] # allow resolving ids we could previously not resolve
72
- Kennel.out.puts "#{LINE_UP}Created #{message} #{item.url(id)}"
73
- end
74
-
75
- resolver.each_resolved internal_plan.updates do |item|
76
- message = "#{item.api_resource} #{item.tracking_id} #{item.url}"
77
- Kennel.out.puts "Updating #{message}"
78
- @api.update item.api_resource, item.id, item.expected.as_json
79
- changes << item.change
80
- Kennel.out.puts "#{LINE_UP}Updated #{message}"
47
+ planned_actions = plan.creates + plan.updates
48
+
49
+ # slos need to be updated first in case their timeframes changed
50
+ # because datadog validates that update+create of slo alerts match an existing timeframe
51
+ planned_actions.sort_by! { |item| item.expected.is_a?(Models::Slo) ? 0 : 1 }
52
+
53
+ resolver.each_resolved(planned_actions) do |item|
54
+ if item.is_a?(Types::PlannedCreate)
55
+ message = "#{item.api_resource} #{item.tracking_id}"
56
+ Kennel.out.puts "Creating #{message}"
57
+ reply = @api.create item.api_resource, item.expected.as_json
58
+ id = reply.fetch(:id)
59
+ changes << item.change(id)
60
+ resolver.add_actual [reply] # allow resolving ids we could previously not resolve
61
+ Kennel.out.puts "#{LINE_UP}Created #{message} #{item.url(id)}"
62
+ else
63
+ message = "#{item.api_resource} #{item.tracking_id} #{item.url}"
64
+ Kennel.out.puts "Updating #{message}"
65
+ @api.update item.api_resource, item.id, item.expected.as_json
66
+ changes << item.change
67
+ Kennel.out.puts "#{LINE_UP}Updated #{message}"
68
+ end
81
69
  end
82
70
 
83
- Plan.new(changes: changes)
71
+ plan.changes = changes
72
+ plan
84
73
  end
85
74
 
86
75
  private
87
76
 
88
- attr_reader :filter, :resolver, :internal_plan
77
+ attr_reader :filter, :resolver
89
78
 
90
79
  def calculate_changes(expected:, actual:)
91
- @warnings = []
92
-
93
80
  Progress.progress "Diffing" do
94
81
  resolver.add_actual actual
95
82
  filter_actual! actual
@@ -123,7 +110,7 @@ module Kennel
123
110
  deletes.sort_by! { |item| DELETE_ORDER.index item.api_resource }
124
111
  updates.sort_by! { |item| DELETE_ORDER.index item.api_resource } # slo needs to come before slo alert
125
112
 
126
- InternalPlan.new(creates, updates, deletes)
113
+ [creates, updates, deletes]
127
114
  end
128
115
  end
129
116
 
@@ -140,15 +127,16 @@ module Kennel
140
127
  if @strict_imports
141
128
  raise "Unable to find existing #{resource} with id #{id}\nIf the #{resource} was deleted, remove the `id: -> { #{id} }` line."
142
129
  else
143
- @warnings << "#{resource} #{e.tracking_id} specifies id #{id}, but no such #{resource} exists. 'id' will be ignored. Remove the `id: -> { #{id} }` line."
130
+ message = "Warning: #{resource} #{e.tracking_id} specifies id #{id}, but no such #{resource} exists. 'id' will be ignored. Remove the `id: -> { #{id} }` line."
131
+ Kennel.err.puts Console.color(:yellow, message)
144
132
  end
145
133
  end
146
134
  end
147
135
 
148
136
  # We've already validated the desired objects ('generated') in isolation.
149
137
  # Now that we have made the plan, we can perform some more validation.
150
- def validate_changes(internal_plan)
151
- internal_plan.updates.each do |item|
138
+ def validate_changes
139
+ @plan.updates.each do |item|
152
140
  item.expected.validate_update!(item.diff)
153
141
  end
154
142
  end
@@ -17,6 +17,8 @@ module Kennel
17
17
  # check for queries that do not use the variables and would be misleading
18
18
  # TODO: do the same check for apm_query and their group_by
19
19
  def validate_json(data)
20
+ super
21
+
20
22
  variables = (data[:template_variables] || []).map { |v| "$#{v.fetch(:name)}" }
21
23
  return if variables.empty?
22
24
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.145.1"
3
+ VERSION = "1.147.0"
4
4
  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.145.1
4
+ version: 1.147.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-10-17 00:00:00.000000000 Z
11
+ date: 2023-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -113,7 +113,8 @@ files:
113
113
  - lib/kennel/subclass_tracking.rb
114
114
  - lib/kennel/syncer.rb
115
115
  - lib/kennel/syncer/matched_expected.rb
116
- - lib/kennel/syncer/plan_displayer.rb
116
+ - lib/kennel/syncer/plan.rb
117
+ - lib/kennel/syncer/plan_printer.rb
117
118
  - lib/kennel/syncer/resolver.rb
118
119
  - lib/kennel/syncer/types.rb
119
120
  - lib/kennel/tags_validation.rb