kennel 1.155.0 → 1.156.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: 52d3ae07f004122c89830d62abf500f176f764bda7848dc3bf10094632f81172
4
- data.tar.gz: c64b314848c4574326f8d485e4fe6849c53e03a7cf38871e86a2d89cf43cbd0e
3
+ metadata.gz: eef80c1b9898cbd9f3a319f686836b41d760abbdbacfd8fddfa6ac27cd4706dd
4
+ data.tar.gz: 80f119c50ac65e3d9985588f37b41961f326b62ce4e028cdc27c6b6d333a75a8
5
5
  SHA512:
6
- metadata.gz: 9e2a7327e64c318fe1ac443d5157ffd4e0a65a298b56e7a5345cc15ed2f472f09b4a4387c97599633d2357f6d9fc26317a218cfa2e48ab87c0db5a18e0365740
7
- data.tar.gz: ae76d3d79ec245ee127266a6ed402766370354a11bc78952a162e001c9bd53037620996524c2e24544d9ac3199df607aee60ff4ed72b320985e2d4fca530bfbb
6
+ metadata.gz: 4a35987012bf0ebf529107451e3304c92fcd7a2226078c5101ea02d1689c0bfed96d0fb0e0dc14a2c44a7274376fb3fb7b61029363ec3b5bdaf356d459253b11
7
+ data.tar.gz: '049fb4c8abe6fd1e107c5343e4f9138ab2b981f405ec289ccbca0e506411d8e039310d2a428f5aaa67858c84eef36a069a74932c6a2acc4686eb9b97b013acf8'
data/lib/kennel/filter.rb CHANGED
@@ -3,9 +3,9 @@
3
3
  module Kennel
4
4
  class Filter
5
5
  def initialize
6
- # build early so we fail fast on invalid user input
7
- @tracking_id_filter = build_tracking_id_filter
8
- @project_filter = build_project_filter
6
+ # read early so we fail fast on invalid user input
7
+ @tracking_id_filter = read_tracking_id_filter_from_env
8
+ @project_filter = read_project_filter_from_env
9
9
  end
10
10
 
11
11
  def filter_projects(projects)
@@ -28,30 +28,36 @@ module Kennel
28
28
  return true unless filtering?
29
29
  return tracking_id_filter.include?(tracking_id) if tracking_id_filter
30
30
 
31
- project_filter.include?(tracking_id.split(":").first)
31
+ project_id = tracking_id.split(":").first
32
+ project_filter.include?(project_id)
33
+ end
34
+
35
+ def tracking_id_for_path(tracking_id)
36
+ return tracking_id unless tracking_id.end_with?(".json")
37
+ tracking_id.sub("generated/", "").sub(".json", "").sub("/", ":")
32
38
  end
33
39
 
34
40
  private
35
41
 
36
42
  attr_reader :project_filter, :tracking_id_filter
37
43
 
38
- def build_project_filter
44
+ # needs to be called after read_tracking_id_filter_from_env
45
+ def read_project_filter_from_env
39
46
  project_names = ENV["PROJECT"]&.split(",")&.sort&.uniq
40
47
  tracking_project_names = tracking_id_filter&.map { |id| id.split(":", 2).first }&.sort&.uniq
41
48
  if project_names && tracking_project_names && project_names != tracking_project_names
42
- raise "do not set PROJECT= when using TRACKING_ID="
49
+ # avoid everything being filtered out
50
+ raise "do not set a different PROJECT= when using TRACKING_ID="
43
51
  end
44
52
  (project_names || tracking_project_names)
45
53
  end
46
54
 
47
- def build_tracking_id_filter
48
- (tracking_id = ENV["TRACKING_ID"]) && tracking_id.split(",").map { |id| tracking_id_path_conversion(id) }.sort.uniq
49
- end
50
-
51
- # allow users to paste the generated path of an objects to update it without manually converting
52
- def tracking_id_path_conversion(tracking_id)
53
- return tracking_id unless tracking_id.end_with?(".json")
54
- tracking_id.sub("generated/", "").sub(".json", "").sub("/", ":")
55
+ def read_tracking_id_filter_from_env
56
+ return unless (tracking_id = ENV["TRACKING_ID"])
57
+ tracking_id.split(",").map do |id|
58
+ # allow users to paste the generated/ path of an objects to update it without manually converting
59
+ tracking_id_for_path(id)
60
+ end.sort.uniq
55
61
  end
56
62
 
57
63
  def filter_resources(resources, by, expected, name, env)
@@ -37,9 +37,10 @@ module Kennel
37
37
  def existing_files_and_folders
38
38
  paths = Dir["generated/**/*"]
39
39
 
40
+ # when filtering we only need the files we are going to write
40
41
  if filter.filtering?
41
42
  paths.select! do |path|
42
- tracking_id = path.split("/")[1..2].to_a.join(":")
43
+ tracking_id = filter.tracking_id_for_path(path)
43
44
  filter.matches_tracking_id?(tracking_id)
44
45
  end
45
46
  end
@@ -20,21 +20,46 @@ module Kennel
20
20
  loader = Zeitwerk::Loader.new
21
21
  Dir.exist?("teams") && loader.push_dir("teams", namespace: Teams)
22
22
  Dir.exist?("parts") && loader.push_dir("parts")
23
- loader.setup
24
- loader.eager_load # TODO: this should not be needed but we see hanging CI processes when it's not added
25
23
 
26
- # TODO: also auto-load projects and update expected path too
27
- ["projects"].each do |folder|
24
+ # TODO: verify this works by running generate and also running generate for each possible PROJECT
25
+ # in isolation, then remove AUTOLOAD_PROJECTS
26
+ if ENV["AUTOLOAD_PROJECTS"]
27
+ loader.push_dir("projects")
28
+ loader.setup
29
+
30
+ if (project = ENV["PROJECT"]) # TODO: use project filter instead and also support TRACKING_ID
31
+ # we support PROJECT being used for nested folders, to allow teams to easily group their projects
32
+ # so when loading a project we need to find anything that could be a project source
33
+ # sorting by name and nesting level to avoid confusion
34
+ projects_path = "#{File.expand_path("projects")}/"
35
+ project_path = loader.all_expected_cpaths.each_key.select do |path|
36
+ path.start_with?(projects_path) && path.end_with?("/#{project}.rb")
37
+ end.sort.min_by { |p| p.count("/") }
38
+ if project_path
39
+ require project_path
40
+ else
41
+ Kennel.err.puts "No file named #{project}.rb, falling back to slow loading of all projects instead"
42
+ loader.eager_load
43
+ end
44
+ else
45
+ loader.eager_load
46
+ end
47
+ else
48
+ loader.setup
49
+ loader.eager_load # TODO: this should not be needed but we see hanging CI processes when it's not added
50
+ # TODO: also auto-load projects and update expected path too
51
+ # but to do that we need to stop the pattern of having a class at the bottom of the project structure
52
+ # and change to Module::Project + Module::Support
28
53
  # we need the extra sort so foo/bar.rb is loaded before foo/bar/baz.rb
29
- Dir["#{folder}/**/*.rb"].sort.each { |f| require "./#{f}" } # rubocop:disable Lint/RedundantDirGlobSort
54
+ Dir["projects/**/*.rb"].sort.each { |f| require "./#{f}" } # rubocop:disable Lint/RedundantDirGlobSort
30
55
  end
31
56
  rescue NameError => e
32
57
  message = e.message
33
58
  raise unless (klass = message[/uninitialized constant (.*)/, 1])
34
59
 
35
60
  # inverse of zeitwerk lib/zeitwerk/inflector.rb
36
- path = klass.gsub("::", "/").gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase + ".rb"
37
- expected_path = (path.start_with?("teams/") ? path : "parts/#{path}")
61
+ project_path = klass.gsub("::", "/").gsub(/([a-z])([A-Z])/, "\\1_\\2").downcase + ".rb"
62
+ expected_path = (project_path.start_with?("teams/") ? project_path : "parts/#{project_path}")
38
63
 
39
64
  # TODO: prefer to raise a new exception with the old backtrace attacked
40
65
  e.define_singleton_method(:message) do
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.155.0"
3
+ VERSION = "1.156.0"
4
4
  end
data/lib/kennel.rb CHANGED
@@ -106,20 +106,16 @@ module Kennel
106
106
 
107
107
  def generated(**kwargs)
108
108
  @generated ||= begin
109
- parts = Progress.progress "Finding parts", **kwargs do
109
+ projects = Progress.progress "Loading projects", **kwargs do
110
110
  projects = ProjectsProvider.new.projects
111
- projects = filter.filter_projects projects
112
-
113
- parts = Utils.parallel(projects, &:validated_parts).flatten(1)
114
- filter.filter_parts parts
111
+ filter.filter_projects projects
115
112
  end
116
113
 
117
- parts.group_by(&:tracking_id).each do |tracking_id, same|
118
- next if same.size == 1
119
- raise <<~ERROR
120
- #{tracking_id} is defined #{same.size} times
121
- use a different `kennel_id` when defining multiple projects/monitors/dashboards to avoid this conflict
122
- ERROR
114
+ parts = Progress.progress "Finding parts", **kwargs do
115
+ parts = Utils.parallel(projects, &:validated_parts).flatten(1)
116
+ parts = filter.filter_parts parts
117
+ validate_unique_tracking_ids(parts)
118
+ parts
123
119
  end
124
120
 
125
121
  Progress.progress "Building json" do
@@ -133,6 +129,17 @@ module Kennel
133
129
  end
134
130
  end
135
131
 
132
+ # performance: this takes ~100ms on large codebases, tried rewriting with Set or Hash but it was slower
133
+ def validate_unique_tracking_ids(parts)
134
+ parts.group_by(&:tracking_id).each do |tracking_id, same|
135
+ next if same.size == 1
136
+ raise <<~ERROR
137
+ #{tracking_id} is defined #{same.size} times
138
+ use a different `kennel_id` when defining multiple projects/monitors/dashboards to avoid this conflict
139
+ ERROR
140
+ end
141
+ end
142
+
136
143
  def definitions(**kwargs)
137
144
  @definitions ||= Progress.progress("Downloading definitions", **kwargs) do
138
145
  Utils.parallel(Models::Record.subclasses) do |klass|
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.155.0
4
+ version: 1.156.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: 2025-03-21 00:00:00.000000000 Z
11
+ date: 2025-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -136,14 +136,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
136
  requirements:
137
137
  - - ">="
138
138
  - !ruby/object:Gem::Version
139
- version: 3.2.0
139
+ version: 3.3.0
140
140
  required_rubygems_version: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - ">="
143
143
  - !ruby/object:Gem::Version
144
144
  version: '0'
145
145
  requirements: []
146
- rubygems_version: 3.4.10
146
+ rubygems_version: 3.5.22
147
147
  signing_key:
148
148
  specification_version: 4
149
149
  summary: Keep datadog monitors/dashboards/etc in version control, avoid chaotic management