datadog-ci 1.14.0 → 1.15.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -2
  3. data/lib/datadog/ci/configuration/components.rb +2 -1
  4. data/lib/datadog/ci/configuration/settings.rb +6 -0
  5. data/lib/datadog/ci/contrib/minitest/runner.rb +4 -1
  6. data/lib/datadog/ci/contrib/parallel_tests/cli.rb +84 -0
  7. data/lib/datadog/ci/contrib/parallel_tests/configuration/settings.rb +32 -0
  8. data/lib/datadog/ci/contrib/parallel_tests/ext.rb +16 -0
  9. data/lib/datadog/ci/contrib/parallel_tests/integration.rb +42 -0
  10. data/lib/datadog/ci/contrib/parallel_tests/patcher.rb +24 -0
  11. data/lib/datadog/ci/contrib/rspec/example.rb +7 -0
  12. data/lib/datadog/ci/contrib/rspec/example_group.rb +18 -8
  13. data/lib/datadog/ci/contrib/rspec/helpers.rb +18 -0
  14. data/lib/datadog/ci/contrib/rspec/runner.rb +2 -0
  15. data/lib/datadog/ci/ext/settings.rb +1 -0
  16. data/lib/datadog/ci/ext/test.rb +20 -0
  17. data/lib/datadog/ci/git/local_repository.rb +1 -1
  18. data/lib/datadog/ci/git/tree_uploader.rb +9 -0
  19. data/lib/datadog/ci/readonly_test_module.rb +28 -0
  20. data/lib/datadog/ci/readonly_test_session.rb +31 -0
  21. data/lib/datadog/ci/remote/component.rb +43 -16
  22. data/lib/datadog/ci/test_management/component.rb +34 -1
  23. data/lib/datadog/ci/test_management/tests_properties.rb +2 -1
  24. data/lib/datadog/ci/test_optimisation/component.rb +31 -5
  25. data/lib/datadog/ci/test_session.rb +7 -1
  26. data/lib/datadog/ci/test_visibility/component.rb +82 -28
  27. data/lib/datadog/ci/test_visibility/context.rb +77 -29
  28. data/lib/datadog/ci/test_visibility/null_component.rb +4 -0
  29. data/lib/datadog/ci/test_visibility/store/{local.rb → fiber_local.rb} +1 -1
  30. data/lib/datadog/ci/test_visibility/store/{global.rb → process.rb} +23 -18
  31. data/lib/datadog/ci/test_visibility/transport.rb +1 -2
  32. data/lib/datadog/ci/transport/http.rb +1 -1
  33. data/lib/datadog/ci/utils/file_storage.rb +57 -0
  34. data/lib/datadog/ci/utils/stateful.rb +52 -0
  35. data/lib/datadog/ci/version.rb +1 -1
  36. data/lib/datadog/ci.rb +4 -3
  37. metadata +14 -5
  38. data/lib/datadog/ci/test_visibility/capabilities.rb +0 -36
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../../readonly_test_session"
4
+ require_relative "../../readonly_test_module"
5
+
3
6
  module Datadog
4
7
  module CI
5
8
  module TestVisibility
6
9
  module Store
7
10
  # This context is shared between threads and represents the current test session and test module.
8
- class Global
11
+ class Process
12
+ attr_reader :readonly_test_session, :readonly_test_module
13
+
9
14
  def initialize
10
15
  # we are using Monitor instead of Mutex because it is reentrant
11
16
  @mutex = Monitor.new
@@ -13,6 +18,11 @@ module Datadog
13
18
  @test_session = nil
14
19
  @test_module = nil
15
20
  @test_suites = {}
21
+
22
+ # small copies of id, name and some tags: store them in the current process to set session/module context
23
+ # for any spans faster
24
+ @readonly_test_session = nil
25
+ @readonly_test_module = nil
16
26
  end
17
27
 
18
28
  def fetch_or_activate_test_suite(test_suite_name, &block)
@@ -53,12 +63,6 @@ module Datadog
53
63
  @mutex.synchronize { @test_suites[test_suite_name] }
54
64
  end
55
65
 
56
- def service
57
- @mutex.synchronize do
58
- @test_session&.service
59
- end
60
- end
61
-
62
66
  def stop_all_test_suites
63
67
  @mutex.synchronize do
64
68
  @test_suites.each_value(&:finish)
@@ -66,17 +70,6 @@ module Datadog
66
70
  end
67
71
  end
68
72
 
69
- def inheritable_session_tags
70
- @mutex.synchronize do
71
- test_session = @test_session
72
- if test_session
73
- test_session.inheritable_tags
74
- else
75
- {}
76
- end
77
- end
78
- end
79
-
80
73
  def deactivate_test_session!
81
74
  @mutex.synchronize { @test_session = nil }
82
75
  end
@@ -88,6 +81,18 @@ module Datadog
88
81
  def deactivate_test_suite!(test_suite_name)
89
82
  @mutex.synchronize { @test_suites.delete(test_suite_name) }
90
83
  end
84
+
85
+ def set_readonly_test_session(remote_test_session)
86
+ return if remote_test_session.nil?
87
+
88
+ @readonly_test_session = Datadog::CI::ReadonlyTestSession.new(remote_test_session)
89
+ end
90
+
91
+ def set_readonly_test_module(remote_test_module)
92
+ return if remote_test_module.nil?
93
+
94
+ @readonly_test_module = Datadog::CI::ReadonlyTestModule.new(remote_test_module)
95
+ end
91
96
  end
92
97
  end
93
98
  end
@@ -4,7 +4,6 @@ require "datadog/core/environment/identity"
4
4
  require "datadog/core/telemetry/logging"
5
5
  require "datadog/core/utils/only_once"
6
6
 
7
- require_relative "capabilities"
8
7
  require_relative "serializers/factories/test_level"
9
8
 
10
9
  require_relative "../ext/app_types"
@@ -117,7 +116,7 @@ module Datadog
117
116
  packer.write("library_version")
118
117
  packer.write(Datadog::CI::VERSION::STRING)
119
118
 
120
- library_capabilities_tags = Capabilities.tags
119
+ library_capabilities_tags = Ext::Test::LibraryCapabilities::CAPABILITY_VERSIONS
121
120
 
122
121
  Ext::AppTypes::CI_SPAN_TYPES.each do |ci_span_type|
123
122
  packer.write(ci_span_type)
@@ -29,7 +29,7 @@ module Datadog
29
29
  @host = host
30
30
  @port = port
31
31
  @timeout = timeout
32
- @ssl = ssl.nil? ? true : ssl
32
+ @ssl = ssl.nil? || ssl
33
33
  @compress = compress.nil? ? false : compress
34
34
  end
35
35
 
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "tempfile"
5
+
6
+ module Datadog
7
+ module CI
8
+ module Utils
9
+ # FileStorage module provides functionality for storing and retrieving arbitrary Ruby objects in a temp file
10
+ # to share them between processes.
11
+ module FileStorage
12
+ TEMP_DIR = File.join(Dir.tmpdir, "datadog-ci-storage")
13
+
14
+ def self.store(key, value)
15
+ ensure_temp_dir_exists
16
+ file_path = file_path_for(key)
17
+
18
+ File.binwrite(file_path, Marshal.dump(value))
19
+
20
+ true
21
+ rescue => e
22
+ Datadog.logger.error("Failed to store data for key '#{key}': #{e.class} - #{e.message}")
23
+ false
24
+ end
25
+
26
+ def self.retrieve(key)
27
+ file_path = file_path_for(key)
28
+ return nil unless File.exist?(file_path)
29
+
30
+ Marshal.load(File.binread(file_path))
31
+ rescue => e
32
+ Datadog.logger.error("Failed to retrieve data for key '#{key}': #{e.class} - #{e.message}")
33
+ nil
34
+ end
35
+
36
+ def self.cleanup
37
+ return false unless Dir.exist?(TEMP_DIR)
38
+
39
+ FileUtils.rm_rf(TEMP_DIR)
40
+ true
41
+ rescue => e
42
+ Datadog.logger.error("Failed to cleanup storage directory: #{e.class} - #{e.message}")
43
+ false
44
+ end
45
+
46
+ def self.ensure_temp_dir_exists
47
+ FileUtils.mkdir_p(TEMP_DIR) unless Dir.exist?(TEMP_DIR)
48
+ end
49
+
50
+ def self.file_path_for(key)
51
+ sanitized_key = key.to_s.gsub(/[^a-zA-Z0-9_-]/, "_")
52
+ File.join(TEMP_DIR, "dd-ci-#{sanitized_key}.dat")
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "file_storage"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Utils
8
+ # Module for components that need to persist and restore state
9
+ module Stateful
10
+ # Store component state
11
+ def store_component_state
12
+ state = serialize_state
13
+
14
+ res = Utils::FileStorage.store(storage_key, state)
15
+ Datadog.logger.debug { "Stored component state (key=#{storage_key}): #{res}" }
16
+
17
+ res
18
+ end
19
+
20
+ # Load component state
21
+ def load_component_state
22
+ test_visibility_component = Datadog.send(:components).test_visibility
23
+ return false unless test_visibility_component.client_process?
24
+
25
+ state = Utils::FileStorage.retrieve(storage_key)
26
+ unless state
27
+ Datadog.logger.debug { "No component state found in file storage (key=#{storage_key})" }
28
+ return false
29
+ end
30
+
31
+ restore_state(state)
32
+ Datadog.logger.debug { "Loaded component state from file storage (key=#{storage_key})" }
33
+
34
+ true
35
+ end
36
+
37
+ # These methods must be implemented by including classes
38
+ def serialize_state
39
+ raise NotImplementedError, "Components must implement #serialize_state"
40
+ end
41
+
42
+ def restore_state(state)
43
+ raise NotImplementedError, "Components must implement #restore_state"
44
+ end
45
+
46
+ def storage_key
47
+ raise NotImplementedError, "Components must implement #storage_key"
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -4,7 +4,7 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = 1
7
- MINOR = 14
7
+ MINOR = 15
8
8
  PATCH = 0
9
9
  PRE = nil
10
10
  BUILD = nil
data/lib/datadog/ci.rb CHANGED
@@ -415,16 +415,17 @@ end
415
415
 
416
416
  # Integrations
417
417
 
418
- # Test frameworks (manual instrumentation)
418
+ # Test frameworks
419
419
  require_relative "ci/contrib/cucumber/integration"
420
420
  require_relative "ci/contrib/minitest/integration"
421
421
  require_relative "ci/contrib/rspec/integration"
422
422
 
423
- # Test runners (instrumented automatically when corresponding frameworks are instrumented)
423
+ # Test runners
424
424
  require_relative "ci/contrib/knapsack/integration"
425
425
  require_relative "ci/contrib/ciqueue/integration"
426
+ require_relative "ci/contrib/parallel_tests/integration"
426
427
 
427
- # Additional test libraries (auto instrumented later on test session start)
428
+ # Additional test libraries (auto instrumented on test session start)
428
429
  require_relative "ci/contrib/selenium/integration"
429
430
  require_relative "ci/contrib/cuprite/integration"
430
431
  require_relative "ci/contrib/simplecov/integration"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog-ci
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.14.0
4
+ version: 1.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-11 00:00:00.000000000 Z
10
+ date: 2025-03-25 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: datadog
@@ -117,11 +117,17 @@ files:
117
117
  - lib/datadog/ci/contrib/minitest/runnable.rb
118
118
  - lib/datadog/ci/contrib/minitest/runner.rb
119
119
  - lib/datadog/ci/contrib/minitest/test.rb
120
+ - lib/datadog/ci/contrib/parallel_tests/cli.rb
121
+ - lib/datadog/ci/contrib/parallel_tests/configuration/settings.rb
122
+ - lib/datadog/ci/contrib/parallel_tests/ext.rb
123
+ - lib/datadog/ci/contrib/parallel_tests/integration.rb
124
+ - lib/datadog/ci/contrib/parallel_tests/patcher.rb
120
125
  - lib/datadog/ci/contrib/patcher.rb
121
126
  - lib/datadog/ci/contrib/rspec/configuration/settings.rb
122
127
  - lib/datadog/ci/contrib/rspec/example.rb
123
128
  - lib/datadog/ci/contrib/rspec/example_group.rb
124
129
  - lib/datadog/ci/contrib/rspec/ext.rb
130
+ - lib/datadog/ci/contrib/rspec/helpers.rb
125
131
  - lib/datadog/ci/contrib/rspec/integration.rb
126
132
  - lib/datadog/ci/contrib/rspec/patcher.rb
127
133
  - lib/datadog/ci/contrib/rspec/runner.rb
@@ -172,6 +178,8 @@ files:
172
178
  - lib/datadog/ci/git/tree_uploader.rb
173
179
  - lib/datadog/ci/git/upload_packfile.rb
174
180
  - lib/datadog/ci/git/user.rb
181
+ - lib/datadog/ci/readonly_test_module.rb
182
+ - lib/datadog/ci/readonly_test_session.rb
175
183
  - lib/datadog/ci/remote/component.rb
176
184
  - lib/datadog/ci/remote/library_settings.rb
177
185
  - lib/datadog/ci/remote/library_settings_client.rb
@@ -206,7 +214,6 @@ files:
206
214
  - lib/datadog/ci/test_retries/strategy/retry_new.rb
207
215
  - lib/datadog/ci/test_session.rb
208
216
  - lib/datadog/ci/test_suite.rb
209
- - lib/datadog/ci/test_visibility/capabilities.rb
210
217
  - lib/datadog/ci/test_visibility/component.rb
211
218
  - lib/datadog/ci/test_visibility/context.rb
212
219
  - lib/datadog/ci/test_visibility/flush.rb
@@ -222,8 +229,8 @@ files:
222
229
  - lib/datadog/ci/test_visibility/serializers/test_suite.rb
223
230
  - lib/datadog/ci/test_visibility/serializers/test_v1.rb
224
231
  - lib/datadog/ci/test_visibility/serializers/test_v2.rb
225
- - lib/datadog/ci/test_visibility/store/global.rb
226
- - lib/datadog/ci/test_visibility/store/local.rb
232
+ - lib/datadog/ci/test_visibility/store/fiber_local.rb
233
+ - lib/datadog/ci/test_visibility/store/process.rb
227
234
  - lib/datadog/ci/test_visibility/telemetry.rb
228
235
  - lib/datadog/ci/test_visibility/total_coverage.rb
229
236
  - lib/datadog/ci/test_visibility/transport.rb
@@ -240,9 +247,11 @@ files:
240
247
  - lib/datadog/ci/transport/telemetry.rb
241
248
  - lib/datadog/ci/utils/bundle.rb
242
249
  - lib/datadog/ci/utils/configuration.rb
250
+ - lib/datadog/ci/utils/file_storage.rb
243
251
  - lib/datadog/ci/utils/git.rb
244
252
  - lib/datadog/ci/utils/parsing.rb
245
253
  - lib/datadog/ci/utils/rum.rb
254
+ - lib/datadog/ci/utils/stateful.rb
246
255
  - lib/datadog/ci/utils/telemetry.rb
247
256
  - lib/datadog/ci/utils/test_run.rb
248
257
  - lib/datadog/ci/version.rb
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../ext/test"
4
-
5
- module Datadog
6
- module CI
7
- module TestVisibility
8
- # Generates internal tags for library capabilities
9
- module Capabilities
10
- def self.tags
11
- tags = {}
12
-
13
- test_optimisation = Datadog::CI.send(:test_optimisation)
14
- tags[Ext::Test::LibraryCapabilities::TAG_TEST_IMPACT_ANALYSIS] = test_optimisation.enabled.to_s
15
-
16
- test_management = Datadog::CI.send(:test_management)
17
- test_management_tag_value = test_management.enabled.to_s
18
-
19
- [
20
- Ext::Test::LibraryCapabilities::TAG_TEST_MANAGEMENT_ATTEMPT_TO_FIX,
21
- Ext::Test::LibraryCapabilities::TAG_TEST_MANAGEMENT_QUARANTINE,
22
- Ext::Test::LibraryCapabilities::TAG_TEST_MANAGEMENT_DISABLE
23
- ].each do |tag|
24
- tags[tag] = test_management_tag_value
25
- end
26
-
27
- test_retries = Datadog::CI.send(:test_retries)
28
- tags[Ext::Test::LibraryCapabilities::TAG_AUTO_TEST_RETRIES] = test_retries.auto_test_retries_feature_enabled.to_s
29
- tags[Ext::Test::LibraryCapabilities::TAG_EARLY_FLAKE_DETECTION] = test_retries.early_flake_detection_feature_enabled.to_s
30
-
31
- tags
32
- end
33
- end
34
- end
35
- end
36
- end