kennel 1.115.0 → 1.116.2

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: 76e2802df7ab2a6583e3529643deb08c382367dea7f90a7253314959d29a5bec
4
- data.tar.gz: 4249c23ca2892cc48ce72dbd9e24fc03f38883d6eaed9b509ef75c78cb31afeb
3
+ metadata.gz: 67342a80e2cd8dd1f0f2ad613cca326405bff85975ceb4253bc6180c856b03cc
4
+ data.tar.gz: 587fb9a0ca21bf084e71c496c411708cc132aa80f2f7ec3c34f56b5a3b1888b4
5
5
  SHA512:
6
- metadata.gz: 8bd1740361932ba4e6dfe4d7aff4ad7cbcdc96796020428902fc6551b9768c6ccc434a279c214a638aa119e012267fd8dfe00e9107052c570789a1e563075505
7
- data.tar.gz: 266aacb034b8933640c3e95a0319afd5fdc923c857d85a5b039e4e14a2bb47dc1096e8849a1d3060171fed2984d847934465ed845a1e45d27caa465c5ca9fcf4
6
+ metadata.gz: 89fb1183eb9ee4db1f0a138c342a79b9f6f5b1aab962090e8f5e83d0e1c7fcbd38486106cbfd506e7da33a747a0391b3a0944c214efeffbe3a5f1854cc0d0fc4
7
+ data.tar.gz: 4b5de65ad6957b45309e8e1158c0a23ac7fb95242a264d2f292f74d156481a23af5737d13236f7761664954c1f77471d6327a2febf30d5489361b0a4988545f2
data/Readme.md CHANGED
@@ -289,23 +289,27 @@ Remove the code that created the resource. The next update will delete it (see a
289
289
  ```
290
290
 
291
291
  ### Updating existing resources with id
292
-
293
292
  Setting `id` makes kennel take over a manually created datadog resource.
294
293
  When manually creating to import, it is best to remove the `id` and delete the manually created resource.
295
294
 
296
295
  When an `id` is set and the original resource is deleted, kennel will fail to update,
297
296
  removing the `id` will cause kennel to create a new resource in datadog.
298
297
 
299
- ### Organizing many projects
300
- Having many projects (and their sub-resources) can quickly get out of hand.
298
+ ### Organizing projects with many resources
299
+ When project files get too long, this structure can keep things bite-sized.
301
300
 
302
- Use this class structure to keep things organized:
303
301
  ```Ruby
304
302
  # projects/project_a/base.rb
305
303
  module ProjectA
306
304
  class Base < Kennel::Models::Project
307
305
  defaults(
308
306
  kennel_id: -> { "project_a" },
307
+ parts: -> {
308
+ [
309
+ Monitors::FooAlert.new(self),
310
+ ...
311
+ ]
312
+ }
309
313
  ...
310
314
 
311
315
  # projects/project_a/monitors/foo_alert.rb
@@ -315,7 +319,16 @@ module ProjectA
315
319
  ...
316
320
  ```
317
321
 
318
- On the command line, use the projects `kennel_id` (and if none is set then snake_case of the class name) to refer to the project. For example here`PROJECT=project_a` but if it were `Foo::ProjectA` then `foo_project_a`.
322
+ ### Updating a single project or resource
323
+
324
+ - Use `PROJECT=<kennel_id>` for single project:
325
+
326
+ Use the projects `kennel_id` (and if none is set then snake_case of the class name including modules)
327
+ to refer to the project. For example for `class ProjectA` use `PROJECT=project_a` but for `Foo::ProjectA` use `foo_project_a`.
328
+
329
+ - Use `TRACKING_ID=<project-kennel_id>:<resource-kennel_id>` for single resource:
330
+
331
+ Use the project kennel_id and the resources kennel_id, for example `class ProjectA` and `FooAlert` would give `project_a:foo_alert`.
319
332
 
320
333
  ### Skipping validations
321
334
  Some validations might be too strict for your usecase or just wrong, please [open an issue](https://github.com/grosser/kennel/issues) and
@@ -7,12 +7,12 @@ module Kennel
7
7
  def self.progress(name)
8
8
  Kennel.err.print "#{name} ... "
9
9
 
10
- animation = "-\\|/"
11
- count = 0
12
10
  stop = false
13
11
  result = nil
14
12
 
15
13
  spinner = Thread.new do
14
+ animation = "-\\|/"
15
+ count = 0
16
16
  loop do
17
17
  break if stop
18
18
  Kennel.err.print animation[count % animation.size]
@@ -30,7 +30,7 @@ module Kennel
30
30
 
31
31
  result
32
32
  ensure
33
- stop = true
33
+ stop = true # make thread stop without killing it
34
34
  end
35
35
  end
36
36
  end
data/lib/kennel/syncer.rb CHANGED
@@ -4,9 +4,10 @@ module Kennel
4
4
  DELETE_ORDER = ["dashboard", "slo", "monitor", "synthetics/tests"].freeze # dashboards references monitors + slos, slos reference monitors
5
5
  LINE_UP = "\e[1A\033[K" # go up and clear
6
6
 
7
- def initialize(api, expected, project_filter: nil)
7
+ def initialize(api, expected, project_filter: nil, tracking_id_filter: nil)
8
8
  @api = api
9
9
  @project_filter = project_filter
10
+ @tracking_id_filter = tracking_id_filter
10
11
  @expected = Set.new expected # need set to speed up deletion
11
12
  calculate_diff
12
13
  validate_plan
@@ -105,7 +106,7 @@ module Kennel
105
106
 
106
107
  Progress.progress "Diffing" do
107
108
  populate_id_map @expected, actual
108
- filter_actual_by_project! actual
109
+ filter_actual! actual
109
110
  resolve_linked_tracking_ids! @expected # resolve dependencies to avoid diff
110
111
 
111
112
  @expected.each(&:add_tracking_id) # avoid diff with actual
@@ -261,11 +262,12 @@ module Kennel
261
262
  next unless tracking_id = a.fetch(:tracking_id)
262
263
 
263
264
  # ignore when deleted from the codebase
264
- # (when running with project filter we cannot see the other resources in the codebase)
265
+ # (when running with filters we cannot see the other resources in the codebase)
265
266
  api_resource = a.fetch(:klass).api_resource
266
267
  next if
267
268
  !@id_map.get(api_resource, tracking_id) &&
268
- (!project_prefixes || tracking_id.start_with?(*project_prefixes))
269
+ (!project_prefixes || tracking_id.start_with?(*project_prefixes)) &&
270
+ (!@tracking_id_filter || @tracking_id_filter.include?(tracking_id))
269
271
 
270
272
  @id_map.set(api_resource, tracking_id, a.fetch(:id))
271
273
  if a[:klass].api_resource == "synthetics/tests"
@@ -278,12 +280,18 @@ module Kennel
278
280
  list.each { |e| e.resolve_linked_tracking_ids!(@id_map, force: force) }
279
281
  end
280
282
 
281
- def filter_actual_by_project!(actual)
282
- return unless @project_filter
283
- project_prefixes = @project_filter&.map { |p| "#{p}:" }
284
- actual.select! do |a|
285
- tracking_id = a.fetch(:tracking_id)
286
- !tracking_id || tracking_id.start_with?(*project_prefixes)
283
+ def filter_actual!(actual)
284
+ if @tracking_id_filter
285
+ actual.select! do |a|
286
+ tracking_id = a.fetch(:tracking_id)
287
+ !tracking_id || @tracking_id_filter.include?(tracking_id)
288
+ end
289
+ elsif @project_filter
290
+ project_prefixes = @project_filter.map { |p| "#{p}:" }
291
+ actual.select! do |a|
292
+ tracking_id = a.fetch(:tracking_id)
293
+ !tracking_id || tracking_id.start_with?(*project_prefixes)
294
+ end
287
295
  end
288
296
  end
289
297
  end
data/lib/kennel/utils.rb CHANGED
@@ -113,7 +113,7 @@ module Kennel
113
113
  done[i] =
114
114
  begin
115
115
  yield item
116
- rescue StandardError => e
116
+ rescue Exception => e # rubocop:disable Lint/RescueException
117
117
  work.clear
118
118
  e
119
119
  end
@@ -121,7 +121,7 @@ module Kennel
121
121
  end
122
122
  end
123
123
  workers.each(&:join)
124
- done.each { |d| raise d if d.is_a?(StandardError) }
124
+ done.each { |d| raise d if d.is_a?(Exception) }
125
125
  end
126
126
 
127
127
  def natural_order(name)
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.115.0"
3
+ VERSION = "1.116.2"
4
4
  end
data/lib/kennel.rb CHANGED
@@ -65,13 +65,22 @@ module Kennel
65
65
 
66
66
  def store(parts)
67
67
  Progress.progress "Storing" do
68
- old = Dir["generated/{#{(project_filter || ["**"]).join(",")}}/*"]
68
+ old = Dir[[
69
+ "generated",
70
+ if project_filter || tracking_id_filter
71
+ [
72
+ "{" + (project_filter || ["*"]).join(",") + "}",
73
+ "{" + (tracking_id_filter || ["*"]).join(",") + "}.json"
74
+ ]
75
+ else
76
+ "**"
77
+ end
78
+ ].join("/")]
69
79
  used = []
70
80
 
71
81
  Utils.parallel(parts, max: 2) do |part|
72
82
  path = "generated/#{part.tracking_id.tr("/", ":").sub(":", "/")}.json"
73
- used << File.dirname(path) # only 1 level of sub folders, so this is safe
74
- used << path
83
+ used.concat [File.dirname(path), path] # only 1 level of sub folders, so this is safe
75
84
  payload = part.as_json.merge(api_resource: part.class.api_resource)
76
85
  write_file_if_necessary(path, JSON.pretty_generate(payload) << "\n")
77
86
  end
@@ -94,7 +103,7 @@ module Kennel
94
103
  end
95
104
 
96
105
  def syncer
97
- @syncer ||= Syncer.new(api, generated, project_filter: project_filter)
106
+ @syncer ||= Syncer.new(api, generated, project_filter: project_filter, tracking_id_filter: tracking_id_filter)
98
107
  end
99
108
 
100
109
  def api
@@ -105,22 +114,12 @@ module Kennel
105
114
  @generated ||= begin
106
115
  Progress.progress "Generating" do
107
116
  load_all
108
- known = []
109
- filter = project_filter
110
-
111
- parts = Utils.parallel(Models::Project.recursive_subclasses) do |project_class|
112
- project = project_class.new
113
- kennel_id = project.kennel_id
114
- if filter
115
- known << kennel_id
116
- next [] unless filter.include?(kennel_id)
117
- end
118
- project.validated_parts
119
- end.flatten(1)
120
-
121
- if filter && parts.empty?
122
- raise "#{filter.join(", ")} does not match any projects, try any of these:\n#{known.uniq.sort.join("\n")}"
123
- end
117
+
118
+ projects = Models::Project.recursive_subclasses.map(&:new)
119
+ filter_resources!(projects, :kennel_id, project_filter, "projects", "PROJECT")
120
+
121
+ parts = Utils.parallel(projects, &:validated_parts).flatten(1)
122
+ filter_resources!(parts, :tracking_id, tracking_id_filter, "resources", "TRACKING_ID")
124
123
 
125
124
  parts.group_by(&:tracking_id).each do |tracking_id, same|
126
125
  next if same.size == 1
@@ -139,7 +138,29 @@ module Kennel
139
138
  end
140
139
 
141
140
  def project_filter
142
- ENV["PROJECT"]&.split(",")
141
+ projects = ENV["PROJECT"]&.split(",")
142
+ tracking_projects = tracking_id_filter&.map { |id| id.split(":", 2).first }
143
+ if projects && tracking_projects && projects != tracking_projects
144
+ raise "do not set PROJECT= when using TRACKING_ID="
145
+ end
146
+ projects || tracking_projects
147
+ end
148
+
149
+ def tracking_id_filter
150
+ (tracking_id = ENV["TRACKING_ID"]) && tracking_id.split(",")
151
+ end
152
+
153
+ def filter_resources!(resources, by, against, name, env)
154
+ return unless against
155
+
156
+ before = resources.dup
157
+ resources.select! { |p| against.include?(p.send(by)) }
158
+ return if resources.size == against.size
159
+
160
+ raise <<~MSG.rstrip
161
+ #{env}=#{against.join(",")} matched #{resources.size} #{name}, try any of these:
162
+ #{before.map(&by).sort.uniq.join("\n")}
163
+ MSG
143
164
  end
144
165
 
145
166
  def load_all
@@ -147,8 +168,9 @@ module Kennel
147
168
  Dir.exist?("teams") && loader.push_dir("teams", namespace: Teams)
148
169
  Dir.exist?("parts") && loader.push_dir("parts")
149
170
  loader.setup
171
+ loader.eager_load # TODO: this should not be needed but we see hanging CI processes when it's not added
150
172
 
151
- # TODO: also do projects and update expected path too
173
+ # TODO: also auto-load projects and update expected path too
152
174
  ["projects"].each do |folder|
153
175
  Dir["#{folder}/**/*.rb"].sort.each { |f| require "./#{f}" }
154
176
  end
data/template/Readme.md CHANGED
@@ -271,23 +271,27 @@ Remove the code that created the resource. The next update will delete it (see a
271
271
  ```
272
272
 
273
273
  ### Updating existing resources with id
274
-
275
274
  Setting `id` makes kennel take over a manually created datadog resource.
276
275
  When manually creating to import, it is best to remove the `id` and delete the manually created resource.
277
276
 
278
277
  When an `id` is set and the original resource is deleted, kennel will fail to update,
279
278
  removing the `id` will cause kennel to create a new resource in datadog.
280
279
 
281
- ### Organizing many projects
282
- Having many projects (and their sub-resources) can quickly get out of hand.
280
+ ### Organizing projects with many resources
281
+ When project files get too long, this structure can keep things bite-sized.
283
282
 
284
- Use this class structure to keep things organized:
285
283
  ```Ruby
286
284
  # projects/project_a/base.rb
287
285
  module ProjectA
288
286
  class Base < Kennel::Models::Project
289
287
  defaults(
290
288
  kennel_id: -> { "project_a" },
289
+ parts: -> {
290
+ [
291
+ Monitors::FooAlert.new(self),
292
+ ...
293
+ ]
294
+ }
291
295
  ...
292
296
 
293
297
  # projects/project_a/monitors/foo_alert.rb
@@ -297,7 +301,16 @@ module ProjectA
297
301
  ...
298
302
  ```
299
303
 
300
- On the command line, use the projects `kennel_id` (and if none is set then snake_case of the class name) to refer to the project. For example here`PROJECT=project_a` but if it were `Foo::ProjectA` then `foo_project_a`.
304
+ ### Updating a single project or resource
305
+
306
+ - Use `PROJECT=<kennel_id>` for single project:
307
+
308
+ Use the projects `kennel_id` (and if none is set then snake_case of the class name including modules)
309
+ to refer to the project. For example for `class ProjectA` use `PROJECT=project_a` but for `Foo::ProjectA` use `foo_project_a`.
310
+
311
+ - Use `TRACKING_ID=<project-kennel_id>:<resource-kennel_id>` for single resource:
312
+
313
+ Use the project kennel_id and the resources kennel_id, for example `class ProjectA` and `FooAlert` would give `project_a:foo_alert`.
301
314
 
302
315
  ### Skipping validations
303
316
  Some validations might be too strict for your usecase or just wrong, please [open an issue](https://github.com/grosser/kennel/issues) and
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.115.0
4
+ version: 1.116.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-28 00:00:00.000000000 Z
11
+ date: 2022-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday