datadog-ci 1.23.2 → 1.24.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: 660ce0996ea0998e1074ca1f3671b00b74659b31520486c0fec7f850cf619c40
4
- data.tar.gz: b3fa584967668ee53d4f66b9c4963236b1fbe58367f4833bf1436064a5112773
3
+ metadata.gz: 30bc86afa5d05d656f9abfa7ffb5ff21d6f9a8fc5edeb5924651de4cdc6df10d
4
+ data.tar.gz: c846a97a47a74120d9926350360cefa4ca3fcdadea6819337ad2990f7856e267
5
5
  SHA512:
6
- metadata.gz: 8c99eab8f2b7f6367627746f94cb1338e77000791f89a96767f23572c43d13d96384b7f9b85c494d64bbef34dbbc0659123b31df14976a1de973075ce7bcb657
7
- data.tar.gz: 5eab6749fe723823f6bcade1f946e9669924b3299219b7a9e67c1db1b8ac12483ffb910aedbd4be145839dd7a17ac0527d95ec36358cd2f2cee82387b6d136b9
6
+ metadata.gz: 2e2a5b3efa12f1c64176e1751e86ebf803f8c894aba7c53453abb22732e0ed16a6087292538b2e03f0657dc9433ceba9e452f5899a95ace325a004ee12c37fbc
7
+ data.tar.gz: 461912b9cb9f406c4fd1cb9975ece506df7e979ed7b373b46c9e0060977f397b2da63095be353351d74b4273ea3cc1a354c12a4ef9dc7bf75a0a5ed065a16fa3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.24.0] - 2025-12-15
4
+
5
+ ### Added
6
+ * Create final status tag on test events ([#433][])
7
+
8
+ ### Changed
9
+ * Add `branch` parameter to `/test-management/tests` request ([#436][])
10
+
11
+ ### Fixed
12
+ * Fix an inheritance blind spot for Test Impact Analysis ([#440][])
13
+
14
+ ## [1.23.3] - 2025-11-19
15
+
16
+ ### Fixed
17
+
18
+ * Fix nil error for test discovery component by introducing NullObject pattern for all components of Datadog Test Optimization ([#430][])
19
+
3
20
  ## [1.23.2] - 2025-11-18
4
21
 
5
22
  ### Added
@@ -548,7 +565,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
548
565
 
549
566
  - Ruby versions < 2.7 no longer supported ([#8][])
550
567
 
551
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.23.2...main
568
+ [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.24.0...main
569
+ [1.24.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.23.3...v1.24.0
570
+ [1.23.3]: https://github.com/DataDog/datadog-ci-rb/compare/v1.23.2...v1.23.3
552
571
  [1.23.2]: https://github.com/DataDog/datadog-ci-rb/compare/v1.23.1...v1.23.2
553
572
  [1.23.1]: https://github.com/DataDog/datadog-ci-rb/compare/v1.23.0...v1.23.1
554
573
  [1.23.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.22.1...v1.23.0
@@ -778,4 +797,8 @@ Currently test suite level visibility is not used by our instrumentation: it wil
778
797
  [#414]: https://github.com/DataDog/datadog-ci-rb/issues/414
779
798
  [#416]: https://github.com/DataDog/datadog-ci-rb/issues/416
780
799
  [#418]: https://github.com/DataDog/datadog-ci-rb/issues/418
781
- [#425]: https://github.com/DataDog/datadog-ci-rb/issues/425
800
+ [#425]: https://github.com/DataDog/datadog-ci-rb/issues/425
801
+ [#430]: https://github.com/DataDog/datadog-ci-rb/issues/430
802
+ [#433]: https://github.com/DataDog/datadog-ci-rb/issues/433
803
+ [#436]: https://github.com/DataDog/datadog-ci-rb/issues/436
804
+ [#440]: https://github.com/DataDog/datadog-ci-rb/issues/440
@@ -156,12 +156,12 @@ static VALUE dd_cov_allocate(VALUE klass) {
156
156
 
157
157
  // Checks if the filename is located under the root folder of the project (but
158
158
  // not in the ignored folder) and adds it to the impacted_files hash.
159
- static void record_impacted_file(struct dd_cov_data *dd_cov_data,
159
+ static bool record_impacted_file(struct dd_cov_data *dd_cov_data,
160
160
  VALUE filename) {
161
161
  char *filename_ptr = RSTRING_PTR(filename);
162
162
  // if the current filename is not located under the root, we skip it
163
163
  if (strncmp(dd_cov_data->root, filename_ptr, dd_cov_data->root_len) != 0) {
164
- return;
164
+ return false;
165
165
  }
166
166
 
167
167
  // if ignored_path is provided and the current filename is located under the
@@ -170,10 +170,11 @@ static void record_impacted_file(struct dd_cov_data *dd_cov_data,
170
170
  if (dd_cov_data->ignored_path_len != 0 &&
171
171
  strncmp(dd_cov_data->ignored_path, filename_ptr,
172
172
  dd_cov_data->ignored_path_len) == 0) {
173
- return;
173
+ return false;
174
174
  }
175
175
 
176
176
  rb_hash_aset(dd_cov_data->impacted_files, filename, Qtrue);
177
+ return true;
177
178
  }
178
179
 
179
180
  // Executed on RUBY_EVENT_LINE event and captures the filename from
@@ -221,29 +222,61 @@ static VALUE safely_get_source_location(VALUE klass_name) {
221
222
  return rescue_nil(get_source_location, klass_name);
222
223
  }
223
224
 
224
- // This function is called for each class that was instantiated during the test
225
- // run.
226
- static int process_instantiated_klass(st_data_t key, st_data_t _value,
227
- st_data_t data) {
228
- VALUE klass = (VALUE)key;
229
- struct dd_cov_data *dd_cov_data = (struct dd_cov_data *)data;
225
+ // Safely get class name, returns Qnil on any error
226
+ static VALUE safely_get_class_name(VALUE klass) {
227
+ return rescue_nil(rb_class_name, klass);
228
+ }
230
229
 
231
- VALUE klass_name = rb_class_name(klass);
230
+ // Safely get module ancestors, returns Qnil on any error
231
+ static VALUE safely_get_mod_ancestors(VALUE klass) {
232
+ return rescue_nil(rb_mod_ancestors, klass);
233
+ }
234
+
235
+ static bool record_impacted_klass(struct dd_cov_data *dd_cov_data,
236
+ VALUE klass) {
237
+ VALUE klass_name = safely_get_class_name(klass);
232
238
  if (klass_name == Qnil) {
233
- return ST_CONTINUE;
239
+ return false;
234
240
  }
235
241
 
236
242
  VALUE source_location = safely_get_source_location(klass_name);
237
- if (source_location == Qnil || RARRAY_LEN(source_location) == 0) {
238
- return ST_CONTINUE;
243
+ if (source_location == Qnil || !RB_TYPE_P(source_location, T_ARRAY) ||
244
+ RARRAY_LEN(source_location) == 0) {
245
+ return false;
239
246
  }
240
247
 
241
248
  VALUE filename = RARRAY_AREF(source_location, 0);
242
249
  if (filename == Qnil || !RB_TYPE_P(filename, T_STRING)) {
250
+ return false;
251
+ }
252
+
253
+ return record_impacted_file(dd_cov_data, filename);
254
+ }
255
+
256
+ // This function is called for each class that was instantiated during the test
257
+ // run.
258
+ static int each_instantiated_klass(st_data_t key, st_data_t _value,
259
+ st_data_t data) {
260
+ VALUE klass = (VALUE)key;
261
+ struct dd_cov_data *dd_cov_data = (struct dd_cov_data *)data;
262
+
263
+ // rb_mod_ancestors returns an array containing the "klass" itself
264
+ // and all the parent classes and/or included/prepended modules
265
+ VALUE ancestors = safely_get_mod_ancestors(klass);
266
+ if (ancestors == Qnil || !RB_TYPE_P(ancestors, T_ARRAY)) {
243
267
  return ST_CONTINUE;
244
268
  }
245
269
 
246
- record_impacted_file(dd_cov_data, filename);
270
+ long len = RARRAY_LEN(ancestors);
271
+ for (long i = 0; i < len; i++) {
272
+ VALUE mod = rb_ary_entry(ancestors, i);
273
+ if (mod == Qnil) {
274
+ continue;
275
+ }
276
+
277
+ record_impacted_klass(dd_cov_data, mod);
278
+ }
279
+
247
280
  return ST_CONTINUE;
248
281
  }
249
282
 
@@ -385,7 +418,7 @@ static VALUE dd_cov_stop(VALUE self) {
385
418
  }
386
419
 
387
420
  // process classes covered by allocation tracing
388
- st_foreach(dd_cov_data->klasses_table, process_instantiated_klass,
421
+ st_foreach(dd_cov_data->klasses_table, each_instantiated_klass,
389
422
  (st_data_t)dd_cov_data);
390
423
  st_clear(dd_cov_data->klasses_table);
391
424
 
@@ -5,18 +5,22 @@ require "datadog/core/telemetry/ext"
5
5
  require_relative "../ext/settings"
6
6
  require_relative "../git/tree_uploader"
7
7
  require_relative "../impacted_tests_detection/component"
8
+ require_relative "../impacted_tests_detection/null_component"
8
9
  require_relative "../logs/component"
9
10
  require_relative "../logs/transport"
11
+ require_relative "../remote/null_component"
10
12
  require_relative "../remote/component"
11
13
  require_relative "../remote/library_settings_client"
12
14
  require_relative "../test_management/component"
13
15
  require_relative "../test_management/null_component"
14
16
  require_relative "../test_management/tests_properties"
17
+ require_relative "../test_optimisation/null_component"
15
18
  require_relative "../test_optimisation/component"
16
19
  require_relative "../test_optimisation/coverage/transport"
17
20
  require_relative "../test_retries/component"
18
21
  require_relative "../test_retries/null_component"
19
22
  require_relative "../test_discovery/component"
23
+ require_relative "../test_discovery/null_component"
20
24
  require_relative "../test_visibility/component"
21
25
  require_relative "../test_visibility/flush"
22
26
  require_relative "../test_visibility/known_tests"
@@ -41,14 +45,14 @@ module Datadog
41
45
  :test_management, :agentless_logs_submission, :impacted_tests_detection, :test_discovery
42
46
 
43
47
  def initialize(settings)
44
- @test_optimisation = nil
48
+ @test_optimisation = TestOptimisation::NullComponent.new
45
49
  @test_visibility = TestVisibility::NullComponent.new
46
50
  @git_tree_upload_worker = DummyWorker.new
47
- @ci_remote = nil
51
+ @ci_remote = Remote::NullComponent.new
48
52
  @test_retries = TestRetries::NullComponent.new
49
53
  @test_management = TestManagement::NullComponent.new
50
- @impacted_tests_detection = nil
51
- @test_discovery = nil
54
+ @impacted_tests_detection = ImpactedTestsDetection::NullComponent.new
55
+ @test_discovery = TestDiscovery::NullComponent.new
52
56
 
53
57
  # Activate CI mode if enabled
54
58
  if settings.ci.enabled
@@ -18,8 +18,10 @@ module Datadog
18
18
  def run_specs(*args)
19
19
  return super unless datadog_configuration[:enabled]
20
20
 
21
- if test_discovery_component.enabled?
22
- discover_tests
21
+ discovery_component = test_discovery_component
22
+
23
+ if discovery_component&.enabled?
24
+ discover_tests(discovery_component)
23
25
 
24
26
  # don't run the tests, we just needed to discover them and now we can return
25
27
  return
@@ -74,15 +76,15 @@ module Datadog
74
76
  Datadog.send(:components).test_discovery
75
77
  end
76
78
 
77
- def discover_tests
78
- test_discovery_component.start
79
+ def discover_tests(component)
80
+ component.start
79
81
 
80
82
  examples = ::RSpec.world.all_examples
81
83
 
82
84
  examples.each do |example|
83
85
  next if example.metadata[:skip]
84
86
 
85
- test_discovery_component.record_test(
87
+ component.record_test(
86
88
  name: example.datadog_test_name,
87
89
  suite: example.datadog_test_suite_name,
88
90
  parameters: example.datadog_test_parameters,
@@ -91,7 +93,7 @@ module Datadog
91
93
  )
92
94
  end
93
95
 
94
- test_discovery_component.finish
96
+ component.finish
95
97
  end
96
98
  end
97
99
  end
@@ -13,7 +13,21 @@ module Datadog
13
13
  TAG_FRAMEWORK_VERSION = "test.framework_version"
14
14
  TAG_NAME = "test.name"
15
15
  TAG_SKIP_REASON = "test.skip_reason"
16
+
17
+ # Status is the result of a single test run
18
+ # See the [Datadog::CI::Ext::Test::Status] module for the list of possible values of this tag
16
19
  TAG_STATUS = "test.status"
20
+ # Final status is the result that Datadog reports after all retries for a given test. It might be different
21
+ # from the status of the given test run:
22
+ #
23
+ # Example: new test was retried 10 times by Early Flake Detection. It succeeded 9 times and failed once.
24
+ # The final status will be "pass" because we keep CI green for flaky tests.
25
+ #
26
+ # This tag is useful to create monitors on hard failures: if test.final_status is "fail", then CI is red.
27
+ #
28
+ # See the [Datadog::CI::Ext::Test::Status] module for the list of possible values of this tag
29
+ TAG_FINAL_STATUS = "test.final_status"
30
+
17
31
  TAG_SUITE = "test.suite"
18
32
  TAG_MODULE = "test.module"
19
33
  TAG_TYPE = "test.type"
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module ImpactedTestsDetection
6
+ # Null object used when impacted tests detection is unavailable
7
+ class NullComponent
8
+ def configure(_library_settings = nil, _test_session = nil)
9
+ end
10
+
11
+ def enabled?
12
+ false
13
+ end
14
+
15
+ def modified?(_test_span)
16
+ false
17
+ end
18
+
19
+ def tag_modified_test(_test_span)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Remote
6
+ # No-op implementation used when remote configuration is disabled.
7
+ class NullComponent
8
+ def configure(_test_session)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -244,6 +244,32 @@ module Datadog
244
244
  get_tag(Ext::Test::TAG_ITR_SKIPPED_BY_ITR) == "true"
245
245
  end
246
246
 
247
+ # @internal
248
+ def record_final_status
249
+ status = get_tag(Ext::Test::TAG_STATUS)
250
+ return if status.nil?
251
+
252
+ if [Ext::Test::Status::PASS, Ext::Test::Status::SKIP].include?(status)
253
+ set_tag(Ext::Test::TAG_FINAL_STATUS, status)
254
+ return
255
+ end
256
+
257
+ if should_ignore_failures?
258
+ set_tag(Ext::Test::TAG_FINAL_STATUS, Ext::Test::Status::PASS)
259
+ else
260
+ set_tag(Ext::Test::TAG_FINAL_STATUS, Ext::Test::Status::FAIL)
261
+ end
262
+ end
263
+
264
+ # @internal
265
+ def peek_duration
266
+ end_time = Core::Utils::Time.now.utc
267
+ start_time = tracer_span.start_time
268
+
269
+ return 0.0 if start_time.nil? || end_time.nil?
270
+ end_time - start_time
271
+ end
272
+
247
273
  private
248
274
 
249
275
  def record_test_result(datadog_status)
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module TestDiscovery
6
+ # Null object used when test discovery component is unavailable
7
+ class NullComponent
8
+ def configure(_library_settings = nil, _test_session = nil)
9
+ end
10
+
11
+ def disable_features_for_test_discovery!(_settings = nil)
12
+ end
13
+
14
+ def start
15
+ end
16
+
17
+ def finish
18
+ end
19
+
20
+ def record_test(name:, suite:, module_name:, parameters:, source_file:)
21
+ end
22
+
23
+ def shutdown!
24
+ end
25
+
26
+ def enabled?
27
+ false
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -127,7 +127,8 @@ module Datadog
127
127
  "attributes" => {
128
128
  "repository_url" => test_session.git_repository_url,
129
129
  "commit_message" => test_session.original_git_commit_message,
130
- "sha" => test_session.original_git_commit_sha
130
+ "sha" => test_session.original_git_commit_sha,
131
+ "branch" => test_session.git_branch
131
132
  }
132
133
  }
133
134
  }.to_json
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ module Datadog
6
+ module CI
7
+ module TestOptimisation
8
+ # No-op implementation used when test optimisation is disabled.
9
+ class NullComponent
10
+ attr_reader :enabled, :skippable_tests_fetch_error, :test_skipping_enabled,
11
+ :code_coverage_enabled, :skippable_tests, :correlation_id
12
+
13
+ def initialize
14
+ @enabled = false
15
+ @test_skipping_enabled = false
16
+ @code_coverage_enabled = false
17
+ @skippable_tests_fetch_error = nil
18
+ @skippable_tests = Set.new
19
+ @correlation_id = nil
20
+ end
21
+
22
+ def configure(_remote_configuration = nil, _test_session = nil)
23
+ end
24
+
25
+ def enabled?
26
+ false
27
+ end
28
+
29
+ def skipping_tests?
30
+ false
31
+ end
32
+
33
+ def code_coverage?
34
+ false
35
+ end
36
+
37
+ def start_coverage(_test)
38
+ end
39
+
40
+ def stop_coverage(_test)
41
+ nil
42
+ end
43
+
44
+ def mark_if_skippable(_test)
45
+ end
46
+
47
+ def skippable?(_datadog_test_id)
48
+ false
49
+ end
50
+
51
+ def on_test_finished(_test, _context)
52
+ end
53
+
54
+ def write_test_session_tags(_test_session, _skipped_tests_count)
55
+ end
56
+
57
+ def skippable_tests_count
58
+ 0
59
+ end
60
+
61
+ def shutdown!
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -94,18 +94,27 @@ module Datadog
94
94
 
95
95
  def record_test_finished(test_span)
96
96
  if current_retry_driver.nil?
97
- # we always run test at least once and after the first pass create a correct retry driver
97
+ # We always run test at least once and after the first pass create a correct retry driver
98
98
  self.current_retry_driver = build_driver(test_span)
99
99
  else
100
- # after each retry we record the result, the driver will decide if we should retry again
100
+ # After each retry we let the driver to record the result.
101
+ # Then the driver will decide if we should retry again.
101
102
  current_retry_driver&.record_retry(test_span)
102
103
 
104
+ # We know that the test was already retried at least once so if we should not retry anymore, then this
105
+ # is the last retry.
103
106
  tag_last_retry(test_span) unless should_retry?
104
107
  end
105
- end
106
108
 
107
- def record_test_span_duration(tracer_span)
108
- current_retry_driver&.record_duration(tracer_span.duration)
109
+ # Some retry strategies such as Early Flake Detection change the number of retries based on
110
+ # how long the test was.
111
+ current_retry_driver&.record_duration(test_span.peek_duration)
112
+
113
+ # We need to set the final status of the test (what will be reported to the test framework) on the last execution
114
+ # no matter if test was retried or not
115
+ #
116
+ # If we should not retry at this point, it means that this execution is the last one (it might the only one as well).
117
+ test_span.record_final_status unless should_retry?
109
118
  end
110
119
 
111
120
  # this API is targeted on Cucumber instrumentation or any other that cannot leverage #with_retries method
@@ -121,8 +121,6 @@ module Datadog
121
121
 
122
122
  if block
123
123
  @context.trace_test(test_name, test_suite, service: service, tags: tags) do |test|
124
- subscribe_to_after_stop_event(test.tracer_span)
125
-
126
124
  on_test_started(test)
127
125
  res = block.call(test)
128
126
  on_test_finished(test)
@@ -130,7 +128,6 @@ module Datadog
130
128
  end
131
129
  else
132
130
  test = @context.trace_test(test_name, test_suite, service: service, tags: tags)
133
- subscribe_to_after_stop_event(test.tracer_span)
134
131
  on_test_started(test)
135
132
  test
136
133
  end
@@ -340,10 +337,6 @@ module Datadog
340
337
  Telemetry.event_finished(test)
341
338
  end
342
339
 
343
- def on_after_test_span_finished(tracer_span)
344
- test_retries.record_test_span_duration(tracer_span)
345
- end
346
-
347
340
  # HELPERS
348
341
  def single_active_test_suite
349
342
  # when fetching test_suite to use as test's context, try local context instance first
@@ -357,14 +350,6 @@ module Datadog
357
350
  block&.call(nil)
358
351
  end
359
352
 
360
- def subscribe_to_after_stop_event(tracer_span)
361
- events = tracer_span.send(:events)
362
-
363
- events.after_stop.subscribe do |span|
364
- on_after_test_span_finished(span)
365
- end
366
- end
367
-
368
353
  def set_codeowners(span)
369
354
  source = span.source_file
370
355
  owners = @codeowners.list_owners(source) if source
@@ -4,8 +4,8 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = 1
7
- MINOR = 23
8
- PATCH = 2
7
+ MINOR = 24
8
+ PATCH = 0
9
9
  PRE = nil
10
10
  BUILD = nil
11
11
  # PRE and BUILD above are modified for dev gems during gem build GHA workflow
@@ -22,7 +22,7 @@ module Datadog
22
22
  # To allow testing with the next unreleased version of Ruby, the version check is performed
23
23
  # as `< #{MAXIMUM_RUBY_VERSION}`, meaning prereleases of MAXIMUM_RUBY_VERSION are allowed
24
24
  # but not stable MAXIMUM_RUBY_VERSION releases.
25
- MAXIMUM_RUBY_VERSION = "3.5"
25
+ MAXIMUM_RUBY_VERSION = "4.0"
26
26
  end
27
27
  end
28
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog-ci
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.23.2
4
+ version: 1.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
@@ -211,6 +211,7 @@ files:
211
211
  - lib/datadog/ci/git/upload_packfile.rb
212
212
  - lib/datadog/ci/git/user.rb
213
213
  - lib/datadog/ci/impacted_tests_detection/component.rb
214
+ - lib/datadog/ci/impacted_tests_detection/null_component.rb
214
215
  - lib/datadog/ci/logs/component.rb
215
216
  - lib/datadog/ci/logs/transport.rb
216
217
  - lib/datadog/ci/readonly_test_module.rb
@@ -218,10 +219,12 @@ files:
218
219
  - lib/datadog/ci/remote/component.rb
219
220
  - lib/datadog/ci/remote/library_settings.rb
220
221
  - lib/datadog/ci/remote/library_settings_client.rb
222
+ - lib/datadog/ci/remote/null_component.rb
221
223
  - lib/datadog/ci/remote/slow_test_retries.rb
222
224
  - lib/datadog/ci/span.rb
223
225
  - lib/datadog/ci/test.rb
224
226
  - lib/datadog/ci/test_discovery/component.rb
227
+ - lib/datadog/ci/test_discovery/null_component.rb
225
228
  - lib/datadog/ci/test_management/component.rb
226
229
  - lib/datadog/ci/test_management/null_component.rb
227
230
  - lib/datadog/ci/test_management/tests_properties.rb
@@ -230,6 +233,7 @@ files:
230
233
  - lib/datadog/ci/test_optimisation/coverage/ddcov.rb
231
234
  - lib/datadog/ci/test_optimisation/coverage/event.rb
232
235
  - lib/datadog/ci/test_optimisation/coverage/transport.rb
236
+ - lib/datadog/ci/test_optimisation/null_component.rb
233
237
  - lib/datadog/ci/test_optimisation/skippable.rb
234
238
  - lib/datadog/ci/test_optimisation/skippable_percentage/base.rb
235
239
  - lib/datadog/ci/test_optimisation/skippable_percentage/calculator.rb
@@ -311,7 +315,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
311
315
  version: 2.7.0
312
316
  - - "<"
313
317
  - !ruby/object:Gem::Version
314
- version: '3.5'
318
+ version: '4.0'
315
319
  required_rubygems_version: !ruby/object:Gem::Requirement
316
320
  requirements:
317
321
  - - ">="