datadog-ci 1.28.0 → 1.29.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 +31 -2
- data/lib/datadog/ci/configuration/settings.rb +1 -1
- data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +3 -2
- data/lib/datadog/ci/ext/test.rb +19 -1
- data/lib/datadog/ci/remote/library_settings_client.rb +4 -0
- data/lib/datadog/ci/test.rb +4 -3
- data/lib/datadog/ci/test_impact_analysis/component.rb +1 -1
- data/lib/datadog/ci/test_impact_analysis/skippable.rb +4 -0
- data/lib/datadog/ci/test_management/tests_properties.rb +5 -0
- data/lib/datadog/ci/test_session.rb +6 -1
- data/lib/datadog/ci/test_tracing/known_tests.rb +4 -0
- data/lib/datadog/ci/transport/api/agentless.rb +43 -1
- data/lib/datadog/ci/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ac5578878c72238512be9428c1414a047b03a854d97e71830328683bcff6677c
|
|
4
|
+
data.tar.gz: 6c91bfd2ed06cc0c87f8a4537ca32c100ee9e1f4f825aa10c05971ee320aa7cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0260d48fffd5ad1a63c9859afa4a14025325454437d54fd0fce6518afec538b091a3f49289042f93a0a4a515e03dfc80288a19b11c71dc965e01ce3c47b0824
|
|
7
|
+
data.tar.gz: b2097df46c9cfa6b197c237dc9e80ca022204f1950c91f35870965036a60f9c90be895220a82d4bda73f3a22e20ce30b9261308d349d4519a2eca78f21f897bf
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.29.0] - 2026-05-04
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
* Add _dd.ci.library_configuration_error.* tags on backend errors ([#501][])
|
|
8
|
+
* Add cucumber 11 ([#499][])
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
* Make attempt_to_fix take precedence over quarantine and disabled ([#498][])
|
|
13
|
+
* Log error when Datadog API rejects request due to API key ([#500][])
|
|
14
|
+
* Enable static dependency tracking by default ([#493][])
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
* Handle nil DDTest skippable tests data ([#491][])
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
|
|
22
|
+
* Remove JRuby from the CI matrix ([#494][])
|
|
23
|
+
|
|
3
24
|
## [1.28.0] - 2026-02-16
|
|
4
25
|
|
|
5
26
|
### Added
|
|
@@ -608,7 +629,8 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
|
608
629
|
|
|
609
630
|
- Ruby versions < 2.7 no longer supported ([#8][])
|
|
610
631
|
|
|
611
|
-
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.
|
|
632
|
+
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.29.0...main
|
|
633
|
+
[1.29.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.28.0...v1.29.0
|
|
612
634
|
[1.28.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.27.0...v1.28.0
|
|
613
635
|
[1.27.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.26.0...v1.27.0
|
|
614
636
|
[1.26.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.25.0...v1.26.0
|
|
@@ -862,4 +884,11 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
|
862
884
|
[#463]: https://github.com/DataDog/datadog-ci-rb/issues/463
|
|
863
885
|
[#464]: https://github.com/DataDog/datadog-ci-rb/issues/464
|
|
864
886
|
[#468]: https://github.com/DataDog/datadog-ci-rb/issues/468
|
|
865
|
-
[#473]: https://github.com/DataDog/datadog-ci-rb/issues/473
|
|
887
|
+
[#473]: https://github.com/DataDog/datadog-ci-rb/issues/473
|
|
888
|
+
[#491]: https://github.com/DataDog/datadog-ci-rb/issues/491
|
|
889
|
+
[#493]: https://github.com/DataDog/datadog-ci-rb/issues/493
|
|
890
|
+
[#494]: https://github.com/DataDog/datadog-ci-rb/issues/494
|
|
891
|
+
[#498]: https://github.com/DataDog/datadog-ci-rb/issues/498
|
|
892
|
+
[#499]: https://github.com/DataDog/datadog-ci-rb/issues/499
|
|
893
|
+
[#500]: https://github.com/DataDog/datadog-ci-rb/issues/500
|
|
894
|
+
[#501]: https://github.com/DataDog/datadog-ci-rb/issues/501
|
|
@@ -183,7 +183,7 @@ module Datadog
|
|
|
183
183
|
option :tia_static_dependencies_tracking_enabled do |o|
|
|
184
184
|
o.type :bool
|
|
185
185
|
o.env CI::Ext::Settings::ENV_TIA_STATIC_DEPENDENCIES_TRACKING_ENABLED
|
|
186
|
-
o.default
|
|
186
|
+
o.default true
|
|
187
187
|
end
|
|
188
188
|
|
|
189
189
|
option :code_coverage_report_upload_enabled do |o|
|
|
@@ -39,8 +39,9 @@ module Datadog
|
|
|
39
39
|
def begin_scenario(test_case)
|
|
40
40
|
datadog_test = Datadog::CI.active_test
|
|
41
41
|
|
|
42
|
-
# special case for cucumber-ruby: we skip quarantined tests, thus for cucumber quarantined is the same as disabled
|
|
43
|
-
|
|
42
|
+
# special case for cucumber-ruby: we skip quarantined tests, thus for cucumber quarantined is the same as disabled.
|
|
43
|
+
# attempt_to_fix takes precedence over quarantine: such tests must run (and be retried) even when quarantined.
|
|
44
|
+
if datadog_test&.should_skip? || (datadog_test&.quarantined? && !datadog_test.attempt_to_fix?)
|
|
44
45
|
raise ::Cucumber::Core::Test::Result::Skipped, datadog_test.datadog_skip_reason
|
|
45
46
|
end
|
|
46
47
|
|
data/lib/datadog/ci/ext/test.rb
CHANGED
|
@@ -93,6 +93,17 @@ module Datadog
|
|
|
93
93
|
TAG_HAS_FAILED_ALL_RETRIES = "test.has_failed_all_retries" # true if test was retried and none of the retries passed
|
|
94
94
|
TAG_ATTEMPT_TO_FIX_PASSED = "test.test_management.attempt_to_fix_passed" # true if test was marked as "attempted to fix" and all of the retries passed
|
|
95
95
|
|
|
96
|
+
# Hidden tags used to indicate that a communication error occurred with the backend
|
|
97
|
+
# during one of the library configuration requests. They are propagated to every CI event
|
|
98
|
+
# (test session, test module, test suite, test) so that the backend can detect when
|
|
99
|
+
# data may be incomplete because the library could not load configuration.
|
|
100
|
+
module LibraryConfigurationError
|
|
101
|
+
TAG_SETTINGS = "_dd.ci.library_configuration_error.settings"
|
|
102
|
+
TAG_SKIPPABLE_TESTS = "_dd.ci.library_configuration_error.skippable_tests"
|
|
103
|
+
TAG_KNOWN_TESTS = "_dd.ci.library_configuration_error.known_tests"
|
|
104
|
+
TAG_TEST_MANAGEMENT_TESTS = "_dd.ci.library_configuration_error.test_management_tests"
|
|
105
|
+
end
|
|
106
|
+
|
|
96
107
|
# a set of tag indicating which capabilities (features) are supported by the library
|
|
97
108
|
module LibraryCapabilities
|
|
98
109
|
TAG_TEST_IMPACT_ANALYSIS = "_dd.library_capabilities.test_impact_analysis"
|
|
@@ -140,7 +151,14 @@ module Datadog
|
|
|
140
151
|
METRIC_CPU_COUNT = "_dd.host.vcpu_count"
|
|
141
152
|
|
|
142
153
|
# tags that are common for the whole session and can be inherited from the test session
|
|
143
|
-
INHERITABLE_TAGS = [
|
|
154
|
+
INHERITABLE_TAGS = [
|
|
155
|
+
TAG_FRAMEWORK,
|
|
156
|
+
TAG_FRAMEWORK_VERSION,
|
|
157
|
+
LibraryConfigurationError::TAG_SETTINGS,
|
|
158
|
+
LibraryConfigurationError::TAG_SKIPPABLE_TESTS,
|
|
159
|
+
LibraryConfigurationError::TAG_KNOWN_TESTS,
|
|
160
|
+
LibraryConfigurationError::TAG_TEST_MANAGEMENT_TESTS
|
|
161
|
+
].freeze
|
|
144
162
|
|
|
145
163
|
# could be either "test" or "suite" depending on whether we skip individual tests or whole suites
|
|
146
164
|
ITR_TEST_SKIPPING_MODE = "test" # we always skip tests (not suites) in Ruby
|
|
@@ -49,6 +49,10 @@ module Datadog
|
|
|
49
49
|
error_type: http_response.telemetry_error_type,
|
|
50
50
|
status_code: http_response.code
|
|
51
51
|
)
|
|
52
|
+
|
|
53
|
+
# mark the test session so that all events emitted in this session are tagged
|
|
54
|
+
# with the hidden _dd.ci.library_configuration_error.settings tag
|
|
55
|
+
test_session.set_tag(Ext::Test::LibraryConfigurationError::TAG_SETTINGS, "true")
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
library_settings = LibrarySettings.from_http_response(http_response)
|
data/lib/datadog/ci/test.rb
CHANGED
|
@@ -235,8 +235,8 @@ module Datadog
|
|
|
235
235
|
|
|
236
236
|
# @internal
|
|
237
237
|
def should_ignore_failures?
|
|
238
|
-
return true if quarantined? || disabled?
|
|
239
238
|
return false if attempt_to_fix?
|
|
239
|
+
return true if quarantined? || disabled?
|
|
240
240
|
|
|
241
241
|
any_retry_passed?
|
|
242
242
|
end
|
|
@@ -271,8 +271,9 @@ module Datadog
|
|
|
271
271
|
# Skip status is always preserved
|
|
272
272
|
return status if status == Ext::Test::Status::SKIP
|
|
273
273
|
|
|
274
|
-
#
|
|
275
|
-
|
|
274
|
+
# attempt_to_fix takes precedence over quarantine/disabled flags:
|
|
275
|
+
# any failure across attempts means the fix didn't work.
|
|
276
|
+
if attempt_to_fix?
|
|
276
277
|
return all_executions_passed? ? Ext::Test::Status::PASS : Ext::Test::Status::FAIL
|
|
277
278
|
end
|
|
278
279
|
|
|
@@ -381,7 +381,7 @@ module Datadog
|
|
|
381
381
|
# "data": [{"type": "test", "attributes": {"suite": "suite_name", "name": "test_name", "parameters": "{...}"}}]
|
|
382
382
|
# }
|
|
383
383
|
def transform_test_runner_data(skippable_tests_data)
|
|
384
|
-
skippable_tests = skippable_tests_data.fetch("skippableTests", {})
|
|
384
|
+
skippable_tests = skippable_tests_data.fetch("skippableTests", {}) || {}
|
|
385
385
|
|
|
386
386
|
# Pre-calculate array size for better memory allocation
|
|
387
387
|
total_test_configs = skippable_tests.sum do |_, tests_hash|
|
|
@@ -111,6 +111,10 @@ module Datadog
|
|
|
111
111
|
error_type: http_response.telemetry_error_type,
|
|
112
112
|
status_code: http_response.code
|
|
113
113
|
)
|
|
114
|
+
|
|
115
|
+
# mark the test session so that all events emitted in this session are tagged
|
|
116
|
+
# with the hidden _dd.ci.library_configuration_error.skippable_tests tag
|
|
117
|
+
test_session.set_tag(Ext::Test::LibraryConfigurationError::TAG_SKIPPABLE_TESTS, "true")
|
|
114
118
|
end
|
|
115
119
|
|
|
116
120
|
Response.from_http_response(http_response)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
5
|
require_relative "../ext/telemetry"
|
|
6
|
+
require_relative "../ext/test"
|
|
6
7
|
require_relative "../ext/transport"
|
|
7
8
|
require_relative "../transport/telemetry"
|
|
8
9
|
require_relative "../utils/parsing"
|
|
@@ -112,6 +113,10 @@ module Datadog
|
|
|
112
113
|
error_type: http_response.telemetry_error_type,
|
|
113
114
|
status_code: http_response.code
|
|
114
115
|
)
|
|
116
|
+
|
|
117
|
+
# mark the test session so that all events emitted in this session are tagged
|
|
118
|
+
# with the hidden _dd.ci.library_configuration_error.test_management_tests tag
|
|
119
|
+
test_session.set_tag(Ext::Test::LibraryConfigurationError::TAG_TEST_MANAGEMENT_TESTS, "true")
|
|
115
120
|
end
|
|
116
121
|
|
|
117
122
|
Response.from_http_response(http_response).tests
|
|
@@ -63,7 +63,12 @@ module Datadog
|
|
|
63
63
|
# uses synchronized method #get_tag to get each tag value
|
|
64
64
|
res = {}
|
|
65
65
|
Ext::Test::INHERITABLE_TAGS.each do |tag|
|
|
66
|
-
|
|
66
|
+
value = get_tag(tag)
|
|
67
|
+
# skip tags that are not set on the session (e.g. library configuration error tags
|
|
68
|
+
# are only set when the corresponding backend request fails)
|
|
69
|
+
next if value.nil?
|
|
70
|
+
|
|
71
|
+
res[tag] = value
|
|
67
72
|
end
|
|
68
73
|
@inheritable_tags = res.freeze
|
|
69
74
|
end
|
|
@@ -103,6 +103,10 @@ module Datadog
|
|
|
103
103
|
response = fetch_page(api, test_session, page_state: page_state)
|
|
104
104
|
|
|
105
105
|
unless response.ok?
|
|
106
|
+
# mark the test session so that all events emitted in this session are tagged
|
|
107
|
+
# with the hidden _dd.ci.library_configuration_error.known_tests tag
|
|
108
|
+
test_session.set_tag(Ext::Test::LibraryConfigurationError::TAG_KNOWN_TESTS, "true")
|
|
109
|
+
|
|
106
110
|
Datadog.logger.debug(
|
|
107
111
|
"Failed to fetch known tests page ##{page_number}, bailing out of known tests fetch. " \
|
|
108
112
|
"Early flake detection will not work."
|
|
@@ -10,6 +10,18 @@ module Datadog
|
|
|
10
10
|
class Agentless < Base
|
|
11
11
|
attr_reader :api_key
|
|
12
12
|
|
|
13
|
+
# HTTP status codes returned by the Datadog backend when a request is
|
|
14
|
+
# rejected for authentication/authorization reasons (typically because
|
|
15
|
+
# of a missing or invalid DD_API_KEY).
|
|
16
|
+
AUTHENTICATION_ERROR_CODES = [401, 403].freeze
|
|
17
|
+
|
|
18
|
+
# Substring we look for in the response payload to confirm the
|
|
19
|
+
# rejection is API-key related rather than some other permission
|
|
20
|
+
# issue. Examples of payloads we want to match:
|
|
21
|
+
# {"errors":[{"status":"403","title":"Forbidden","detail":"API key is missing"}]}
|
|
22
|
+
# {"errors":[{"status":"403","title":"Forbidden","detail":"API key is invalid"}]}
|
|
23
|
+
API_KEY_ERROR_PAYLOAD_MARKER = "API key"
|
|
24
|
+
|
|
13
25
|
def initialize(api_key:, citestcycle_url:, api_url:, citestcov_url:, logs_intake_url:, cicovreprt_url:)
|
|
14
26
|
@api_key = api_key
|
|
15
27
|
@citestcycle_http = build_http_client(citestcycle_url, compress: true)
|
|
@@ -17,6 +29,7 @@ module Datadog
|
|
|
17
29
|
@citestcov_http = build_http_client(citestcov_url, compress: true)
|
|
18
30
|
@logs_intake_http = build_http_client(logs_intake_url, compress: true)
|
|
19
31
|
@cicovreprt_http = build_http_client(cicovreprt_url, compress: false)
|
|
32
|
+
@api_key_error_logged = false
|
|
20
33
|
end
|
|
21
34
|
|
|
22
35
|
def citestcycle_request(path:, payload:, headers: {}, verb: "post")
|
|
@@ -59,13 +72,42 @@ module Datadog
|
|
|
59
72
|
private
|
|
60
73
|
|
|
61
74
|
def perform_request(http_client, path:, payload:, headers:, verb:, accept_compressed_response: false)
|
|
62
|
-
http_client.request(
|
|
75
|
+
response = http_client.request(
|
|
63
76
|
path: path,
|
|
64
77
|
payload: payload,
|
|
65
78
|
headers: headers_with_default(headers),
|
|
66
79
|
verb: verb,
|
|
67
80
|
accept_compressed_response: accept_compressed_response
|
|
68
81
|
)
|
|
82
|
+
|
|
83
|
+
log_api_key_error(response)
|
|
84
|
+
|
|
85
|
+
response
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def log_api_key_error(response)
|
|
89
|
+
return if @api_key_error_logged
|
|
90
|
+
return unless AUTHENTICATION_ERROR_CODES.include?(response.code)
|
|
91
|
+
return unless response.payload.to_s.include?(API_KEY_ERROR_PAYLOAD_MARKER)
|
|
92
|
+
|
|
93
|
+
@api_key_error_logged = true
|
|
94
|
+
|
|
95
|
+
if api_key.nil? || api_key.strip.empty?
|
|
96
|
+
Datadog.logger.error do
|
|
97
|
+
"DATADOG CONFIGURATION - TEST OPTIMIZATION - ATTENTION - " \
|
|
98
|
+
"Datadog API rejected the request because DD_API_KEY is not set. " \
|
|
99
|
+
"Please set DD_API_KEY environment variable to a valid Datadog API key. " \
|
|
100
|
+
"Server response: #{response.payload}"
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
Datadog.logger.error do
|
|
104
|
+
"DATADOG CONFIGURATION - TEST OPTIMIZATION - ATTENTION - " \
|
|
105
|
+
"Datadog API rejected the request because the configured DD_API_KEY is invalid. " \
|
|
106
|
+
"Please verify that DD_API_KEY environment variable is set to a valid Datadog API key " \
|
|
107
|
+
"for the configured DD_SITE. " \
|
|
108
|
+
"Server response: #{response.payload}"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
69
111
|
end
|
|
70
112
|
|
|
71
113
|
def build_http_client(url, compress:)
|
data/lib/datadog/ci/version.rb
CHANGED