datadog-ci 1.30.0 → 1.32.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 +4 -4
- data/CHANGELOG.md +29 -2
- data/ext/datadog_ci_native/ci.c +1 -1
- data/ext/datadog_ci_native/iseq_collector.c +1 -1
- data/ext/datadog_ci_native/iseq_collector.h +1 -1
- data/lib/datadog/ci/configuration/components.rb +15 -2
- data/lib/datadog/ci/configuration/settings.rb +21 -0
- data/lib/datadog/ci/contrib/minitest/helpers.rb +5 -2
- data/lib/datadog/ci/contrib/minitest/run_method_capture.rb +47 -0
- data/lib/datadog/ci/contrib/minitest/test.rb +72 -14
- data/lib/datadog/ci/ext/environment/providers/jenkins.rb +2 -1
- data/lib/datadog/ci/ext/test_discovery.rb +3 -1
- data/lib/datadog/ci/ext/test_optimization_cache.rb +31 -0
- data/lib/datadog/ci/git/tree_uploader.rb +6 -3
- data/lib/datadog/ci/remote/component.rb +4 -4
- data/lib/datadog/ci/remote/library_settings.rb +7 -1
- data/lib/datadog/ci/test_impact_analysis/component.rb +5 -65
- data/lib/datadog/ci/test_management/component.rb +4 -14
- data/lib/datadog/ci/test_optimization_cache/component.rb +82 -0
- data/lib/datadog/ci/test_optimization_cache/locator.rb +96 -0
- data/lib/datadog/ci/test_optimization_cache/null_component.rb +32 -0
- data/lib/datadog/ci/test_optimization_cache/readers/base.rb +39 -0
- data/lib/datadog/ci/test_optimization_cache/readers/legacy.rb +74 -0
- data/lib/datadog/ci/test_optimization_cache/readers/missing.rb +33 -0
- data/lib/datadog/ci/test_optimization_cache/readers/v1.rb +56 -0
- data/lib/datadog/ci/test_tracing/component.rb +4 -11
- data/lib/datadog/ci/test_tracing/serializers/base.rb +4 -1
- data/lib/datadog/ci/test_tracing/serializers/meta_truncation.rb +23 -0
- data/lib/datadog/ci/test_tracing/transport.rb +10 -7
- data/lib/datadog/ci/utils/json.rb +23 -0
- data/lib/datadog/ci/utils/stateful.rb +18 -20
- data/lib/datadog/ci/utils/test_run.rb +0 -6
- data/lib/datadog/ci/version.rb +1 -1
- metadata +12 -2
- data/lib/datadog/ci/ext/dd_test.rb +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9525584d2c9951d35efe82ecfead3c45e104ced47bddaa5c11146147dfab1ed8
|
|
4
|
+
data.tar.gz: 438719f7fb308e58196321706bf03beeda21c717875e9a23d88027a485d5dfba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d1537eb0f893513d6ba2b2ccfacecfd2ff424c8f0d1f84ef27045d03d0d4963046b8c1df0611c7360cfbdd6a6a893e74804377b725b6439a559e27fe8e9ce57b
|
|
7
|
+
data.tar.gz: 31d30f06434ec6305d17000499879d1133a7f472ba01c3300d30effe2abf770b0f7bb002390a984baf9b77febbc3e4dc9b9390f249a2c81a66aa68ecd37bf344
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.32.0] - 2026-06-08
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
* Truncate CI Visibility meta tag values ([#515][])
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
* Fix Minitest TIA skipped hooks ([#516][])
|
|
12
|
+
* Fix: use Gem::Version for Ruby allocation tracing check ([#522][])
|
|
13
|
+
* Fix symbol collision with a debug gem ([#521][])
|
|
14
|
+
|
|
15
|
+
## [1.31.0] - 2026-05-20
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
* Add Test Optimization cache readers for Bazel support and DDTest (test parallelization) ([#511][])
|
|
20
|
+
* Add Jenkins custom parent id env var ([#509][])
|
|
21
|
+
|
|
3
22
|
## [1.30.0] - 2026-05-12
|
|
4
23
|
|
|
5
24
|
### Changed
|
|
@@ -634,7 +653,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
|
634
653
|
|
|
635
654
|
- Ruby versions < 2.7 no longer supported ([#8][])
|
|
636
655
|
|
|
637
|
-
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.
|
|
656
|
+
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.32.0...main
|
|
657
|
+
[1.32.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.31.0...v1.32.0
|
|
658
|
+
[1.31.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.30.0...v1.31.0
|
|
638
659
|
[1.30.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.29.0...v1.30.0
|
|
639
660
|
[1.29.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.28.0...v1.29.0
|
|
640
661
|
[1.28.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.27.0...v1.28.0
|
|
@@ -898,4 +919,10 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
|
898
919
|
[#499]: https://github.com/DataDog/datadog-ci-rb/issues/499
|
|
899
920
|
[#500]: https://github.com/DataDog/datadog-ci-rb/issues/500
|
|
900
921
|
[#501]: https://github.com/DataDog/datadog-ci-rb/issues/501
|
|
901
|
-
[#506]: https://github.com/DataDog/datadog-ci-rb/issues/506
|
|
922
|
+
[#506]: https://github.com/DataDog/datadog-ci-rb/issues/506
|
|
923
|
+
[#509]: https://github.com/DataDog/datadog-ci-rb/issues/509
|
|
924
|
+
[#511]: https://github.com/DataDog/datadog-ci-rb/issues/511
|
|
925
|
+
[#515]: https://github.com/DataDog/datadog-ci-rb/issues/515
|
|
926
|
+
[#516]: https://github.com/DataDog/datadog-ci-rb/issues/516
|
|
927
|
+
[#521]: https://github.com/DataDog/datadog-ci-rb/issues/521
|
|
928
|
+
[#522]: https://github.com/DataDog/datadog-ci-rb/issues/522
|
data/ext/datadog_ci_native/ci.c
CHANGED
|
@@ -54,7 +54,7 @@ static VALUE iseq_collector_collect(VALUE self) {
|
|
|
54
54
|
|
|
55
55
|
/* ---- Module initialization ---------------------------------------------- */
|
|
56
56
|
|
|
57
|
-
void
|
|
57
|
+
void Init_dd_ci_iseq_collector(void) {
|
|
58
58
|
VALUE mDatadog = rb_define_module("Datadog");
|
|
59
59
|
VALUE mCI = rb_define_module_under(mDatadog, "CI");
|
|
60
60
|
VALUE mSourceCode = rb_define_module_under(mCI, "SourceCode");
|
|
@@ -17,6 +17,8 @@ require_relative "../remote/library_settings_client"
|
|
|
17
17
|
require_relative "../test_management/component"
|
|
18
18
|
require_relative "../test_management/null_component"
|
|
19
19
|
require_relative "../test_management/tests_properties"
|
|
20
|
+
require_relative "../test_optimization_cache/component"
|
|
21
|
+
require_relative "../test_optimization_cache/null_component"
|
|
20
22
|
require_relative "../test_impact_analysis/null_component"
|
|
21
23
|
require_relative "../test_impact_analysis/component"
|
|
22
24
|
require_relative "../test_impact_analysis/coverage/transport"
|
|
@@ -45,7 +47,8 @@ module Datadog
|
|
|
45
47
|
# Adds CI behavior to Datadog trace components
|
|
46
48
|
module Components
|
|
47
49
|
attr_reader :test_tracing, :test_impact_analysis, :git_tree_upload_worker, :ci_remote, :test_retries,
|
|
48
|
-
:test_management, :agentless_logs_submission, :impacted_tests_detection, :test_discovery, :code_coverage
|
|
50
|
+
:test_management, :agentless_logs_submission, :impacted_tests_detection, :test_discovery, :code_coverage,
|
|
51
|
+
:test_optimization_cache
|
|
49
52
|
|
|
50
53
|
def initialize(settings)
|
|
51
54
|
@test_impact_analysis = TestImpactAnalysis::NullComponent.new
|
|
@@ -57,6 +60,7 @@ module Datadog
|
|
|
57
60
|
@impacted_tests_detection = ImpactedTestsDetection::NullComponent.new
|
|
58
61
|
@test_discovery = TestDiscovery::NullComponent.new
|
|
59
62
|
@code_coverage = CodeCoverage::NullComponent.new
|
|
63
|
+
@test_optimization_cache = TestOptimizationCache::NullComponent.new
|
|
60
64
|
|
|
61
65
|
# Activate CI mode if enabled
|
|
62
66
|
if settings.ci.enabled
|
|
@@ -69,6 +73,7 @@ module Datadog
|
|
|
69
73
|
def shutdown!(replacement = nil)
|
|
70
74
|
super
|
|
71
75
|
|
|
76
|
+
@test_optimization_cache&.shutdown!
|
|
72
77
|
@test_tracing&.shutdown!
|
|
73
78
|
@test_impact_analysis&.shutdown!
|
|
74
79
|
@agentless_logs_submission&.shutdown!
|
|
@@ -113,6 +118,13 @@ module Datadog
|
|
|
113
118
|
)
|
|
114
119
|
@test_discovery.disable_features_for_test_discovery!(settings)
|
|
115
120
|
|
|
121
|
+
@test_optimization_cache = TestOptimizationCache::Component.new(
|
|
122
|
+
manifest_file: settings.ci.test_optimization_cache_manifest_file,
|
|
123
|
+
runfiles_dir: settings.ci.test_optimization_cache_runfiles_dir,
|
|
124
|
+
runfiles_manifest_file: settings.ci.test_optimization_cache_runfiles_manifest_file,
|
|
125
|
+
test_srcdir: settings.ci.test_optimization_cache_test_srcdir
|
|
126
|
+
)
|
|
127
|
+
|
|
116
128
|
# Configure Datadog::Tracing module
|
|
117
129
|
|
|
118
130
|
# No need not use 128-bit trace ids for test visibility,
|
|
@@ -180,7 +192,8 @@ module Datadog
|
|
|
180
192
|
settings.ci.itr_test_impact_analysis_use_allocation_tracing = false
|
|
181
193
|
end
|
|
182
194
|
|
|
183
|
-
if RUBY_VERSION.start_with?("3.2.") &&
|
|
195
|
+
if RUBY_VERSION.start_with?("3.2.") &&
|
|
196
|
+
Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2.3") &&
|
|
184
197
|
settings.ci.itr_test_impact_analysis_use_allocation_tracing
|
|
185
198
|
Datadog.logger.warn(
|
|
186
199
|
"Test Impact Analysis: Allocation tracing is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly " \
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../contrib/instrumentation"
|
|
4
4
|
require_relative "../ext/settings"
|
|
5
|
+
require_relative "../ext/test_optimization_cache"
|
|
5
6
|
require_relative "../utils/bundle"
|
|
6
7
|
require_relative "../utils/parsing"
|
|
7
8
|
|
|
@@ -180,6 +181,26 @@ module Datadog
|
|
|
180
181
|
o.env CI::Ext::Settings::ENV_TEST_DISCOVERY_OUTPUT_PATH
|
|
181
182
|
end
|
|
182
183
|
|
|
184
|
+
option :test_optimization_cache_manifest_file do |o|
|
|
185
|
+
o.type :string, nilable: true
|
|
186
|
+
o.env CI::Ext::TestOptimizationCache::ENV_MANIFEST_FILE
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
option :test_optimization_cache_runfiles_dir do |o|
|
|
190
|
+
o.type :string, nilable: true
|
|
191
|
+
o.env CI::Ext::TestOptimizationCache::ENV_RUNFILES_DIR
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
option :test_optimization_cache_runfiles_manifest_file do |o|
|
|
195
|
+
o.type :string, nilable: true
|
|
196
|
+
o.env CI::Ext::TestOptimizationCache::ENV_RUNFILES_MANIFEST_FILE
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
option :test_optimization_cache_test_srcdir do |o|
|
|
200
|
+
o.type :string, nilable: true
|
|
201
|
+
o.env CI::Ext::TestOptimizationCache::ENV_TEST_SRCDIR
|
|
202
|
+
end
|
|
203
|
+
|
|
183
204
|
option :tia_static_dependencies_tracking_enabled do |o|
|
|
184
205
|
o.type :bool
|
|
185
206
|
o.env CI::Ext::Settings::ENV_TIA_STATIC_DEPENDENCIES_TRACKING_ENABLED
|
|
@@ -61,8 +61,11 @@ module Datadog
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
def self.parallel?(klass)
|
|
64
|
-
klass.ancestors.include?(::Minitest::Parallel::Test) ||
|
|
65
|
-
|
|
64
|
+
klass.ancestors.include?(::Minitest::Parallel::Test) || ci_queue?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.ci_queue?
|
|
68
|
+
!!(defined?(::Minitest::Queue) && ::Minitest.singleton_class.ancestors.include?(::Minitest::Queue))
|
|
66
69
|
end
|
|
67
70
|
|
|
68
71
|
def self.extract_source_location_from_class(klass)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module CI
|
|
5
|
+
module Contrib
|
|
6
|
+
module Minitest
|
|
7
|
+
# Captures the concrete Minitest::Test#run implementation below Datadog.
|
|
8
|
+
#
|
|
9
|
+
# This exists because ci-queue loads minitest-reporters, and minitest-reporters
|
|
10
|
+
# aliases the current Minitest::Test#run as run_without_hooks before replacing it
|
|
11
|
+
# with its own wrapper. If Datadog has already prepended its run method, that alias
|
|
12
|
+
# points back to Datadog and re-enters the same active test span.
|
|
13
|
+
#
|
|
14
|
+
# Auto-instrumentation makes this trickier: it patches from a script_compiled
|
|
15
|
+
# TracePoint, so it can observe Minitest::Test while `require "minitest"` is still
|
|
16
|
+
# evaluating the class body. In that window Minitest::Test exists, but its concrete
|
|
17
|
+
# #run has not been defined yet, so instance_method(:run) resolves to the abstract
|
|
18
|
+
# Minitest::Runnable#run. The one-shot method_added path below replaces that early
|
|
19
|
+
# abstract capture with the concrete Minitest::Test#run, before later plugin wrappers
|
|
20
|
+
# like minitest-reporters can alias Datadog's wrapper.
|
|
21
|
+
module RunMethodCapture
|
|
22
|
+
class << self
|
|
23
|
+
def capture_concrete_pre_datadog_run!(storage, owner, datadog_run_owner)
|
|
24
|
+
saved_run = storage._dd_pre_datadog_minitest_run
|
|
25
|
+
return if concrete_pre_datadog_run?(saved_run, datadog_run_owner)
|
|
26
|
+
return if !defined?(::Minitest::Test) || !owner.equal?(::Minitest::Test)
|
|
27
|
+
|
|
28
|
+
datadog_run = owner.instance_method(:run)
|
|
29
|
+
return unless datadog_run.owner == datadog_run_owner
|
|
30
|
+
|
|
31
|
+
candidate_run = datadog_run.super_method
|
|
32
|
+
if concrete_pre_datadog_run?(candidate_run, datadog_run_owner)
|
|
33
|
+
storage._dd_pre_datadog_minitest_run = candidate_run
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def concrete_pre_datadog_run?(method, datadog_run_owner)
|
|
38
|
+
method &&
|
|
39
|
+
method.owner != datadog_run_owner &&
|
|
40
|
+
(!defined?(::Minitest::Runnable) || method.owner != ::Minitest::Runnable)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -6,6 +6,7 @@ require_relative "../../source_code/method_inspect"
|
|
|
6
6
|
require_relative "../instrumentation"
|
|
7
7
|
require_relative "ext"
|
|
8
8
|
require_relative "helpers"
|
|
9
|
+
require_relative "run_method_capture"
|
|
9
10
|
|
|
10
11
|
module Datadog
|
|
11
12
|
module CI
|
|
@@ -13,16 +14,68 @@ module Datadog
|
|
|
13
14
|
module Minitest
|
|
14
15
|
# Lifecycle hooks to instrument Minitest::Test
|
|
15
16
|
module Test
|
|
17
|
+
class << self
|
|
18
|
+
attr_accessor :_dd_pre_datadog_minitest_run
|
|
19
|
+
end
|
|
20
|
+
|
|
16
21
|
def self.included(base)
|
|
17
|
-
base
|
|
18
|
-
|
|
22
|
+
unless base < InstanceMethods
|
|
23
|
+
# Preserve the run implementation that existed before Datadog was prepended.
|
|
24
|
+
# RunMethodCapture repairs this if auto-instrumentation observes Minitest::Test
|
|
25
|
+
# before Minitest defines its concrete #run. See that helper for the ci-queue
|
|
26
|
+
# and minitest-reporters load-order details.
|
|
27
|
+
self._dd_pre_datadog_minitest_run = base.instance_method(:run)
|
|
28
|
+
base.prepend(InstanceMethods)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
base.singleton_class.prepend(ClassMethods) unless base.singleton_class < ClassMethods
|
|
19
32
|
end
|
|
20
33
|
|
|
21
34
|
module InstanceMethods
|
|
22
|
-
def
|
|
35
|
+
def run
|
|
36
|
+
return super unless datadog_configuration[:enabled]
|
|
37
|
+
|
|
38
|
+
return run_without_datadog_reentry if datadog_run_reentered?
|
|
39
|
+
|
|
40
|
+
test_span = start_datadog_test
|
|
41
|
+
return skip_datadog_test(test_span) if test_span&.should_skip?
|
|
42
|
+
|
|
43
|
+
super
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def after_teardown
|
|
47
|
+
test_span = _dd_test_tracing_component.active_test
|
|
48
|
+
return super unless test_span
|
|
49
|
+
|
|
50
|
+
finish_with_result(test_span, result_code)
|
|
51
|
+
|
|
52
|
+
# remove failures if failure can be ignored because of retries
|
|
53
|
+
self.failures = [] if test_span.should_ignore_failures?
|
|
54
|
+
|
|
23
55
|
super
|
|
24
|
-
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
25
59
|
|
|
60
|
+
def datadog_run_reentered?
|
|
61
|
+
!!_dd_test_tracing_component.active_test
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def run_without_datadog_reentry
|
|
65
|
+
Datadog.logger.debug do
|
|
66
|
+
"Datadog Minitest instrumentation re-entered for #{self.class}##{name}; running pre-Datadog Minitest run without starting another test span"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
pre_datadog_minitest_run = Test._dd_pre_datadog_minitest_run
|
|
70
|
+
if RunMethodCapture.concrete_pre_datadog_run?(pre_datadog_minitest_run, InstanceMethods)
|
|
71
|
+
return pre_datadog_minitest_run.bind_call(self)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
raise "Datadog Minitest instrumentation re-entered for #{self.class}##{name}, " \
|
|
75
|
+
"but the concrete pre-Datadog Minitest::Test#run method was not captured"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def start_datadog_test
|
|
26
79
|
if Helpers.parallel?(self.class)
|
|
27
80
|
Helpers.start_test_suite(self.class)
|
|
28
81
|
end
|
|
@@ -55,23 +108,22 @@ module Datadog
|
|
|
55
108
|
# steep:ignore:start
|
|
56
109
|
test_span&.itr_unskippable! if self.class.dd_suite_unskippable? || self.class.dd_test_unskippable?(name)
|
|
57
110
|
# steep:ignore:end
|
|
58
|
-
|
|
111
|
+
|
|
112
|
+
test_span
|
|
59
113
|
end
|
|
60
114
|
|
|
61
|
-
def
|
|
62
|
-
|
|
63
|
-
|
|
115
|
+
def skip_datadog_test(test_span)
|
|
116
|
+
time_it do
|
|
117
|
+
capture_exceptions do
|
|
118
|
+
skip(test_span.datadog_skip_reason)
|
|
119
|
+
end
|
|
120
|
+
end
|
|
64
121
|
|
|
65
122
|
finish_with_result(test_span, result_code)
|
|
66
123
|
|
|
67
|
-
|
|
68
|
-
self.failures = [] if test_span.should_ignore_failures?
|
|
69
|
-
|
|
70
|
-
super
|
|
124
|
+
::Minitest::Result.from(self)
|
|
71
125
|
end
|
|
72
126
|
|
|
73
|
-
private
|
|
74
|
-
|
|
75
127
|
def finish_with_result(span, result_code)
|
|
76
128
|
return unless span
|
|
77
129
|
|
|
@@ -101,6 +153,12 @@ module Datadog
|
|
|
101
153
|
end
|
|
102
154
|
|
|
103
155
|
module ClassMethods
|
|
156
|
+
def method_added(method_name)
|
|
157
|
+
RunMethodCapture.capture_concrete_pre_datadog_run!(Test, self, InstanceMethods) if method_name == :run
|
|
158
|
+
ensure
|
|
159
|
+
super
|
|
160
|
+
end
|
|
161
|
+
|
|
104
162
|
def datadog_itr_unskippable(*args)
|
|
105
163
|
if args.nil? || args.empty?
|
|
106
164
|
@datadog_itr_unskippable_suite = true
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "test_optimization_cache"
|
|
4
|
+
|
|
3
5
|
module Datadog
|
|
4
6
|
module CI
|
|
5
7
|
module Ext
|
|
6
8
|
# Defines constants for test discovery mode
|
|
7
9
|
module TestDiscovery
|
|
8
10
|
# Default output path for test discovery mode
|
|
9
|
-
DEFAULT_OUTPUT_PATH = "./#{
|
|
11
|
+
DEFAULT_OUTPUT_PATH = "./#{TestOptimizationCache::PLAN_FOLDER}/test_discovery/tests.json"
|
|
10
12
|
|
|
11
13
|
# Maximum buffer size before writing to file
|
|
12
14
|
MAX_BUFFER_SIZE = 10_000
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module CI
|
|
5
|
+
module Ext
|
|
6
|
+
# Constants for Test Optimization cache generated by ddtest or Bazel.
|
|
7
|
+
module TestOptimizationCache
|
|
8
|
+
ENV_MANIFEST_FILE = "TEST_OPTIMIZATION_MANIFEST_FILE"
|
|
9
|
+
ENV_RUNFILES_DIR = "RUNFILES_DIR"
|
|
10
|
+
ENV_RUNFILES_MANIFEST_FILE = "RUNFILES_MANIFEST_FILE"
|
|
11
|
+
ENV_TEST_SRCDIR = "TEST_SRCDIR"
|
|
12
|
+
|
|
13
|
+
PLAN_FOLDER = ".testoptimization"
|
|
14
|
+
MANIFEST_FILE_NAME = "manifest.txt"
|
|
15
|
+
SUPPORTED_MANIFEST_VERSION = "1"
|
|
16
|
+
|
|
17
|
+
CACHE_FOLDER_NAME = "cache"
|
|
18
|
+
HTTP_CACHE_FOLDER_NAME = "http"
|
|
19
|
+
|
|
20
|
+
TESTOPTIMIZATION_CACHE_PATH = "#{PLAN_FOLDER}/#{CACHE_FOLDER_NAME}"
|
|
21
|
+
TESTOPTIMIZATION_HTTP_CACHE_PATH = "#{TESTOPTIMIZATION_CACHE_PATH}/#{HTTP_CACHE_FOLDER_NAME}"
|
|
22
|
+
|
|
23
|
+
SETTINGS_FILE_NAME = "settings.json"
|
|
24
|
+
KNOWN_TESTS_FILE_NAME = "known_tests.json"
|
|
25
|
+
TEST_MANAGEMENT_FILE_NAME = "test_management.json"
|
|
26
|
+
LEGACY_TEST_MANAGEMENT_TESTS_FILE_NAME = "test_management_tests.json"
|
|
27
|
+
SKIPPABLE_TESTS_FILE_NAME = "skippable_tests.json"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -10,7 +10,6 @@ require_relative "packfiles"
|
|
|
10
10
|
|
|
11
11
|
require_relative "../ext/telemetry"
|
|
12
12
|
require_relative "../utils/telemetry"
|
|
13
|
-
require_relative "../utils/test_run"
|
|
14
13
|
|
|
15
14
|
module Datadog
|
|
16
15
|
module CI
|
|
@@ -34,8 +33,8 @@ module Datadog
|
|
|
34
33
|
return
|
|
35
34
|
end
|
|
36
35
|
|
|
37
|
-
if
|
|
38
|
-
Datadog.logger.debug("
|
|
36
|
+
if test_optimization_cache.cache_available?
|
|
37
|
+
Datadog.logger.debug("Test Optimization cache found, git upload already done, skipping git upload")
|
|
39
38
|
return
|
|
40
39
|
end
|
|
41
40
|
|
|
@@ -113,6 +112,10 @@ module Datadog
|
|
|
113
112
|
def test_tracing_component
|
|
114
113
|
Datadog.send(:components).test_tracing
|
|
115
114
|
end
|
|
115
|
+
|
|
116
|
+
def test_optimization_cache
|
|
117
|
+
Datadog.send(:components).test_optimization_cache
|
|
118
|
+
end
|
|
116
119
|
end
|
|
117
120
|
end
|
|
118
121
|
end
|
|
@@ -56,15 +56,15 @@ module Datadog
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def restore_state_from_datadog_test_runner
|
|
59
|
-
Datadog.logger.debug { "Restoring library configuration from
|
|
59
|
+
Datadog.logger.debug { "Restoring library configuration from Test Optimization cache" }
|
|
60
60
|
|
|
61
|
-
settings =
|
|
61
|
+
settings = load_cached_settings
|
|
62
62
|
if settings.nil?
|
|
63
63
|
Datadog.logger.debug { "Restoring library configuration failed, will request again" }
|
|
64
64
|
return false
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
Datadog.logger.debug { "Restored library configuration from
|
|
67
|
+
Datadog.logger.debug { "Restored library configuration from Test Optimization: #{settings}" }
|
|
68
68
|
@library_configuration = LibrarySettings.from_json(settings)
|
|
69
69
|
true
|
|
70
70
|
end
|
|
@@ -75,7 +75,7 @@ module Datadog
|
|
|
75
75
|
# In test discovery mode, skip backend fetching and use default settings (everything is disabled)
|
|
76
76
|
return @library_configuration = LibrarySettings.from_http_response(nil) if @test_discovery_enabled
|
|
77
77
|
|
|
78
|
-
# skip backend request if library configuration was loaded
|
|
78
|
+
# skip backend request if library configuration was loaded from external cache or stored on disk
|
|
79
79
|
library_configuration_loaded = load_component_state
|
|
80
80
|
return @library_configuration if library_configuration_loaded
|
|
81
81
|
|
|
@@ -19,7 +19,13 @@ module Datadog
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def self.from_json(json)
|
|
22
|
-
new(nil, json)
|
|
22
|
+
new(nil, normalize_json(json))
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.normalize_json(json)
|
|
26
|
+
return nil if json.nil?
|
|
27
|
+
|
|
28
|
+
json.dig(*Ext::Transport::DD_API_SETTINGS_RESPONSE_DIG_KEYS) || json
|
|
23
29
|
end
|
|
24
30
|
|
|
25
31
|
def ok?
|
|
@@ -6,7 +6,6 @@ require "datadog/core/telemetry/logging"
|
|
|
6
6
|
|
|
7
7
|
require_relative "../ext/test"
|
|
8
8
|
require_relative "../ext/telemetry"
|
|
9
|
-
require_relative "../ext/dd_test"
|
|
10
9
|
|
|
11
10
|
require_relative "../git/local_repository"
|
|
12
11
|
|
|
@@ -102,11 +101,9 @@ module Datadog
|
|
|
102
101
|
populate_static_dependencies_map!
|
|
103
102
|
end
|
|
104
103
|
|
|
105
|
-
# Load component state first, and if successful, skip fetching skippable tests
|
|
106
|
-
# Also try to restore from DDTest cache if available
|
|
104
|
+
# Load external cache or component state first, and if successful, skip fetching skippable tests
|
|
107
105
|
if skipping_tests?
|
|
108
106
|
return if load_component_state
|
|
109
|
-
return if restore_state_from_datadog_test_runner
|
|
110
107
|
|
|
111
108
|
fetch_skippable_tests(test_session)
|
|
112
109
|
store_component_state if test_session.distributed
|
|
@@ -333,22 +330,17 @@ module Datadog
|
|
|
333
330
|
end
|
|
334
331
|
|
|
335
332
|
def restore_state_from_datadog_test_runner
|
|
336
|
-
Datadog.logger.debug { "Restoring skippable tests from
|
|
333
|
+
Datadog.logger.debug { "Restoring skippable tests from Test Optimization cache" }
|
|
337
334
|
|
|
338
|
-
skippable_tests_data =
|
|
335
|
+
skippable_tests_data = load_cached_skippable_tests
|
|
339
336
|
if skippable_tests_data.nil?
|
|
340
337
|
Datadog.logger.debug { "Restoring skippable tests failed, will request again" }
|
|
341
338
|
return false
|
|
342
339
|
end
|
|
343
340
|
|
|
344
|
-
Datadog.logger.debug { "Restored skippable tests from
|
|
341
|
+
Datadog.logger.debug { "Restored skippable tests from Test Optimization: #{skippable_tests_data}" }
|
|
345
342
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
Datadog.logger.debug { "Skippable tests after transformation: #{transformed_data}" }
|
|
349
|
-
|
|
350
|
-
# Use the Skippable::Response class to parse the transformed data
|
|
351
|
-
skippable_response = Skippable::Response.from_json(transformed_data)
|
|
343
|
+
skippable_response = Skippable::Response.from_json(skippable_tests_data)
|
|
352
344
|
|
|
353
345
|
@mutex.synchronize do
|
|
354
346
|
@correlation_id = skippable_response.correlation_id
|
|
@@ -363,58 +355,6 @@ module Datadog
|
|
|
363
355
|
|
|
364
356
|
private
|
|
365
357
|
|
|
366
|
-
# Transforms Test Runner skippable tests data format to the format expected by Skippable::Response
|
|
367
|
-
#
|
|
368
|
-
# Test Runner format:
|
|
369
|
-
# {
|
|
370
|
-
# "correlationId": "abc123",
|
|
371
|
-
# "skippableTests": {
|
|
372
|
-
# "suite_name": {
|
|
373
|
-
# "test_name": [{"suite": "suite_name", "name": "test_name", "parameters": "{...}", "configurations": {}}]
|
|
374
|
-
# }
|
|
375
|
-
# }
|
|
376
|
-
# }
|
|
377
|
-
#
|
|
378
|
-
# Expected format:
|
|
379
|
-
# {
|
|
380
|
-
# "meta": {"correlation_id": "abc123"},
|
|
381
|
-
# "data": [{"type": "test", "attributes": {"suite": "suite_name", "name": "test_name", "parameters": "{...}"}}]
|
|
382
|
-
# }
|
|
383
|
-
def transform_test_runner_data(skippable_tests_data)
|
|
384
|
-
skippable_tests = skippable_tests_data.fetch("skippableTests", {}) || {}
|
|
385
|
-
|
|
386
|
-
# Pre-calculate array size for better memory allocation
|
|
387
|
-
total_test_configs = skippable_tests.sum do |_, tests_hash|
|
|
388
|
-
tests_hash.sum { |_, test_configs| test_configs.size }
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
data_array = Array.new(total_test_configs)
|
|
392
|
-
index = 0
|
|
393
|
-
|
|
394
|
-
skippable_tests.each_value do |tests_hash|
|
|
395
|
-
tests_hash.each_value do |test_configs|
|
|
396
|
-
test_configs.each do |test_config|
|
|
397
|
-
data_array[index] = {
|
|
398
|
-
"type" => Ext::Test::ITR_TEST_SKIPPING_MODE,
|
|
399
|
-
"attributes" => {
|
|
400
|
-
"suite" => test_config["suite"],
|
|
401
|
-
"name" => test_config["name"],
|
|
402
|
-
"parameters" => test_config["parameters"]
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
index += 1
|
|
406
|
-
end
|
|
407
|
-
end
|
|
408
|
-
end
|
|
409
|
-
|
|
410
|
-
{
|
|
411
|
-
"meta" => {
|
|
412
|
-
"correlation_id" => skippable_tests_data["correlationId"]
|
|
413
|
-
},
|
|
414
|
-
"data" => data_array
|
|
415
|
-
}
|
|
416
|
-
end
|
|
417
|
-
|
|
418
358
|
def write(event)
|
|
419
359
|
# skip sending events if writer is not configured
|
|
420
360
|
@coverage_writer&.write(event)
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../ext/telemetry"
|
|
4
4
|
require_relative "../ext/test"
|
|
5
|
-
require_relative "../ext/dd_test"
|
|
6
5
|
require_relative "../utils/stateful"
|
|
7
6
|
require_relative "../utils/telemetry"
|
|
8
7
|
require_relative "../utils/test_run"
|
|
@@ -36,7 +35,6 @@ module Datadog
|
|
|
36
35
|
|
|
37
36
|
test_session.set_tag(Ext::Test::TAG_TEST_MANAGEMENT_ENABLED, "true")
|
|
38
37
|
|
|
39
|
-
return if restore_state_from_datadog_test_runner
|
|
40
38
|
return if load_component_state
|
|
41
39
|
|
|
42
40
|
@tests_properties = @tests_properties_client.fetch(test_session)
|
|
@@ -85,25 +83,17 @@ module Datadog
|
|
|
85
83
|
end
|
|
86
84
|
|
|
87
85
|
def restore_state_from_datadog_test_runner
|
|
88
|
-
Datadog.logger.debug { "Restoring test management tests from
|
|
86
|
+
Datadog.logger.debug { "Restoring test management tests from Test Optimization cache" }
|
|
89
87
|
|
|
90
|
-
test_management_data =
|
|
88
|
+
test_management_data = load_cached_test_management
|
|
91
89
|
if test_management_data.nil?
|
|
92
90
|
Datadog.logger.debug { "Restoring test management tests failed, will request again" }
|
|
93
91
|
return false
|
|
94
92
|
end
|
|
95
93
|
|
|
96
|
-
Datadog.logger.debug { "Restored test management tests from
|
|
94
|
+
Datadog.logger.debug { "Restored test management tests from Test Optimization: #{test_management_data}" }
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
# Wrap the data in the expected backend API format
|
|
100
|
-
wrapped_data = {
|
|
101
|
-
"data" => {
|
|
102
|
-
"attributes" => test_management_data
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
tests_properties_response = TestsProperties::Response.from_json(wrapped_data)
|
|
96
|
+
tests_properties_response = TestsProperties::Response.from_json(test_management_data)
|
|
107
97
|
@tests_properties = tests_properties_response.tests
|
|
108
98
|
|
|
109
99
|
Datadog.logger.debug { "Found [#{@tests_properties.size}] test management tests from context" }
|