datadog-ci 0.7.0 → 0.8.3
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 +50 -1
- data/README.md +39 -1
- data/lib/datadog/ci/configuration/components.rb +56 -54
- data/lib/datadog/ci/configuration/settings.rb +6 -0
- data/lib/datadog/ci/contrib/cucumber/formatter.rb +13 -3
- data/lib/datadog/ci/contrib/minitest/helpers.rb +15 -1
- data/lib/datadog/ci/contrib/minitest/runner.rb +2 -2
- data/lib/datadog/ci/contrib/rspec/runner.rb +1 -2
- data/lib/datadog/ci/ext/environment/extractor.rb +3 -2
- data/lib/datadog/ci/ext/environment/providers/github_actions.rb +3 -2
- data/lib/datadog/ci/ext/settings.rb +1 -0
- data/lib/datadog/ci/ext/test.rb +11 -0
- data/lib/datadog/ci/ext/transport.rb +19 -1
- data/lib/datadog/ci/itr/runner.rb +67 -0
- data/lib/datadog/ci/span.rb +42 -0
- data/lib/datadog/ci/test_session.rb +8 -0
- data/lib/datadog/ci/test_visibility/context/global.rb +8 -0
- data/lib/datadog/ci/test_visibility/recorder.rb +45 -2
- data/lib/datadog/ci/test_visibility/transport.rb +1 -5
- data/lib/datadog/ci/transport/api/agentless.rb +63 -0
- data/lib/datadog/ci/transport/api/base.rb +10 -14
- data/lib/datadog/ci/transport/api/builder.rb +25 -21
- data/lib/datadog/ci/transport/api/evp_proxy.rb +47 -7
- data/lib/datadog/ci/transport/http.rb +7 -1
- data/lib/datadog/ci/transport/remote_settings_api.rb +96 -0
- data/lib/datadog/ci/version.rb +2 -2
- metadata +6 -5
- data/lib/datadog/ci/transport/api/ci_test_cycle.rb +0 -30
- data/lib/datadog/ci/utils/url.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf750f24412b0800ba1599f22c5b12e8679dddc1d0e9a30aed98d0a51a6badd3
|
4
|
+
data.tar.gz: 652631fac9702beb340f136e32d4b72b3b38d7c84a8de7dc8ce4f203dc67983b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3295d136609aca4be41cc041613873297a5e91bb37a428a6612a1e62f7e547db2bb2c836f4a0348fdd4466d085a29ec78a26962d48f1c59e05163dcb26668783
|
7
|
+
data.tar.gz: 5446bba62689a4133a75b64437efd47f8369814e863c8ddab0c91d52692b5bf71b5be2a4f4264839ec81374ff3c4ff498e4c2cd7a8c54f566e63558cb1f55cff
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,42 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.8.3] - 2024-03-20
|
4
|
+
|
5
|
+
### Fixed
|
6
|
+
|
7
|
+
* fix: cucumber-ruby 9.2 includes breaking change for Cucumber::Core::Test::Result ([#145][])
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
* remove temporary hack and use Core::Remote::Negotiation's new constructor param ([#142][])
|
12
|
+
* use filter_basic_auth method from Datadog::Core ([#141][])
|
13
|
+
|
14
|
+
## [0.8.2] - 2024-03-19
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
|
18
|
+
* assign the single running test suite for a test if none found by test suite name ([#139][])
|
19
|
+
|
20
|
+
## [0.8.1] - 2024-03-12
|
21
|
+
|
22
|
+
### Fixed
|
23
|
+
|
24
|
+
* fix minitest instrumentation with mixins ([#134][])
|
25
|
+
|
26
|
+
## [0.8.0] - 2024-03-08
|
27
|
+
|
28
|
+
### Added
|
29
|
+
|
30
|
+
* gzip agent payloads support via evp_proxy/v4 ([#123][])
|
31
|
+
|
32
|
+
### Changed
|
33
|
+
|
34
|
+
* Add note to README on using VCR ([#122][])
|
35
|
+
|
36
|
+
### Fixed
|
37
|
+
|
38
|
+
* use framework name as test module name to make test fingerprints stable ([#131][])
|
39
|
+
|
3
40
|
## [0.7.0] - 2024-01-26
|
4
41
|
|
5
42
|
### Added
|
@@ -150,7 +187,11 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
150
187
|
|
151
188
|
* Ruby versions < 2.7 no longer supported ([#8][])
|
152
189
|
|
153
|
-
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v0.
|
190
|
+
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v0.8.3...main
|
191
|
+
[0.8.3]: https://github.com/DataDog/datadog-ci-rb/compare/v0.8.2...v0.8.3
|
192
|
+
[0.8.2]: https://github.com/DataDog/datadog-ci-rb/compare/v0.8.1...v0.8.2
|
193
|
+
[0.8.1]: https://github.com/DataDog/datadog-ci-rb/compare/v0.8.0...v0.8.1
|
194
|
+
[0.8.0]: https://github.com/DataDog/datadog-ci-rb/compare/v0.7.0...v0.8.0
|
154
195
|
[0.7.0]: https://github.com/DataDog/datadog-ci-rb/compare/v0.6.0...v0.7.0
|
155
196
|
[0.6.0]: https://github.com/DataDog/datadog-ci-rb/compare/v0.5.1...v0.6.0
|
156
197
|
[0.5.1]: https://github.com/DataDog/datadog-ci-rb/compare/v0.5.0...v0.5.1
|
@@ -213,3 +254,11 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
213
254
|
[#113]: https://github.com/DataDog/datadog-ci-rb/issues/113
|
214
255
|
[#114]: https://github.com/DataDog/datadog-ci-rb/issues/114
|
215
256
|
[#115]: https://github.com/DataDog/datadog-ci-rb/issues/115
|
257
|
+
[#122]: https://github.com/DataDog/datadog-ci-rb/issues/122
|
258
|
+
[#123]: https://github.com/DataDog/datadog-ci-rb/issues/123
|
259
|
+
[#131]: https://github.com/DataDog/datadog-ci-rb/issues/131
|
260
|
+
[#134]: https://github.com/DataDog/datadog-ci-rb/issues/134
|
261
|
+
[#139]: https://github.com/DataDog/datadog-ci-rb/issues/139
|
262
|
+
[#141]: https://github.com/DataDog/datadog-ci-rb/issues/141
|
263
|
+
[#142]: https://github.com/DataDog/datadog-ci-rb/issues/142
|
264
|
+
[#145]: https://github.com/DataDog/datadog-ci-rb/issues/145
|
data/README.md
CHANGED
@@ -79,6 +79,25 @@ if ENV["DD_ENV"] == "ci"
|
|
79
79
|
end
|
80
80
|
```
|
81
81
|
|
82
|
+
> [!IMPORTANT]
|
83
|
+
> When using `minitest/autorun` the order of requires matters: `datadog/ci` must be
|
84
|
+
> always required before `minitest/autorun`.
|
85
|
+
|
86
|
+
Example using `minitest/autorun`
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
require 'datadog/ci'
|
90
|
+
require 'minitest/autorun'
|
91
|
+
|
92
|
+
if ENV["DD_ENV"] == "ci"
|
93
|
+
Datadog.configure do |c|
|
94
|
+
c.ci.enabled = true
|
95
|
+
c.service = 'my-ruby-app'
|
96
|
+
c.ci.instrument :minitest
|
97
|
+
end
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
82
101
|
`options` are the following keyword arguments:
|
83
102
|
|
84
103
|
| Key | Description | Default |
|
@@ -175,7 +194,7 @@ Webmock accordingly.
|
|
175
194
|
```ruby
|
176
195
|
# when using agentless mode
|
177
196
|
# note to use the correct datadog site (e.g. datadoghq.eu, etc)
|
178
|
-
WebMock.disable_net_connect!(:allow =>
|
197
|
+
WebMock.disable_net_connect!(:allow => /datadoghq.com/)
|
179
198
|
|
180
199
|
# when using agent
|
181
200
|
WebMock.disable_net_connect!(:allow_localhost => true)
|
@@ -184,6 +203,25 @@ WebMock.disable_net_connect!(:allow_localhost => true)
|
|
184
203
|
WebMock.disable_net_connect!(:allow => "localhost:8126")
|
185
204
|
```
|
186
205
|
|
206
|
+
### VCR
|
207
|
+
|
208
|
+
[VCR](https://github.com/vcr/vcr) is another popular testing library for HTTP interactions.
|
209
|
+
|
210
|
+
It requires additional configuration to correctly work with datadog-ci:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
VCR.configure do |config|
|
214
|
+
# ... your usual configuration here ...
|
215
|
+
|
216
|
+
# when using agent
|
217
|
+
config.ignore_hosts "127.0.0.1", "localhost"
|
218
|
+
|
219
|
+
# when using agentless mode
|
220
|
+
# note to use the correct datadog site (e.g. datadoghq.eu, etc)
|
221
|
+
config.ignore_hosts "citestcycle-intake.datadoghq.com", "api.datadoghq.com"
|
222
|
+
end
|
223
|
+
```
|
224
|
+
|
187
225
|
### Disabling startup logs
|
188
226
|
|
189
227
|
Startup logs produce a report of tracing state when the application is initially configured.
|
@@ -1,10 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "datadog/core/configuration/agent_settings_resolver"
|
4
|
-
require "datadog/core/remote/negotiation"
|
5
|
-
|
6
|
-
require_relative "../ext/transport"
|
7
3
|
require_relative "../ext/settings"
|
4
|
+
require_relative "../itr/runner"
|
8
5
|
require_relative "../test_visibility/flush"
|
9
6
|
require_relative "../test_visibility/recorder"
|
10
7
|
require_relative "../test_visibility/null_recorder"
|
@@ -12,6 +9,7 @@ require_relative "../test_visibility/serializers/factories/test_level"
|
|
12
9
|
require_relative "../test_visibility/serializers/factories/test_suite_level"
|
13
10
|
require_relative "../test_visibility/transport"
|
14
11
|
require_relative "../transport/api/builder"
|
12
|
+
require_relative "../transport/remote_settings_api"
|
15
13
|
|
16
14
|
module Datadog
|
17
15
|
module CI
|
@@ -32,18 +30,7 @@ module Datadog
|
|
32
30
|
end
|
33
31
|
|
34
32
|
def activate_ci!(settings)
|
35
|
-
|
36
|
-
agent_settings = Datadog::Core::Configuration::AgentSettingsResolver.call(settings)
|
37
|
-
|
38
|
-
if settings.ci.agentless_mode_enabled
|
39
|
-
check_dd_site(settings)
|
40
|
-
test_visibility_transport = build_agentless_transport(settings)
|
41
|
-
elsif can_use_evp_proxy?(settings, agent_settings)
|
42
|
-
test_visibility_transport = build_evp_proxy_transport(settings, agent_settings)
|
43
|
-
else
|
44
|
-
settings.ci.force_test_level_visibility = true
|
45
|
-
end
|
46
|
-
|
33
|
+
# Configure ddtrace library for CI visibility mode
|
47
34
|
# Deactivate telemetry
|
48
35
|
settings.telemetry.enabled = false
|
49
36
|
|
@@ -60,62 +47,77 @@ module Datadog
|
|
60
47
|
# Choose user defined TraceFlush or default to CI TraceFlush
|
61
48
|
settings.tracing.test_mode.trace_flush = settings.ci.trace_flush || CI::TestVisibility::Flush::Partial.new
|
62
49
|
|
50
|
+
# transport creation
|
63
51
|
writer_options = settings.ci.writer_options
|
64
|
-
|
65
|
-
|
52
|
+
test_visibility_api = build_test_visibility_api(settings)
|
53
|
+
|
54
|
+
if test_visibility_api
|
55
|
+
writer_options[:transport] = Datadog::CI::TestVisibility::Transport.new(
|
56
|
+
api: test_visibility_api,
|
57
|
+
serializers_factory: serializers_factory(settings),
|
58
|
+
dd_env: settings.env
|
59
|
+
)
|
66
60
|
writer_options[:shutdown_timeout] = 60
|
67
61
|
writer_options[:buffer_size] = 10_000
|
68
62
|
|
69
63
|
settings.tracing.test_mode.async = true
|
64
|
+
else
|
65
|
+
# only legacy APM protocol is supported, so no test suite level visibility
|
66
|
+
settings.ci.force_test_level_visibility = true
|
67
|
+
|
68
|
+
# ITR is not supported with APM protocol
|
69
|
+
settings.ci.itr_enabled = false
|
70
70
|
end
|
71
71
|
|
72
72
|
settings.tracing.test_mode.writer_options = writer_options
|
73
73
|
|
74
|
-
|
75
|
-
|
74
|
+
itr = Datadog::CI::ITR::Runner.new(
|
75
|
+
enabled: settings.ci.enabled && settings.ci.itr_enabled
|
76
76
|
)
|
77
|
-
end
|
78
77
|
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
remote_settings_api = Transport::RemoteSettingsApi.new(
|
79
|
+
api: test_visibility_api,
|
80
|
+
dd_env: settings.env
|
81
|
+
)
|
82
|
+
|
83
|
+
# CI visibility recorder global instance
|
84
|
+
@ci_recorder = TestVisibility::Recorder.new(
|
85
|
+
test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility,
|
86
|
+
itr: itr,
|
87
|
+
remote_settings_api: remote_settings_api
|
82
88
|
)
|
83
89
|
end
|
84
90
|
|
85
|
-
def
|
86
|
-
if settings.
|
87
|
-
|
88
|
-
# we cannot continue and log an error
|
89
|
-
# Tests are running without CI visibility enabled
|
91
|
+
def build_test_visibility_api(settings)
|
92
|
+
if settings.ci.agentless_mode_enabled
|
93
|
+
check_dd_site(settings)
|
90
94
|
|
91
|
-
Datadog.logger.
|
92
|
-
"DATADOG CONFIGURATION - CI VISIBILITY - ATTENTION - " \
|
93
|
-
"Agentless mode was enabled but DD_API_KEY is not set: CI visibility is disabled. " \
|
94
|
-
"Please make sure to set valid api key in DD_API_KEY environment variable"
|
95
|
-
)
|
95
|
+
Datadog.logger.debug("CI visibility configured to use agentless transport")
|
96
96
|
|
97
|
-
|
97
|
+
api = Transport::Api::Builder.build_agentless_api(settings)
|
98
|
+
if api.nil?
|
99
|
+
Datadog.logger.error do
|
100
|
+
"DATADOG CONFIGURATION - CI VISIBILITY - ATTENTION - " \
|
101
|
+
"Agentless mode was enabled but DD_API_KEY is not set: CI visibility is disabled. " \
|
102
|
+
"Please make sure to set valid api key in DD_API_KEY environment variable"
|
103
|
+
end
|
98
104
|
|
99
|
-
|
100
|
-
|
101
|
-
|
105
|
+
# Tests are running without CI visibility enabled
|
106
|
+
settings.ci.enabled = false
|
107
|
+
end
|
102
108
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
109
|
+
else
|
110
|
+
Datadog.logger.debug("CI visibility configured to use agent transport via EVP proxy")
|
111
|
+
|
112
|
+
api = Transport::Api::Builder.build_evp_proxy_api(settings)
|
113
|
+
if api.nil?
|
114
|
+
Datadog.logger.debug(
|
115
|
+
"Old agent version detected, no evp_proxy support. Forcing test level visibility mode"
|
116
|
+
)
|
117
|
+
end
|
108
118
|
end
|
109
|
-
end
|
110
|
-
|
111
|
-
def build_evp_proxy_transport(settings, agent_settings)
|
112
|
-
Datadog.logger.debug("CI visibility configured to use agent transport via EVP proxy")
|
113
119
|
|
114
|
-
|
115
|
-
api: Transport::Api::Builder.build_evp_proxy_api(agent_settings),
|
116
|
-
serializers_factory: serializers_factory(settings),
|
117
|
-
dd_env: settings.env
|
118
|
-
)
|
120
|
+
api
|
119
121
|
end
|
120
122
|
|
121
123
|
def serializers_factory(settings)
|
@@ -130,11 +132,11 @@ module Datadog
|
|
130
132
|
return if settings.site.nil?
|
131
133
|
return if Ext::Settings::DD_SITE_ALLOWLIST.include?(settings.site)
|
132
134
|
|
133
|
-
Datadog.logger.warn
|
135
|
+
Datadog.logger.warn do
|
134
136
|
"CI VISIBILITY CONFIGURATION " \
|
135
137
|
"Agentless mode was enabled but DD_SITE is not set to one of the following: #{Ext::Settings::DD_SITE_ALLOWLIST.join(", ")}. " \
|
136
138
|
"Please make sure to set valid site in DD_SITE environment variable"
|
137
|
-
|
139
|
+
end
|
138
140
|
end
|
139
141
|
end
|
140
142
|
end
|
@@ -55,6 +55,12 @@ module Datadog
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
option :itr_enabled do |o|
|
59
|
+
o.type :bool
|
60
|
+
o.env CI::Ext::Settings::ENV_ITR_ENABLED
|
61
|
+
o.default false
|
62
|
+
end
|
63
|
+
|
58
64
|
define_method(:instrument) do |integration_name, options = {}, &block|
|
59
65
|
return unless enabled
|
60
66
|
|
@@ -34,14 +34,14 @@ module Datadog
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def on_test_run_started(event)
|
37
|
-
|
37
|
+
CI.start_test_session(
|
38
38
|
tags: {
|
39
39
|
CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
|
40
40
|
CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::Cucumber::Integration.version.to_s
|
41
41
|
},
|
42
42
|
service: configuration[:service_name]
|
43
43
|
)
|
44
|
-
CI.start_test_module(
|
44
|
+
CI.start_test_module(Ext::FRAMEWORK)
|
45
45
|
end
|
46
46
|
|
47
47
|
def on_test_run_finished(event)
|
@@ -113,7 +113,7 @@ module Datadog
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def finish_span(span, result)
|
116
|
-
if !result.passed? &&
|
116
|
+
if !result.passed? && ok?(result, @config.strict)
|
117
117
|
span.skipped!(reason: result.message)
|
118
118
|
elsif result.passed?
|
119
119
|
span.passed!
|
@@ -186,6 +186,16 @@ module Datadog
|
|
186
186
|
nil
|
187
187
|
end
|
188
188
|
|
189
|
+
def ok?(result, strict)
|
190
|
+
# in minor update in Cucumber 9.2.0, the arity of the `ok?` method changed
|
191
|
+
parameters = result.method(:ok?).parameters
|
192
|
+
if parameters == [[:opt, :be_strict]]
|
193
|
+
result.ok?(strict)
|
194
|
+
else
|
195
|
+
result.ok?(strict: strict)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
189
199
|
def configuration
|
190
200
|
Datadog.configuration.ci[:cucumber]
|
191
201
|
end
|
@@ -6,7 +6,12 @@ module Datadog
|
|
6
6
|
module Minitest
|
7
7
|
module Helpers
|
8
8
|
def self.test_suite_name(klass, method_name)
|
9
|
-
source_location
|
9
|
+
source_location = extract_source_location_from_class(klass)
|
10
|
+
# if we are in anonymous class, fallback to the method source location
|
11
|
+
if source_location.nil?
|
12
|
+
source_location, = klass.instance_method(method_name).source_location
|
13
|
+
end
|
14
|
+
|
10
15
|
source_file_path = Pathname.new(source_location.to_s).relative_path_from(Pathname.pwd).to_s
|
11
16
|
|
12
17
|
"#{klass.name} at #{source_file_path}"
|
@@ -16,6 +21,15 @@ module Datadog
|
|
16
21
|
klass.ancestors.include?(::Minitest::Parallel::Test) ||
|
17
22
|
(defined?(::Minitest::Queue) && ::Minitest.singleton_class.ancestors.include?(::Minitest::Queue))
|
18
23
|
end
|
24
|
+
|
25
|
+
def self.extract_source_location_from_class(klass)
|
26
|
+
return nil if klass.nil? || klass.name.nil?
|
27
|
+
|
28
|
+
source_location = klass.const_source_location(klass.name)
|
29
|
+
source_location.first unless source_location.nil?
|
30
|
+
rescue
|
31
|
+
nil
|
32
|
+
end
|
19
33
|
end
|
20
34
|
end
|
21
35
|
end
|
@@ -18,14 +18,14 @@ module Datadog
|
|
18
18
|
|
19
19
|
return unless datadog_configuration[:enabled]
|
20
20
|
|
21
|
-
|
21
|
+
CI.start_test_session(
|
22
22
|
tags: {
|
23
23
|
CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
|
24
24
|
CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::Minitest::Integration.version.to_s
|
25
25
|
},
|
26
26
|
service: datadog_configuration[:service_name]
|
27
27
|
)
|
28
|
-
CI.start_test_module(
|
28
|
+
CI.start_test_module(Ext::FRAMEWORK)
|
29
29
|
end
|
30
30
|
|
31
31
|
private
|
@@ -25,13 +25,12 @@ module Datadog
|
|
25
25
|
service: datadog_configuration[:service_name]
|
26
26
|
)
|
27
27
|
|
28
|
-
test_module = CI.start_test_module(
|
28
|
+
test_module = CI.start_test_module(Ext::FRAMEWORK)
|
29
29
|
|
30
30
|
result = super
|
31
31
|
return result unless test_module && test_session
|
32
32
|
|
33
33
|
if result != 0
|
34
|
-
# TODO: repeating this twice feels clunky, we need to remove test_module API before GA
|
35
34
|
test_module.failed!
|
36
35
|
test_session.failed!
|
37
36
|
else
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "datadog/core/utils/url"
|
4
|
+
|
3
5
|
require_relative "../git"
|
4
6
|
require_relative "../../utils/git"
|
5
|
-
require_relative "../../utils/url"
|
6
7
|
require_relative "providers"
|
7
8
|
|
8
9
|
module Datadog
|
@@ -76,7 +77,7 @@ module Datadog
|
|
76
77
|
|
77
78
|
@tags[Git::TAG_TAG] = Utils::Git.normalize_ref(@tags[Git::TAG_TAG])
|
78
79
|
@tags[Git::TAG_BRANCH] = Utils::Git.normalize_ref(@tags[Git::TAG_BRANCH])
|
79
|
-
@tags[Git::TAG_REPOSITORY_URL] = Utils::Url.
|
80
|
+
@tags[Git::TAG_REPOSITORY_URL] = Datadog::Core::Utils::Url.filter_basic_auth(
|
80
81
|
@tags[Git::TAG_REPOSITORY_URL]
|
81
82
|
)
|
82
83
|
end
|
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
require "json"
|
4
4
|
|
5
|
+
require "datadog/core/utils/url"
|
6
|
+
|
5
7
|
require_relative "base"
|
6
|
-
require_relative "../../../utils/url"
|
7
8
|
|
8
9
|
module Datadog
|
9
10
|
module CI
|
@@ -79,7 +80,7 @@ module Datadog
|
|
79
80
|
def github_server_url
|
80
81
|
return @github_server_url if defined?(@github_server_url)
|
81
82
|
|
82
|
-
@github_server_url ||= Utils::Url.
|
83
|
+
@github_server_url ||= Datadog::Core::Utils::Url.filter_basic_auth(env["GITHUB_SERVER_URL"])
|
83
84
|
end
|
84
85
|
end
|
85
86
|
end
|
@@ -10,6 +10,7 @@ module Datadog
|
|
10
10
|
ENV_AGENTLESS_URL = "DD_CIVISIBILITY_AGENTLESS_URL"
|
11
11
|
ENV_EXPERIMENTAL_TEST_SUITE_LEVEL_VISIBILITY_ENABLED = "DD_CIVISIBILITY_EXPERIMENTAL_TEST_SUITE_LEVEL_VISIBILITY_ENABLED"
|
12
12
|
ENV_FORCE_TEST_LEVEL_VISIBILITY = "DD_CIVISIBILITY_FORCE_TEST_LEVEL_VISIBILITY"
|
13
|
+
ENV_ITR_ENABLED = "DD_CIVISIBILITY_ITR_ENABLED"
|
13
14
|
|
14
15
|
# Source: https://docs.datadoghq.com/getting_started/site/
|
15
16
|
DD_SITE_ALLOWLIST = [
|
data/lib/datadog/ci/ext/test.rb
CHANGED
@@ -23,6 +23,13 @@ module Datadog
|
|
23
23
|
TAG_CODEOWNERS = "test.codeowners"
|
24
24
|
TAG_PARAMETERS = "test.parameters"
|
25
25
|
|
26
|
+
# ITR tags
|
27
|
+
TAG_ITR_TEST_SKIPPING_ENABLED = "test.itr.tests_skipping.enabled"
|
28
|
+
TAG_ITR_TEST_SKIPPING_TYPE = "test.itr.tests_skipping.type"
|
29
|
+
|
30
|
+
# Code coverage tags
|
31
|
+
TAG_CODE_COVERAGE_ENABLED = "test.code_coverage.enabled"
|
32
|
+
|
26
33
|
# those tags are special and used to correlate tests with the test sessions, suites, and modules
|
27
34
|
# they are transient and not sent to the backend
|
28
35
|
TAG_TEST_SESSION_ID = "_test.session_id"
|
@@ -43,6 +50,10 @@ module Datadog
|
|
43
50
|
TAG_SPAN_KIND = "span.kind"
|
44
51
|
SPAN_KIND_TEST = "test"
|
45
52
|
|
53
|
+
# could be either "test" or "suite" depending on whether we skip individual tests or whole suites
|
54
|
+
# we use test skipping for Ruby
|
55
|
+
ITR_TEST_SKIPPING_MODE = "test"
|
56
|
+
|
46
57
|
# test status as recognized by Datadog
|
47
58
|
module Status
|
48
59
|
PASS = "pass"
|
@@ -12,11 +12,29 @@ module Datadog
|
|
12
12
|
HEADER_EVP_SUBDOMAIN = "X-Datadog-EVP-Subdomain"
|
13
13
|
HEADER_CONTAINER_ID = "Datadog-Container-ID"
|
14
14
|
|
15
|
-
|
15
|
+
EVP_PROXY_V2_PATH_PREFIX = "/evp_proxy/v2/"
|
16
|
+
EVP_PROXY_V4_PATH_PREFIX = "/evp_proxy/v4/"
|
17
|
+
EVP_PROXY_PATH_PREFIXES = [EVP_PROXY_V4_PATH_PREFIX, EVP_PROXY_V2_PATH_PREFIX].freeze
|
18
|
+
EVP_PROXY_COMPRESSION_SUPPORTED = {
|
19
|
+
EVP_PROXY_V4_PATH_PREFIX => true,
|
20
|
+
EVP_PROXY_V2_PATH_PREFIX => false
|
21
|
+
}
|
22
|
+
|
16
23
|
TEST_VISIBILITY_INTAKE_HOST_PREFIX = "citestcycle-intake"
|
17
24
|
TEST_VISIBILITY_INTAKE_PATH = "/api/v2/citestcycle"
|
18
25
|
|
26
|
+
DD_API_HOST_PREFIX = "api"
|
27
|
+
DD_API_SETTINGS_PATH = "/api/v2/libraries/tests/services/setting"
|
28
|
+
DD_API_SETTINGS_TYPE = "ci_app_test_service_libraries_settings"
|
29
|
+
DD_API_SETTINGS_RESPONSE_DIG_KEYS = %w[data attributes].freeze
|
30
|
+
DD_API_SETTINGS_RESPONSE_ITR_ENABLED_KEY = "itr_enabled"
|
31
|
+
DD_API_SETTINGS_RESPONSE_CODE_COVERAGE_KEY = "code_coverage"
|
32
|
+
DD_API_SETTINGS_RESPONSE_TESTS_SKIPPING_KEY = "tests_skipping"
|
33
|
+
DD_API_SETTINGS_RESPONSE_REQUIRE_GIT_KEY = "require_git"
|
34
|
+
DD_API_SETTINGS_RESPONSE_DEFAULT = {DD_API_SETTINGS_RESPONSE_ITR_ENABLED_KEY => false}.freeze
|
35
|
+
|
19
36
|
CONTENT_TYPE_MESSAGEPACK = "application/msgpack"
|
37
|
+
CONTENT_TYPE_JSON = "application/json"
|
20
38
|
CONTENT_ENCODING_GZIP = "gzip"
|
21
39
|
end
|
22
40
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../ext/test"
|
4
|
+
require_relative "../ext/transport"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module CI
|
8
|
+
module ITR
|
9
|
+
# Intelligent test runner implementation
|
10
|
+
# Integrates with backend to provide test impact analysis data and
|
11
|
+
# skip tests that are not impacted by the changes
|
12
|
+
class Runner
|
13
|
+
def initialize(
|
14
|
+
enabled: false
|
15
|
+
)
|
16
|
+
@enabled = enabled
|
17
|
+
@test_skipping_enabled = false
|
18
|
+
@code_coverage_enabled = false
|
19
|
+
|
20
|
+
Datadog.logger.debug("ITR Runner initialized with enabled: #{@enabled}")
|
21
|
+
end
|
22
|
+
|
23
|
+
def configure(remote_configuration, test_session)
|
24
|
+
Datadog.logger.debug("Configuring ITR Runner with remote configuration: #{remote_configuration}")
|
25
|
+
|
26
|
+
@enabled = convert_to_bool(
|
27
|
+
remote_configuration.fetch(Ext::Transport::DD_API_SETTINGS_RESPONSE_ITR_ENABLED_KEY, false)
|
28
|
+
)
|
29
|
+
@test_skipping_enabled = @enabled && convert_to_bool(
|
30
|
+
remote_configuration.fetch(Ext::Transport::DD_API_SETTINGS_RESPONSE_TESTS_SKIPPING_KEY, false)
|
31
|
+
)
|
32
|
+
@code_coverage_enabled = @enabled && convert_to_bool(
|
33
|
+
remote_configuration.fetch(Ext::Transport::DD_API_SETTINGS_RESPONSE_CODE_COVERAGE_KEY, false)
|
34
|
+
)
|
35
|
+
|
36
|
+
test_session.set_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_ENABLED, @test_skipping_enabled)
|
37
|
+
# currently we set this tag when ITR requires collecting code coverage
|
38
|
+
# this will change as soon as we implement total code coverage support in this library
|
39
|
+
test_session.set_tag(Ext::Test::TAG_CODE_COVERAGE_ENABLED, @code_coverage_enabled)
|
40
|
+
|
41
|
+
# we skip tests, not suites
|
42
|
+
test_session.set_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_TYPE, Ext::Test::ITR_TEST_SKIPPING_MODE)
|
43
|
+
|
44
|
+
Datadog.logger.debug("Configured ITR Runner with enabled: #{@enabled}, skipping_tests: #{@test_skipping_enabled}, code_coverage: #{@code_coverage_enabled}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def enabled?
|
48
|
+
@enabled
|
49
|
+
end
|
50
|
+
|
51
|
+
def skipping_tests?
|
52
|
+
@test_skipping_enabled
|
53
|
+
end
|
54
|
+
|
55
|
+
def code_coverage?
|
56
|
+
@code_coverage_enabled
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def convert_to_bool(value)
|
62
|
+
value.to_s == "true"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/datadog/ci/span.rb
CHANGED
@@ -121,6 +121,48 @@ module Datadog
|
|
121
121
|
tracer_span.set_tags(tags)
|
122
122
|
end
|
123
123
|
|
124
|
+
# Returns the git repository URL extracted from the environment.
|
125
|
+
# @return [String] the repository URL.
|
126
|
+
def git_repository_url
|
127
|
+
tracer_span.get_tag(Ext::Git::TAG_REPOSITORY_URL)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns the latest commit SHA extracted from the environment.
|
131
|
+
# @return [String] the commit SHA of the last commit.
|
132
|
+
def git_commit_sha
|
133
|
+
tracer_span.get_tag(Ext::Git::TAG_COMMIT_SHA)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns the git branch name extracted from the environment.
|
137
|
+
# @return [String] the branch.
|
138
|
+
def git_branch
|
139
|
+
tracer_span.get_tag(Ext::Git::TAG_BRANCH)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Returns the OS architecture extracted from the environment.
|
143
|
+
# @return [String] OS arch.
|
144
|
+
def os_architecture
|
145
|
+
tracer_span.get_tag(Ext::Test::TAG_OS_ARCHITECTURE)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns the OS platform extracted from the environment.
|
149
|
+
# @return [String] OS platform.
|
150
|
+
def os_platform
|
151
|
+
tracer_span.get_tag(Ext::Test::TAG_OS_PLATFORM)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns the runtime name extracted from the environment.
|
155
|
+
# @return [String] runtime name.
|
156
|
+
def runtime_name
|
157
|
+
tracer_span.get_tag(Ext::Test::TAG_RUNTIME_NAME)
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns the runtime version extracted from the environment.
|
161
|
+
# @return [String] runtime version.
|
162
|
+
def runtime_version
|
163
|
+
tracer_span.get_tag(Ext::Test::TAG_RUNTIME_VERSION)
|
164
|
+
end
|
165
|
+
|
124
166
|
def set_environment_runtime_tags
|
125
167
|
tracer_span.set_tag(Ext::Test::TAG_OS_ARCHITECTURE, ::RbConfig::CONFIG["host_cpu"])
|
126
168
|
tracer_span.set_tag(Ext::Test::TAG_OS_PLATFORM, ::RbConfig::CONFIG["host_os"])
|
@@ -26,6 +26,14 @@ module Datadog
|
|
26
26
|
get_tag(Ext::Test::TAG_COMMAND)
|
27
27
|
end
|
28
28
|
|
29
|
+
def skipping_tests?
|
30
|
+
get_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_ENABLED) == "true"
|
31
|
+
end
|
32
|
+
|
33
|
+
def code_coverage?
|
34
|
+
get_tag(Ext::Test::TAG_CODE_COVERAGE_ENABLED) == "true"
|
35
|
+
end
|
36
|
+
|
29
37
|
# Return the test session tags that could be inherited by sub-spans
|
30
38
|
# @return [Hash] the tags to be inherited by sub-spans.
|
31
39
|
def inheritable_tags
|
@@ -21,6 +21,14 @@ module Datadog
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
def fetch_single_test_suite
|
25
|
+
@mutex.synchronize do
|
26
|
+
return nil if @test_suites.empty? || @test_suites.size > 1
|
27
|
+
|
28
|
+
@test_suites.values.first
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
24
32
|
def fetch_or_activate_test_module(&block)
|
25
33
|
@mutex.synchronize do
|
26
34
|
@test_module ||= block.call
|
@@ -29,7 +29,7 @@ module Datadog
|
|
29
29
|
attr_reader :environment_tags, :test_suite_level_visibility_enabled
|
30
30
|
|
31
31
|
def initialize(
|
32
|
-
test_suite_level_visibility_enabled: false,
|
32
|
+
itr:, remote_settings_api:, test_suite_level_visibility_enabled: false,
|
33
33
|
codeowners: Codeowners::Parser.new(Utils::Git.root).parse
|
34
34
|
)
|
35
35
|
@test_suite_level_visibility_enabled = test_suite_level_visibility_enabled
|
@@ -37,7 +37,11 @@ module Datadog
|
|
37
37
|
@environment_tags = Ext::Environment.tags(ENV).freeze
|
38
38
|
@local_context = Context::Local.new
|
39
39
|
@global_context = Context::Global.new
|
40
|
+
|
40
41
|
@codeowners = codeowners
|
42
|
+
|
43
|
+
@itr = itr
|
44
|
+
@remote_settings_api = remote_settings_api
|
41
45
|
end
|
42
46
|
|
43
47
|
def start_test_session(service: nil, tags: {})
|
@@ -49,7 +53,11 @@ module Datadog
|
|
49
53
|
)
|
50
54
|
set_session_context(tags, tracer_span)
|
51
55
|
|
52
|
-
build_test_session(tracer_span, tags)
|
56
|
+
test_session = build_test_session(tracer_span, tags)
|
57
|
+
|
58
|
+
configure_library(test_session)
|
59
|
+
|
60
|
+
test_session
|
53
61
|
end
|
54
62
|
end
|
55
63
|
|
@@ -175,8 +183,20 @@ module Datadog
|
|
175
183
|
@global_context.deactivate_test_suite!(test_suite_name)
|
176
184
|
end
|
177
185
|
|
186
|
+
def itr_enabled?
|
187
|
+
@itr.enabled?
|
188
|
+
end
|
189
|
+
|
178
190
|
private
|
179
191
|
|
192
|
+
def configure_library(test_session)
|
193
|
+
# this will change when EFD is implemented
|
194
|
+
return unless itr_enabled?
|
195
|
+
|
196
|
+
remote_configuration = @remote_settings_api.fetch_library_settings(test_session)
|
197
|
+
@itr.configure(remote_configuration.payload, test_session)
|
198
|
+
end
|
199
|
+
|
180
200
|
def skip_tracing(block = nil)
|
181
201
|
block.call(nil) if block
|
182
202
|
end
|
@@ -207,6 +227,11 @@ module Datadog
|
|
207
227
|
def build_test(tracer_span, tags)
|
208
228
|
test = Test.new(tracer_span)
|
209
229
|
set_initial_tags(test, tags)
|
230
|
+
|
231
|
+
# sometimes test suite is not being assigned correctly
|
232
|
+
# fix it by fetching the one single running test suite from the global context
|
233
|
+
fix_test_suite!(test) if test.test_suite_id.nil?
|
234
|
+
|
210
235
|
validate_test_suite_level_visibility_correctness(test)
|
211
236
|
set_codeowners(test)
|
212
237
|
|
@@ -274,6 +299,24 @@ module Datadog
|
|
274
299
|
end
|
275
300
|
end
|
276
301
|
|
302
|
+
def fix_test_suite!(test)
|
303
|
+
test_suite = @global_context.fetch_single_test_suite
|
304
|
+
unless test_suite
|
305
|
+
Datadog.logger.debug do
|
306
|
+
"Trying to fix test suite for test [#{test.name}] but no single test suite is running."
|
307
|
+
end
|
308
|
+
return
|
309
|
+
end
|
310
|
+
|
311
|
+
Datadog.logger.debug do
|
312
|
+
"For test [#{test.name}]: expected test suite [#{test.test_suite_name}] to be running, " \
|
313
|
+
"but it was not found. Fixing it by assigning test suite [#{test_suite.name}] to the test."
|
314
|
+
end
|
315
|
+
|
316
|
+
test.set_tag(Ext::Test::TAG_TEST_SUITE_ID, test_suite.id.to_s)
|
317
|
+
test.set_tag(Ext::Test::TAG_SUITE, test_suite.name)
|
318
|
+
end
|
319
|
+
|
277
320
|
def start_datadog_tracer_span(span_name, span_options, &block)
|
278
321
|
if block
|
279
322
|
Datadog::Tracing.trace(span_name, **span_options) do |tracer_span, trace|
|
@@ -55,10 +55,6 @@ module Datadog
|
|
55
55
|
|
56
56
|
response = send_payload(encoded_payload)
|
57
57
|
|
58
|
-
Datadog.logger.debug do
|
59
|
-
"Received server response: #{response.inspect}"
|
60
|
-
end
|
61
|
-
|
62
58
|
responses << response
|
63
59
|
end
|
64
60
|
|
@@ -68,7 +64,7 @@ module Datadog
|
|
68
64
|
private
|
69
65
|
|
70
66
|
def send_payload(encoded_payload)
|
71
|
-
api.
|
67
|
+
api.citestcycle_request(
|
72
68
|
path: Datadog::CI::Ext::Transport::TEST_VISIBILITY_INTAKE_PATH,
|
73
69
|
payload: encoded_payload
|
74
70
|
)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require_relative "../../ext/transport"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module CI
|
8
|
+
module Transport
|
9
|
+
module Api
|
10
|
+
class Agentless < Base
|
11
|
+
attr_reader :api_key
|
12
|
+
|
13
|
+
def initialize(api_key:, citestcycle_url:, api_url:)
|
14
|
+
@api_key = api_key
|
15
|
+
@citestcycle_http = build_http_client(citestcycle_url, compress: true)
|
16
|
+
@api_http = build_http_client(api_url, compress: false)
|
17
|
+
end
|
18
|
+
|
19
|
+
def citestcycle_request(path:, payload:, headers: {}, verb: "post")
|
20
|
+
super
|
21
|
+
|
22
|
+
perform_request(@citestcycle_http, path: path, payload: payload, headers: headers, verb: verb)
|
23
|
+
end
|
24
|
+
|
25
|
+
def api_request(path:, payload:, headers: {}, verb: "post")
|
26
|
+
super
|
27
|
+
|
28
|
+
perform_request(@api_http, path: path, payload: payload, headers: headers, verb: verb)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def perform_request(http_client, path:, payload:, headers:, verb:)
|
34
|
+
http_client.request(
|
35
|
+
path: path,
|
36
|
+
payload: payload,
|
37
|
+
headers: headers_with_default(headers),
|
38
|
+
verb: verb
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_http_client(url, compress:)
|
43
|
+
uri = URI.parse(url)
|
44
|
+
raise "Invalid agentless mode URL: #{url}" if uri.host.nil?
|
45
|
+
|
46
|
+
Datadog::CI::Transport::HTTP.new(
|
47
|
+
host: uri.host,
|
48
|
+
port: uri.port,
|
49
|
+
ssl: uri.scheme == "https" || uri.port == 443,
|
50
|
+
compress: compress
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_headers
|
55
|
+
headers = super
|
56
|
+
headers[Ext::Transport::HEADER_DD_API_KEY] = api_key
|
57
|
+
headers
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -7,27 +7,23 @@ module Datadog
|
|
7
7
|
module Transport
|
8
8
|
module Api
|
9
9
|
class Base
|
10
|
-
|
10
|
+
def api_request(path:, payload:, headers: {}, verb: "post")
|
11
|
+
headers[Ext::Transport::HEADER_CONTENT_TYPE] ||= Ext::Transport::CONTENT_TYPE_JSON
|
12
|
+
end
|
11
13
|
|
12
|
-
def
|
13
|
-
|
14
|
+
def citestcycle_request(path:, payload:, headers: {}, verb: "post")
|
15
|
+
headers[Ext::Transport::HEADER_CONTENT_TYPE] ||= Ext::Transport::CONTENT_TYPE_MESSAGEPACK
|
14
16
|
end
|
15
17
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
payload: payload,
|
20
|
-
verb: verb,
|
21
|
-
headers: headers
|
22
|
-
)
|
18
|
+
def headers_with_default(headers)
|
19
|
+
request_headers = default_headers
|
20
|
+
request_headers.merge!(headers)
|
23
21
|
end
|
24
22
|
|
25
23
|
private
|
26
24
|
|
27
|
-
def
|
28
|
-
{
|
29
|
-
Ext::Transport::HEADER_CONTENT_TYPE => Ext::Transport::CONTENT_TYPE_MESSAGEPACK
|
30
|
-
}
|
25
|
+
def default_headers
|
26
|
+
{}
|
31
27
|
end
|
32
28
|
end
|
33
29
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require "datadog/core/configuration/agent_settings_resolver"
|
4
|
+
require "datadog/core/remote/negotiation"
|
5
|
+
|
6
|
+
require_relative "agentless"
|
4
7
|
require_relative "evp_proxy"
|
5
8
|
require_relative "../http"
|
6
9
|
require_relative "../../ext/transport"
|
@@ -10,34 +13,35 @@ module Datadog
|
|
10
13
|
module Transport
|
11
14
|
module Api
|
12
15
|
module Builder
|
13
|
-
def self.
|
16
|
+
def self.build_agentless_api(settings)
|
17
|
+
return nil if settings.api_key.nil?
|
18
|
+
|
14
19
|
dd_site = settings.site || Ext::Transport::DEFAULT_DD_SITE
|
15
|
-
|
20
|
+
|
21
|
+
citestcycle_url = settings.ci.agentless_url ||
|
16
22
|
"https://#{Ext::Transport::TEST_VISIBILITY_INTAKE_HOST_PREFIX}.#{dd_site}:443"
|
17
23
|
|
18
|
-
|
19
|
-
|
24
|
+
api_url = settings.ci.agentless_url ||
|
25
|
+
"https://#{Ext::Transport::DD_API_HOST_PREFIX}.#{dd_site}:443"
|
20
26
|
|
21
|
-
|
22
|
-
host: uri.host,
|
23
|
-
port: uri.port,
|
24
|
-
ssl: uri.scheme == "https" || uri.port == 443,
|
25
|
-
compress: true
|
26
|
-
)
|
27
|
-
|
28
|
-
CiTestCycle.new(api_key: settings.api_key, http: http)
|
27
|
+
Agentless.new(api_key: settings.api_key, citestcycle_url: citestcycle_url, api_url: api_url)
|
29
28
|
end
|
30
29
|
|
31
|
-
def self.build_evp_proxy_api(
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
compress: false
|
30
|
+
def self.build_evp_proxy_api(settings)
|
31
|
+
agent_settings = Datadog::Core::Configuration::AgentSettingsResolver.call(settings)
|
32
|
+
negotiation = Datadog::Core::Remote::Negotiation.new(
|
33
|
+
settings,
|
34
|
+
agent_settings,
|
35
|
+
suppress_logging: {no_config_endpoint: true}
|
38
36
|
)
|
39
37
|
|
40
|
-
|
38
|
+
evp_proxy_path_prefix = Ext::Transport::EVP_PROXY_PATH_PREFIXES.find do |path_prefix|
|
39
|
+
negotiation.endpoint?(path_prefix)
|
40
|
+
end
|
41
|
+
|
42
|
+
return nil if evp_proxy_path_prefix.nil?
|
43
|
+
|
44
|
+
EvpProxy.new(agent_settings: agent_settings, path_prefix: evp_proxy_path_prefix)
|
41
45
|
end
|
42
46
|
end
|
43
47
|
end
|
@@ -10,17 +10,48 @@ module Datadog
|
|
10
10
|
module Transport
|
11
11
|
module Api
|
12
12
|
class EvpProxy < Base
|
13
|
-
def
|
14
|
-
|
13
|
+
def initialize(agent_settings:, path_prefix: Ext::Transport::EVP_PROXY_V2_PATH_PREFIX)
|
14
|
+
@agent_intake_http = build_http_client(
|
15
|
+
agent_settings,
|
16
|
+
compress: Ext::Transport::EVP_PROXY_COMPRESSION_SUPPORTED[path_prefix]
|
17
|
+
)
|
18
|
+
|
19
|
+
@agent_api_http = build_http_client(agent_settings, compress: false)
|
20
|
+
|
21
|
+
path_prefix = "#{path_prefix}/" unless path_prefix.end_with?("/")
|
22
|
+
@path_prefix = path_prefix
|
23
|
+
end
|
24
|
+
|
25
|
+
def citestcycle_request(path:, payload:, headers: {}, verb: "post")
|
26
|
+
super
|
27
|
+
|
28
|
+
headers[Ext::Transport::HEADER_EVP_SUBDOMAIN] = Ext::Transport::TEST_VISIBILITY_INTAKE_HOST_PREFIX
|
29
|
+
|
30
|
+
perform_request(@agent_intake_http, path: path, payload: payload, headers: headers, verb: verb)
|
31
|
+
end
|
32
|
+
|
33
|
+
def api_request(path:, payload:, headers: {}, verb: "post")
|
34
|
+
super
|
35
|
+
|
36
|
+
headers[Ext::Transport::HEADER_EVP_SUBDOMAIN] = Ext::Transport::DD_API_HOST_PREFIX
|
15
37
|
|
16
|
-
|
17
|
-
|
38
|
+
perform_request(@agent_api_http, path: path, payload: payload, headers: headers, verb: verb)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def perform_request(http_client, path:, payload:, headers:, verb:)
|
44
|
+
http_client.request(
|
45
|
+
path: path_with_prefix(path),
|
18
46
|
payload: payload,
|
47
|
+
headers: headers_with_default(headers),
|
19
48
|
verb: verb
|
20
49
|
)
|
21
50
|
end
|
22
51
|
|
23
|
-
|
52
|
+
def path_with_prefix(path)
|
53
|
+
"#{@path_prefix}#{path.sub(/^\//, "")}"
|
54
|
+
end
|
24
55
|
|
25
56
|
def container_id
|
26
57
|
return @container_id if defined?(@container_id)
|
@@ -28,15 +59,24 @@ module Datadog
|
|
28
59
|
@container_id = Datadog::Core::Environment::Container.container_id
|
29
60
|
end
|
30
61
|
|
31
|
-
def
|
62
|
+
def default_headers
|
32
63
|
headers = super
|
33
|
-
headers[Ext::Transport::HEADER_EVP_SUBDOMAIN] = Ext::Transport::TEST_VISIBILITY_INTAKE_HOST_PREFIX
|
34
64
|
|
35
65
|
c_id = container_id
|
36
66
|
headers[Ext::Transport::HEADER_CONTAINER_ID] = c_id unless c_id.nil?
|
37
67
|
|
38
68
|
headers
|
39
69
|
end
|
70
|
+
|
71
|
+
def build_http_client(agent_settings, compress:)
|
72
|
+
Datadog::CI::Transport::HTTP.new(
|
73
|
+
host: agent_settings.hostname,
|
74
|
+
port: agent_settings.port,
|
75
|
+
ssl: agent_settings.ssl,
|
76
|
+
timeout: agent_settings.timeout_seconds,
|
77
|
+
compress: compress
|
78
|
+
)
|
79
|
+
end
|
40
80
|
end
|
41
81
|
end
|
42
82
|
end
|
@@ -40,11 +40,17 @@ module Datadog
|
|
40
40
|
"compression_enabled=#{compress}; path=#{path}; payload_size=#{payload.size}"
|
41
41
|
end
|
42
42
|
|
43
|
-
ResponseDecorator.new(
|
43
|
+
response = ResponseDecorator.new(
|
44
44
|
adapter.call(
|
45
45
|
build_env(path: path, payload: payload, headers: headers, verb: verb)
|
46
46
|
)
|
47
47
|
)
|
48
|
+
|
49
|
+
Datadog.logger.debug do
|
50
|
+
"Received server response: #{response.inspect}"
|
51
|
+
end
|
52
|
+
|
53
|
+
response
|
48
54
|
end
|
49
55
|
|
50
56
|
private
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
require "datadog/core/environment/identity"
|
6
|
+
|
7
|
+
require_relative "../ext/transport"
|
8
|
+
|
9
|
+
module Datadog
|
10
|
+
module CI
|
11
|
+
module Transport
|
12
|
+
# Datadog API client
|
13
|
+
# Calls settings endpoint to fetch library settings for given service and env
|
14
|
+
class RemoteSettingsApi
|
15
|
+
class Response
|
16
|
+
def initialize(http_response)
|
17
|
+
@http_response = http_response
|
18
|
+
@json = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def ok?
|
22
|
+
resp = @http_response
|
23
|
+
!resp.nil? && resp.ok?
|
24
|
+
end
|
25
|
+
|
26
|
+
def payload
|
27
|
+
cached = @json
|
28
|
+
return cached unless cached.nil?
|
29
|
+
|
30
|
+
resp = @http_response
|
31
|
+
return @json = default_payload if resp.nil? || !resp.ok?
|
32
|
+
|
33
|
+
begin
|
34
|
+
@json = JSON.parse(resp.payload).dig(*Ext::Transport::DD_API_SETTINGS_RESPONSE_DIG_KEYS) ||
|
35
|
+
default_payload
|
36
|
+
rescue JSON::ParserError => e
|
37
|
+
Datadog.logger.error("Failed to parse settings response payload: #{e}. Payload was: #{resp.payload}")
|
38
|
+
@json = default_payload
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def default_payload
|
45
|
+
Ext::Transport::DD_API_SETTINGS_RESPONSE_DEFAULT
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(api: nil, dd_env: nil)
|
50
|
+
@api = api
|
51
|
+
@dd_env = dd_env
|
52
|
+
end
|
53
|
+
|
54
|
+
def fetch_library_settings(test_session)
|
55
|
+
api = @api
|
56
|
+
return Response.new(nil) unless api
|
57
|
+
|
58
|
+
request_payload = payload(test_session)
|
59
|
+
Datadog.logger.debug("Fetching library settings with request: #{request_payload}")
|
60
|
+
|
61
|
+
http_response = api.api_request(
|
62
|
+
path: Ext::Transport::DD_API_SETTINGS_PATH,
|
63
|
+
payload: request_payload
|
64
|
+
)
|
65
|
+
|
66
|
+
Response.new(http_response)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def payload(test_session)
|
72
|
+
{
|
73
|
+
"data" => {
|
74
|
+
"id" => Datadog::Core::Environment::Identity.id,
|
75
|
+
"type" => Ext::Transport::DD_API_SETTINGS_TYPE,
|
76
|
+
"attributes" => {
|
77
|
+
"service" => test_session.service,
|
78
|
+
"env" => @dd_env,
|
79
|
+
"repository_url" => test_session.git_repository_url,
|
80
|
+
"branch" => test_session.git_branch,
|
81
|
+
"sha" => test_session.git_commit_sha,
|
82
|
+
"test_level" => Ext::Test::ITR_TEST_SKIPPING_MODE,
|
83
|
+
"configurations" => {
|
84
|
+
"os.platform" => test_session.os_platform,
|
85
|
+
"os.arch" => test_session.os_architecture,
|
86
|
+
"runtime.name" => test_session.runtime_name,
|
87
|
+
"runtime.version" => test_session.runtime_version
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}.to_json
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/datadog/ci/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datadog-ci
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Datadog, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: msgpack
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- lib/datadog/ci/ext/settings.rb
|
99
99
|
- lib/datadog/ci/ext/test.rb
|
100
100
|
- lib/datadog/ci/ext/transport.rb
|
101
|
+
- lib/datadog/ci/itr/runner.rb
|
101
102
|
- lib/datadog/ci/span.rb
|
102
103
|
- lib/datadog/ci/test.rb
|
103
104
|
- lib/datadog/ci/test_module.rb
|
@@ -118,16 +119,16 @@ files:
|
|
118
119
|
- lib/datadog/ci/test_visibility/serializers/test_v1.rb
|
119
120
|
- lib/datadog/ci/test_visibility/serializers/test_v2.rb
|
120
121
|
- lib/datadog/ci/test_visibility/transport.rb
|
122
|
+
- lib/datadog/ci/transport/api/agentless.rb
|
121
123
|
- lib/datadog/ci/transport/api/base.rb
|
122
124
|
- lib/datadog/ci/transport/api/builder.rb
|
123
|
-
- lib/datadog/ci/transport/api/ci_test_cycle.rb
|
124
125
|
- lib/datadog/ci/transport/api/evp_proxy.rb
|
125
126
|
- lib/datadog/ci/transport/gzip.rb
|
126
127
|
- lib/datadog/ci/transport/http.rb
|
128
|
+
- lib/datadog/ci/transport/remote_settings_api.rb
|
127
129
|
- lib/datadog/ci/utils/configuration.rb
|
128
130
|
- lib/datadog/ci/utils/git.rb
|
129
131
|
- lib/datadog/ci/utils/test_run.rb
|
130
|
-
- lib/datadog/ci/utils/url.rb
|
131
132
|
- lib/datadog/ci/version.rb
|
132
133
|
homepage: https://github.com/DataDog/datadog-ci-rb
|
133
134
|
licenses:
|
@@ -155,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
156
|
- !ruby/object:Gem::Version
|
156
157
|
version: 2.0.0
|
157
158
|
requirements: []
|
158
|
-
rubygems_version: 3.5.
|
159
|
+
rubygems_version: 3.5.6
|
159
160
|
signing_key:
|
160
161
|
specification_version: 4
|
161
162
|
summary: Datadog CI visibility for your ruby application
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "base"
|
4
|
-
require_relative "../../ext/transport"
|
5
|
-
|
6
|
-
module Datadog
|
7
|
-
module CI
|
8
|
-
module Transport
|
9
|
-
module Api
|
10
|
-
class CiTestCycle < Base
|
11
|
-
attr_reader :api_key
|
12
|
-
|
13
|
-
def initialize(api_key:, http:)
|
14
|
-
@api_key = api_key
|
15
|
-
|
16
|
-
super(http: http)
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def headers
|
22
|
-
headers = super
|
23
|
-
headers[Ext::Transport::HEADER_DD_API_KEY] = api_key
|
24
|
-
headers
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/datadog/ci/utils/url.rb
DELETED