datadog-ci 1.33.0 → 1.35.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 +13 -2
- data/lib/datadog/ci/configuration/components.rb +2 -0
- data/lib/datadog/ci/configuration/settings.rb +11 -0
- data/lib/datadog/ci/contrib/cucumber/formatter.rb +51 -1
- data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +5 -0
- data/lib/datadog/ci/contrib/minitest/helpers.rb +54 -6
- data/lib/datadog/ci/contrib/minitest/runnable.rb +5 -0
- data/lib/datadog/ci/contrib/minitest/runnable_minitest_6.rb +5 -0
- data/lib/datadog/ci/contrib/minitest/test.rb +21 -27
- data/lib/datadog/ci/contrib/patcher.rb +0 -4
- data/lib/datadog/ci/contrib/rspec/anonymous_example_name.rb +515 -0
- data/lib/datadog/ci/contrib/rspec/example.rb +23 -5
- data/lib/datadog/ci/contrib/rspec/example_group.rb +11 -1
- data/lib/datadog/ci/contrib/simplecov/result_extractor.rb +9 -1
- data/lib/datadog/ci/ext/settings.rb +1 -0
- data/lib/datadog/ci/ext/telemetry.rb +1 -0
- data/lib/datadog/ci/ext/test.rb +8 -1
- data/lib/datadog/ci/remote/library_settings_client.rb +3 -2
- data/lib/datadog/ci/source_code/method_inspect.rb +0 -3
- data/lib/datadog/ci/test_discovery/component.rb +4 -0
- data/lib/datadog/ci/test_impact_analysis/component.rb +176 -59
- data/lib/datadog/ci/test_impact_analysis/coverage/event.rb +6 -4
- data/lib/datadog/ci/test_impact_analysis/null_component.rb +25 -2
- data/lib/datadog/ci/test_impact_analysis/skippable.rb +20 -5
- data/lib/datadog/ci/test_impact_analysis/skippable_percentage/estimator.rb +3 -3
- data/lib/datadog/ci/test_optimization_cache/readers/legacy.rb +1 -1
- data/lib/datadog/ci/test_suite.rb +20 -0
- data/lib/datadog/ci/test_tracing/component.rb +10 -0
- data/lib/datadog/ci/test_tracing/deprecated_total_coverage_metric.rb +11 -1
- data/lib/datadog/ci/utils/configuration.rb +12 -0
- data/lib/datadog/ci/utils/test_name.rb +112 -0
- data/lib/datadog/ci/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f1aa81f9987d876f143abe3a9b7721e1a5b35178c5c854dcdaf79b872c5a0c9e
|
|
4
|
+
data.tar.gz: 261ea8b1b233ac66c0ba7b417018fe477afb05a274ed6607b6bf3c235c58c3ff
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 05aed65898a6b065f99e6a9fd2aab34023fd3ac77aaacc4146d39d8a1e6653ad5cb6d970afc5e6d590a4ddf6eec3f54704089a5ea49d7bf2f614d27d1572ed91
|
|
7
|
+
data.tar.gz: f89daf423afed1bd0ac7c227a28c4a980b92916fcf03a078a9278eb880e059c9fb40f8dc3b0887645e8a806f2e879e70bf23eaaa7500cd3e6e6e2d4b518a449f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.35.0] - 2026-07-23
|
|
4
|
+
|
|
5
|
+
## [1.34.0] - 2026-06-25
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
* Add configurable TIA skipping mode ([#530][])
|
|
10
|
+
|
|
3
11
|
## [1.33.0] - 2026-06-19
|
|
4
12
|
|
|
5
13
|
### Added
|
|
@@ -659,7 +667,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
|
659
667
|
|
|
660
668
|
- Ruby versions < 2.7 no longer supported ([#8][])
|
|
661
669
|
|
|
662
|
-
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.
|
|
670
|
+
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.35.0...main
|
|
671
|
+
[1.35.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.34.0...v1.35.0
|
|
672
|
+
[1.34.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.33.0...v1.34.0
|
|
663
673
|
[1.33.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.32.0...v1.33.0
|
|
664
674
|
[1.32.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.31.0...v1.32.0
|
|
665
675
|
[1.31.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.30.0...v1.31.0
|
|
@@ -933,4 +943,5 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
|
933
943
|
[#516]: https://github.com/DataDog/datadog-ci-rb/issues/516
|
|
934
944
|
[#521]: https://github.com/DataDog/datadog-ci-rb/issues/521
|
|
935
945
|
[#522]: https://github.com/DataDog/datadog-ci-rb/issues/522
|
|
936
|
-
[#527]: https://github.com/DataDog/datadog-ci-rb/issues/527
|
|
946
|
+
[#527]: https://github.com/DataDog/datadog-ci-rb/issues/527
|
|
947
|
+
[#530]: https://github.com/DataDog/datadog-ci-rb/issues/530
|
|
@@ -210,6 +210,7 @@ module Datadog
|
|
|
210
210
|
api: test_visibility_api,
|
|
211
211
|
dd_env: settings.env,
|
|
212
212
|
config_tags: custom_configuration(settings),
|
|
213
|
+
test_skipping_mode: settings.ci.tia_test_skipping_mode,
|
|
213
214
|
coverage_writer: build_coverage_writer(settings, test_visibility_api),
|
|
214
215
|
enabled: settings.ci.enabled && settings.ci.itr_enabled,
|
|
215
216
|
bundle_location: settings.ci.itr_code_coverage_excluded_bundle_path,
|
|
@@ -293,6 +294,7 @@ module Datadog
|
|
|
293
294
|
Remote::LibrarySettingsClient.new(
|
|
294
295
|
api: api,
|
|
295
296
|
dd_env: settings.env,
|
|
297
|
+
test_skipping_mode: settings.ci.tia_test_skipping_mode,
|
|
296
298
|
config_tags: custom_configuration(settings)
|
|
297
299
|
)
|
|
298
300
|
end
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../contrib/instrumentation"
|
|
4
4
|
require_relative "../ext/settings"
|
|
5
|
+
require_relative "../ext/test"
|
|
5
6
|
require_relative "../ext/test_optimization_cache"
|
|
6
7
|
require_relative "../utils/bundle"
|
|
8
|
+
require_relative "../utils/configuration"
|
|
7
9
|
require_relative "../utils/parsing"
|
|
8
10
|
|
|
9
11
|
module Datadog
|
|
@@ -79,6 +81,15 @@ module Datadog
|
|
|
79
81
|
o.default true
|
|
80
82
|
end
|
|
81
83
|
|
|
84
|
+
option :tia_test_skipping_mode do |o|
|
|
85
|
+
o.type :string
|
|
86
|
+
o.env CI::Ext::Settings::ENV_TIA_TEST_SKIPPING_MODE
|
|
87
|
+
o.default CI::Ext::Test::TIATestSkippingMode::TEST
|
|
88
|
+
o.setter do |mode|
|
|
89
|
+
Utils::Configuration.normalize_tia_test_skipping_mode(mode)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
82
93
|
option :git_metadata_upload_enabled do |o|
|
|
83
94
|
o.type :bool
|
|
84
95
|
o.env CI::Ext::Settings::ENV_GIT_METADATA_UPLOAD_ENABLED
|
|
@@ -72,9 +72,14 @@ module Datadog
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
unless same_test_suite_as_current?(test_suite_name)
|
|
75
|
+
suite_tags = test_suite_source_file_tags(event.test_case)
|
|
76
|
+
if test_suite_unskippable?(event.test_case)
|
|
77
|
+
suite_tags[CI::Ext::Test::TAG_ITR_UNSKIPPABLE] = "true"
|
|
78
|
+
end
|
|
79
|
+
|
|
75
80
|
start_test_suite(
|
|
76
81
|
test_suite_name,
|
|
77
|
-
tags:
|
|
82
|
+
tags: suite_tags
|
|
78
83
|
)
|
|
79
84
|
end
|
|
80
85
|
|
|
@@ -228,6 +233,51 @@ module Datadog
|
|
|
228
233
|
CI::Ext::Test::TAG_SOURCE_START => line_number.to_s
|
|
229
234
|
}
|
|
230
235
|
end
|
|
236
|
+
|
|
237
|
+
def test_suite_unskippable?(test_case)
|
|
238
|
+
feature = if test_case.respond_to?(:feature)
|
|
239
|
+
test_case.feature
|
|
240
|
+
else
|
|
241
|
+
@ast_lookup&.gherkin_document(test_case.location.file)&.feature
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
node_has_unskippable_tag?(feature) || test_case_unskippable?(test_case)
|
|
245
|
+
rescue
|
|
246
|
+
test_case_unskippable?(test_case)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def node_has_unskippable_tag?(node)
|
|
250
|
+
return false if node.nil?
|
|
251
|
+
return true if node_tags_include_unskippable?(node)
|
|
252
|
+
|
|
253
|
+
if node.respond_to?(:scenario) && node.scenario
|
|
254
|
+
return true if node_has_unskippable_tag?(node.scenario)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
if node.respond_to?(:rule) && node.rule
|
|
258
|
+
return true if node_has_unskippable_tag?(node.rule)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
return false unless node.respond_to?(:children)
|
|
262
|
+
|
|
263
|
+
node.children.any? { |child| node_has_unskippable_tag?(child) }
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def node_tags_include_unskippable?(node)
|
|
267
|
+
return false unless node.respond_to?(:tags)
|
|
268
|
+
|
|
269
|
+
node.tags.any? { |tag| tag.respond_to?(:name) && tag.name == datadog_itr_unskippable_tag }
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def test_case_unskippable?(test_case)
|
|
273
|
+
test_case.match_tags?(datadog_itr_unskippable_tag)
|
|
274
|
+
rescue
|
|
275
|
+
false
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def datadog_itr_unskippable_tag
|
|
279
|
+
"@#{CI::Ext::Test::ITR_UNSKIPPABLE_OPTION}"
|
|
280
|
+
end
|
|
231
281
|
end
|
|
232
282
|
end
|
|
233
283
|
end
|
|
@@ -37,6 +37,11 @@ module Datadog
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def begin_scenario(test_case)
|
|
40
|
+
active_suite = Datadog::CI.active_test_suite
|
|
41
|
+
if active_suite&.should_skip?
|
|
42
|
+
raise ::Cucumber::Core::Test::Result::Skipped, active_suite.datadog_skip_reason
|
|
43
|
+
end
|
|
44
|
+
|
|
40
45
|
datadog_test = Datadog::CI.active_test
|
|
41
46
|
|
|
42
47
|
# special case for cucumber-ruby: we skip quarantined tests, thus for cucumber quarantined is the same as disabled.
|
|
@@ -7,6 +7,31 @@ module Datadog
|
|
|
7
7
|
module Contrib
|
|
8
8
|
module Minitest
|
|
9
9
|
module Helpers
|
|
10
|
+
module RunnableClassMethods
|
|
11
|
+
def datadog_itr_unskippable(*args)
|
|
12
|
+
if args.nil? || args.empty?
|
|
13
|
+
@datadog_itr_unskippable_suite = true
|
|
14
|
+
else
|
|
15
|
+
@datadog_itr_unskippable_tests = args
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def dd_suite_unskippable?
|
|
20
|
+
@datadog_itr_unskippable_suite
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def dd_test_unskippable?(test_name)
|
|
24
|
+
tests = @datadog_itr_unskippable_tests
|
|
25
|
+
return false unless tests
|
|
26
|
+
|
|
27
|
+
tests.include?(test_name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def dd_any_unskippable?
|
|
31
|
+
dd_suite_unskippable? || !!@datadog_itr_unskippable_tests
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
10
35
|
def self.start_test_suite(klass)
|
|
11
36
|
method = klass.runnable_methods.first
|
|
12
37
|
return nil if method.nil?
|
|
@@ -22,6 +47,9 @@ module Datadog
|
|
|
22
47
|
else
|
|
23
48
|
{}
|
|
24
49
|
end
|
|
50
|
+
if klass.dd_any_unskippable?
|
|
51
|
+
test_suite_tags[CI::Ext::Test::TAG_ITR_UNSKIPPABLE] = "true"
|
|
52
|
+
end
|
|
25
53
|
|
|
26
54
|
test_tracing_component = Datadog.send(:components).test_tracing
|
|
27
55
|
test_suite = test_tracing_component.start_test_suite(
|
|
@@ -53,11 +81,19 @@ module Datadog
|
|
|
53
81
|
end
|
|
54
82
|
|
|
55
83
|
def self.extract_runnable_source_location(klass, method_name)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
84
|
+
method_source_location = extract_source_location_from_method(klass, method_name)
|
|
85
|
+
klass_source_location = extract_source_location_from_class(klass)
|
|
86
|
+
|
|
87
|
+
if defined?(::Minitest::Spec) && klass&.ancestors&.include?(::Minitest::Spec)
|
|
88
|
+
method_source_location || klass_source_location
|
|
89
|
+
else
|
|
90
|
+
klass_source_location || method_source_location
|
|
59
91
|
end
|
|
60
|
-
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def self.skip_test_suite(test_suite)
|
|
95
|
+
test_suite&.finish
|
|
96
|
+
[]
|
|
61
97
|
end
|
|
62
98
|
|
|
63
99
|
def self.parallel?(klass)
|
|
@@ -69,9 +105,21 @@ module Datadog
|
|
|
69
105
|
end
|
|
70
106
|
|
|
71
107
|
def self.extract_source_location_from_class(klass)
|
|
72
|
-
return
|
|
108
|
+
return nil if klass.nil? || klass.name.nil?
|
|
73
109
|
|
|
74
|
-
SourceCode::ConstantResolver.safely_get_const_source_location(klass.name)
|
|
110
|
+
empty_source_location_to_nil(SourceCode::ConstantResolver.safely_get_const_source_location(klass.name))
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.extract_source_location_from_method(klass, method_name)
|
|
114
|
+
return nil if klass.nil?
|
|
115
|
+
return nil if method_name.nil? || method_name.empty?
|
|
116
|
+
|
|
117
|
+
empty_source_location_to_nil(klass.instance_method(method_name).source_location)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.empty_source_location_to_nil(source_location)
|
|
121
|
+
return nil if source_location.nil? || source_location.empty?
|
|
122
|
+
source_location
|
|
75
123
|
end
|
|
76
124
|
end
|
|
77
125
|
end
|
|
@@ -10,11 +10,16 @@ module Datadog
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
module ClassMethods
|
|
13
|
+
include Helpers::RunnableClassMethods
|
|
14
|
+
|
|
13
15
|
def run(*args)
|
|
14
16
|
return super unless datadog_configuration[:enabled]
|
|
15
17
|
return super if Helpers.parallel?(self)
|
|
16
18
|
|
|
17
19
|
test_suite = Helpers.start_test_suite(self)
|
|
20
|
+
if test_suite&.should_skip?
|
|
21
|
+
return Helpers.skip_test_suite(test_suite)
|
|
22
|
+
end
|
|
18
23
|
|
|
19
24
|
results = super
|
|
20
25
|
return results unless test_suite
|
|
@@ -10,11 +10,16 @@ module Datadog
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
module ClassMethods
|
|
13
|
+
include Helpers::RunnableClassMethods
|
|
14
|
+
|
|
13
15
|
def run_suite(*args)
|
|
14
16
|
return super unless datadog_configuration[:enabled]
|
|
15
17
|
return super if Helpers.parallel?(self)
|
|
16
18
|
|
|
17
19
|
test_suite = Helpers.start_test_suite(self)
|
|
20
|
+
if test_suite&.should_skip?
|
|
21
|
+
return Helpers.skip_test_suite(test_suite)
|
|
22
|
+
end
|
|
18
23
|
|
|
19
24
|
results = super
|
|
20
25
|
return results unless test_suite
|
|
@@ -37,6 +37,11 @@ module Datadog
|
|
|
37
37
|
|
|
38
38
|
return run_without_datadog_reentry if datadog_run_reentered?
|
|
39
39
|
|
|
40
|
+
test_suite = start_datadog_test_suite_if_parallel
|
|
41
|
+
if test_suite&.should_skip?
|
|
42
|
+
return skip_datadog_suite(test_suite)
|
|
43
|
+
end
|
|
44
|
+
|
|
40
45
|
test_span = start_datadog_test
|
|
41
46
|
return skip_datadog_test(test_span) if test_span&.should_skip?
|
|
42
47
|
|
|
@@ -76,10 +81,6 @@ module Datadog
|
|
|
76
81
|
end
|
|
77
82
|
|
|
78
83
|
def start_datadog_test
|
|
79
|
-
if Helpers.parallel?(self.class)
|
|
80
|
-
Helpers.start_test_suite(self.class)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
84
|
test_suite_name = Helpers.test_suite_name(self.class, name)
|
|
84
85
|
|
|
85
86
|
# @type var tags : Hash[String, String]
|
|
@@ -103,15 +104,17 @@ module Datadog
|
|
|
103
104
|
tags: tags,
|
|
104
105
|
service: datadog_configuration[:service_name]
|
|
105
106
|
)
|
|
106
|
-
# Steep type checker doesn't know that we patched Minitest::Test class definition
|
|
107
|
-
#
|
|
108
|
-
# steep:ignore:start
|
|
109
107
|
test_span&.itr_unskippable! if self.class.dd_suite_unskippable? || self.class.dd_test_unskippable?(name)
|
|
110
|
-
# steep:ignore:end
|
|
111
108
|
|
|
112
109
|
test_span
|
|
113
110
|
end
|
|
114
111
|
|
|
112
|
+
def start_datadog_test_suite_if_parallel
|
|
113
|
+
return unless Helpers.parallel?(self.class)
|
|
114
|
+
|
|
115
|
+
Helpers.start_test_suite(self.class)
|
|
116
|
+
end
|
|
117
|
+
|
|
115
118
|
def skip_datadog_test(test_span)
|
|
116
119
|
time_it do
|
|
117
120
|
capture_exceptions do
|
|
@@ -124,6 +127,16 @@ module Datadog
|
|
|
124
127
|
::Minitest::Result.from(self)
|
|
125
128
|
end
|
|
126
129
|
|
|
130
|
+
def skip_datadog_suite(test_suite)
|
|
131
|
+
time_it do
|
|
132
|
+
capture_exceptions do
|
|
133
|
+
skip(test_suite.datadog_skip_reason)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
::Minitest::Result.from(self)
|
|
138
|
+
end
|
|
139
|
+
|
|
127
140
|
def finish_with_result(span, result_code)
|
|
128
141
|
return unless span
|
|
129
142
|
|
|
@@ -158,25 +171,6 @@ module Datadog
|
|
|
158
171
|
ensure
|
|
159
172
|
super
|
|
160
173
|
end
|
|
161
|
-
|
|
162
|
-
def datadog_itr_unskippable(*args)
|
|
163
|
-
if args.nil? || args.empty?
|
|
164
|
-
@datadog_itr_unskippable_suite = true
|
|
165
|
-
else
|
|
166
|
-
@datadog_itr_unskippable_tests = args
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def dd_suite_unskippable?
|
|
171
|
-
@datadog_itr_unskippable_suite
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def dd_test_unskippable?(test_name)
|
|
175
|
-
tests = @datadog_itr_unskippable_tests
|
|
176
|
-
return false unless tests
|
|
177
|
-
|
|
178
|
-
tests.include?(test_name)
|
|
179
|
-
end
|
|
180
174
|
end
|
|
181
175
|
end
|
|
182
176
|
end
|
|
@@ -29,13 +29,9 @@ module Datadog
|
|
|
29
29
|
return unless defined?(super)
|
|
30
30
|
|
|
31
31
|
patch_only_once.run do
|
|
32
|
-
# There is no way to tell Steep that we prepend these methods to modules that have .patch method
|
|
33
|
-
#
|
|
34
|
-
# steep:ignore:start
|
|
35
32
|
super.tap do
|
|
36
33
|
@patch_successful = true
|
|
37
34
|
end
|
|
38
|
-
# steep:ignore:end
|
|
39
35
|
rescue => e
|
|
40
36
|
on_patch_error(e)
|
|
41
37
|
end
|