datadog-ci 0.3.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +89 -1
  3. data/README.md +57 -34
  4. data/lib/datadog/ci/concurrent_span.rb +59 -0
  5. data/lib/datadog/ci/configuration/components.rb +40 -1
  6. data/lib/datadog/ci/configuration/extensions.rb +21 -0
  7. data/lib/datadog/ci/configuration/settings.rb +7 -1
  8. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +12 -1
  9. data/lib/datadog/ci/contrib/cucumber/formatter.rb +22 -29
  10. data/lib/datadog/ci/contrib/minitest/configuration/settings.rb +10 -1
  11. data/lib/datadog/ci/contrib/minitest/hooks.rb +15 -25
  12. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +10 -1
  13. data/lib/datadog/ci/contrib/rspec/example.rb +13 -18
  14. data/lib/datadog/ci/contrib/settings.rb +2 -0
  15. data/lib/datadog/ci/ext/app_types.rb +5 -0
  16. data/lib/datadog/ci/ext/environment/extractor.rb +5 -10
  17. data/lib/datadog/ci/ext/environment/providers/github_actions.rb +13 -4
  18. data/lib/datadog/ci/ext/settings.rb +11 -0
  19. data/lib/datadog/ci/ext/test.rb +12 -1
  20. data/lib/datadog/ci/null_span.rb +63 -0
  21. data/lib/datadog/ci/span.rb +117 -0
  22. data/lib/datadog/ci/test.rb +25 -0
  23. data/lib/datadog/ci/test_module.rb +23 -0
  24. data/lib/datadog/ci/test_session.rb +36 -0
  25. data/lib/datadog/ci/test_suite.rb +25 -0
  26. data/lib/datadog/ci/test_visibility/context/global.rb +82 -0
  27. data/lib/datadog/ci/test_visibility/context/local.rb +52 -0
  28. data/lib/datadog/ci/test_visibility/recorder.rb +293 -0
  29. data/lib/datadog/ci/test_visibility/serializers/base.rb +100 -12
  30. data/lib/datadog/ci/test_visibility/serializers/factories/test_suite_level.rb +37 -0
  31. data/lib/datadog/ci/test_visibility/serializers/span.rb +2 -16
  32. data/lib/datadog/ci/test_visibility/serializers/test_module.rb +46 -0
  33. data/lib/datadog/ci/test_visibility/serializers/test_session.rb +46 -0
  34. data/lib/datadog/ci/test_visibility/serializers/test_suite.rb +46 -0
  35. data/lib/datadog/ci/test_visibility/serializers/test_v1.rb +3 -17
  36. data/lib/datadog/ci/test_visibility/serializers/test_v2.rb +38 -0
  37. data/lib/datadog/ci/test_visibility/transport.rb +4 -4
  38. data/lib/datadog/ci/utils/test_run.rb +15 -0
  39. data/lib/datadog/ci/utils/url.rb +15 -0
  40. data/lib/datadog/ci/version.rb +2 -2
  41. data/lib/datadog/ci.rb +378 -7
  42. data/sig/datadog/ci/concurrent_span.rbs +23 -0
  43. data/sig/datadog/ci/configuration/components.rbs +6 -0
  44. data/sig/datadog/ci/configuration/extensions.rbs +9 -0
  45. data/sig/datadog/ci/ext/app_types.rbs +6 -1
  46. data/sig/datadog/ci/ext/environment/extractor.rbs +0 -2
  47. data/sig/datadog/ci/ext/environment/providers/github_actions.rbs +5 -0
  48. data/sig/datadog/ci/ext/settings.rbs +3 -0
  49. data/sig/datadog/ci/ext/test.rbs +15 -0
  50. data/sig/datadog/ci/null_span.rbs +37 -0
  51. data/sig/datadog/ci/span.rbs +39 -0
  52. data/sig/datadog/ci/test.rbs +7 -0
  53. data/sig/datadog/ci/test_module.rbs +6 -0
  54. data/sig/datadog/ci/test_session.rbs +9 -0
  55. data/sig/datadog/ci/test_suite.rbs +6 -0
  56. data/sig/datadog/ci/test_visibility/context/global.rbs +39 -0
  57. data/sig/datadog/ci/test_visibility/context/local.rbs +23 -0
  58. data/sig/datadog/ci/test_visibility/recorder.rbs +85 -0
  59. data/sig/datadog/ci/test_visibility/serializers/base.rbs +26 -5
  60. data/sig/datadog/ci/test_visibility/serializers/factories/test_suite_level.rbs +13 -0
  61. data/sig/datadog/ci/test_visibility/serializers/test_module.rbs +26 -0
  62. data/sig/datadog/ci/test_visibility/serializers/test_session.rbs +26 -0
  63. data/sig/datadog/ci/test_visibility/serializers/test_suite.rbs +26 -0
  64. data/sig/datadog/ci/test_visibility/serializers/test_v1.rbs +1 -1
  65. data/sig/datadog/ci/test_visibility/serializers/test_v2.rbs +25 -0
  66. data/sig/datadog/ci/test_visibility/transport.rbs +3 -3
  67. data/sig/datadog/ci/utils/test_run.rbs +11 -0
  68. data/sig/datadog/ci/utils/url.rbs +9 -0
  69. data/sig/datadog/ci.rbs +31 -3
  70. metadata +38 -6
  71. data/lib/datadog/ci/extensions.rb +0 -19
  72. data/lib/datadog/ci/recorder.rb +0 -83
  73. data/sig/datadog/ci/extensions.rbs +0 -7
  74. data/sig/datadog/ci/recorder.rbs +0 -18
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../../ext/test"
5
+
6
+ module Datadog
7
+ module CI
8
+ module TestVisibility
9
+ module Serializers
10
+ class TestSession < Base
11
+ CONTENT_FIELDS = (["test_session_id"] + Base::CONTENT_FIELDS).freeze
12
+
13
+ CONTENT_MAP_SIZE = calculate_content_map_size(CONTENT_FIELDS)
14
+
15
+ REQUIRED_FIELDS = (["test_session_id"] + Base::REQUIRED_FIELDS).freeze
16
+
17
+ def content_fields
18
+ CONTENT_FIELDS
19
+ end
20
+
21
+ def content_map_size
22
+ CONTENT_MAP_SIZE
23
+ end
24
+
25
+ def type
26
+ Ext::AppTypes::TYPE_TEST_SESSION
27
+ end
28
+
29
+ def name
30
+ "#{@span.get_tag(Ext::Test::TAG_FRAMEWORK)}.test_session"
31
+ end
32
+
33
+ def resource
34
+ "#{@span.get_tag(Ext::Test::TAG_FRAMEWORK)}.test_session.#{@span.get_tag(Ext::Test::TAG_COMMAND)}"
35
+ end
36
+
37
+ private
38
+
39
+ def required_fields
40
+ REQUIRED_FIELDS
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../../ext/test"
5
+
6
+ module Datadog
7
+ module CI
8
+ module TestVisibility
9
+ module Serializers
10
+ class TestSuite < Base
11
+ CONTENT_FIELDS = (["test_session_id", "test_module_id", "test_suite_id"] + Base::CONTENT_FIELDS).freeze
12
+
13
+ CONTENT_MAP_SIZE = calculate_content_map_size(CONTENT_FIELDS)
14
+
15
+ REQUIRED_FIELDS = (["test_session_id", "test_module_id", "test_suite_id"] + Base::REQUIRED_FIELDS).freeze
16
+
17
+ def content_fields
18
+ CONTENT_FIELDS
19
+ end
20
+
21
+ def content_map_size
22
+ CONTENT_MAP_SIZE
23
+ end
24
+
25
+ def type
26
+ Ext::AppTypes::TYPE_TEST_SUITE
27
+ end
28
+
29
+ def name
30
+ "#{@span.get_tag(Ext::Test::TAG_FRAMEWORK)}.test_suite"
31
+ end
32
+
33
+ def resource
34
+ "#{@span.get_tag(Ext::Test::TAG_FRAMEWORK)}.test_suite.#{@span.get_tag(Ext::Test::TAG_SUITE)}"
35
+ end
36
+
37
+ private
38
+
39
+ def required_fields
40
+ REQUIRED_FIELDS
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -8,25 +8,11 @@ module Datadog
8
8
  module TestVisibility
9
9
  module Serializers
10
10
  class TestV1 < Base
11
- CONTENT_FIELDS = [
12
- "trace_id", "span_id",
13
- "name", "resource", "service",
14
- "error", "start", "duration",
15
- "meta", "metrics",
16
- "type" => "span_type"
17
- ].freeze
11
+ CONTENT_FIELDS = (["trace_id", "span_id"] + Base::CONTENT_FIELDS).freeze
18
12
 
19
13
  CONTENT_MAP_SIZE = calculate_content_map_size(CONTENT_FIELDS)
20
14
 
21
- REQUIRED_FIELDS = [
22
- "trace_id",
23
- "span_id",
24
- "error",
25
- "name",
26
- "resource",
27
- "start",
28
- "duration"
29
- ].freeze
15
+ REQUIRED_FIELDS = (["trace_id", "span_id"] + Base::REQUIRED_FIELDS).freeze
30
16
 
31
17
  def content_fields
32
18
  CONTENT_FIELDS
@@ -37,7 +23,7 @@ module Datadog
37
23
  end
38
24
 
39
25
  def type
40
- "test"
26
+ Ext::AppTypes::TYPE_TEST
41
27
  end
42
28
 
43
29
  def name
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "test_v1"
4
+ require_relative "../../ext/test"
5
+
6
+ module Datadog
7
+ module CI
8
+ module TestVisibility
9
+ module Serializers
10
+ class TestV2 < TestV1
11
+ CONTENT_FIELDS = (["test_session_id", "test_module_id", "test_suite_id"] + TestV1::CONTENT_FIELDS).freeze
12
+
13
+ CONTENT_MAP_SIZE = calculate_content_map_size(CONTENT_FIELDS)
14
+
15
+ REQUIRED_FIELDS = (["test_session_id", "test_module_id", "test_suite_id"] + TestV1::REQUIRED_FIELDS).freeze
16
+
17
+ def content_fields
18
+ CONTENT_FIELDS
19
+ end
20
+
21
+ def content_map_size
22
+ CONTENT_MAP_SIZE
23
+ end
24
+
25
+ def version
26
+ 2
27
+ end
28
+
29
+ private
30
+
31
+ def required_fields
32
+ REQUIRED_FIELDS
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -81,7 +81,7 @@ module Datadog
81
81
  if spans.respond_to?(:filter_map)
82
82
  spans.filter_map { |span| encode_span(trace, span) }
83
83
  else
84
- trace.spans.map { |span| encode_span(trace, span) }.reject(&:nil?)
84
+ spans.map { |span| encode_span(trace, span) }.reject(&:nil?)
85
85
  end
86
86
  end
87
87
  end
@@ -94,15 +94,15 @@ module Datadog
94
94
 
95
95
  if encoded.size > max_payload_size
96
96
  # This single event is too large, we can't flush it
97
- Datadog.logger.debug { "Dropping test event. Payload too large: '#{span.inspect}'" }
98
- Datadog.logger.debug { encoded }
97
+ Datadog.logger.warn("Dropping test event. Payload too large: '#{span.inspect}'")
98
+ Datadog.logger.warn(encoded)
99
99
 
100
100
  return nil
101
101
  end
102
102
 
103
103
  encoded
104
104
  else
105
- Datadog.logger.debug { "Invalid span skipped: #{span}" }
105
+ Datadog.logger.warn("Invalid event skipped: #{serializer} Errors: #{serializer.validation_errors}")
106
106
  nil
107
107
  end
108
108
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Utils
6
+ module TestRun
7
+ def self.command
8
+ return @command if defined?(@command)
9
+
10
+ @command = "#{$0} #{ARGV.join(" ")}"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Utils
6
+ module Url
7
+ def self.filter_sensitive_info(url)
8
+ return nil if url.nil?
9
+
10
+ url.gsub(%r{((https?|ssh)://)[^/]*@}, '\1')
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -4,8 +4,8 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = "0"
7
- MINOR = "3"
8
- PATCH = "0"
7
+ MINOR = "5"
8
+ PATCH = "1"
9
9
  PRE = nil
10
10
  BUILD = nil
11
11
  # PRE and BUILD above are modified for dev gems during gem build GHA workflow
data/lib/datadog/ci.rb CHANGED
@@ -5,11 +5,382 @@ require_relative "ci/version"
5
5
  require "datadog/core"
6
6
 
7
7
  module Datadog
8
- # Namespace for Datadog CI instrumentation:
9
- # e.g. rspec, cucumber, etc...
8
+ # Datadog CI visibility public API.
9
+ #
10
+ # @public_api
10
11
  module CI
11
- class Error < StandardError; end
12
- # Your code goes here...
12
+ class << self
13
+ # Starts a {Datadog::CI::TestSession ci_test_session} that represents the whole test session run.
14
+ #
15
+ # Read Datadog documentation on test sessions
16
+ # [here](https://docs.datadoghq.com/continuous_integration/explorer/?tab=testruns#sessions).
17
+ #
18
+ # Returns the existing test session if one is already active. There is at most a single test session per process.
19
+ #
20
+ # The {.start_test_session} method is used to mark the start of the test session:
21
+ # ```
22
+ # Datadog::CI.start_test_session(
23
+ # service: "my-web-site-tests",
24
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
25
+ # )
26
+ #
27
+ # # Somewhere else after test run has ended
28
+ # Datadog::CI.active_test_session.finish
29
+ # ```
30
+ #
31
+ # Remember that calling {Datadog::CI::TestSession#finish} is mandatory.
32
+ #
33
+ # @param [String] service the service name for this session (optional, defaults to DD_SERVICE)
34
+ # @param [Hash<String,String>] tags extra tags which should be added to the test session.
35
+ # @return [Datadog::CI::TestSession] returns the active, running {Datadog::CI::TestSession}.
36
+ # @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled or if old Datadog agent is
37
+ # detected and test suite level visibility cannot be supported.
38
+ def start_test_session(service: nil, tags: {})
39
+ service ||= Datadog.configuration.service
40
+ recorder.start_test_session(service: service, tags: tags)
41
+ end
42
+
43
+ # The active, unfinished test session.
44
+ #
45
+ # Usage:
46
+ #
47
+ # ```
48
+ # # start a test session
49
+ # Datadog::CI.start_test_session(
50
+ # service: "my-web-site-tests",
51
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
52
+ # )
53
+ #
54
+ # # somewhere else, access the session
55
+ # test_session = Datadog::CI.active_test_session
56
+ # test_session.finish
57
+ # ```
58
+ #
59
+ # @return [Datadog::CI::TestSession] the active test session
60
+ # @return [nil] if no test session is active
61
+ def active_test_session
62
+ recorder.active_test_session
63
+ end
64
+
65
+ # Starts a {Datadog::CI::TestModule ci_test_module} that represents a single test module (for most Ruby test frameworks
66
+ # module will correspond 1-1 to the test session).
67
+ #
68
+ # Read Datadog documentation on test modules
69
+ # [here](https://docs.datadoghq.com/continuous_integration/explorer/?tab=testruns#module).
70
+ #
71
+ # Returns the existing test session if one is already active. There is at most a single test module per process
72
+ # active at any given time.
73
+ #
74
+ # The {.start_test_module} method is used to mark the start of the test session:
75
+ # ```
76
+ # Datadog::CI.start_test_module(
77
+ # "my-module",
78
+ # service: "my-web-site-tests",
79
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
80
+ # )
81
+ #
82
+ # # Somewhere else after the module has ended
83
+ # Datadog::CI.active_test_module.finish
84
+ # ```
85
+ #
86
+ # Remember that calling {Datadog::CI::TestModule#finish} is mandatory.
87
+ #
88
+ # @param [String] test_module_name the name for this module
89
+ # @param [String] service the service name for this session (optional, inherited from test session if not provided)
90
+ # @param [Hash<String,String>] tags extra tags which should be added to the test module (optional, some tags are inherited from test session).
91
+ # @return [Datadog::CI::TestModule] returns the active, running {Datadog::CI::TestModule}.
92
+ # @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled or if old Datadog agent is
93
+ # detected and test suite level visibility cannot be supported.
94
+ def start_test_module(test_module_name, service: nil, tags: {})
95
+ recorder.start_test_module(test_module_name, service: service, tags: tags)
96
+ end
97
+
98
+ # The active, unfinished test module.
99
+ #
100
+ # Usage:
101
+ #
102
+ # ```
103
+ # # start a test module
104
+ # Datadog::CI.start_test_module(
105
+ # "my-module",
106
+ # service: "my-web-site-tests",
107
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
108
+ # )
109
+ #
110
+ # # somewhere else, access the current module
111
+ # test_module = Datadog::CI.active_test_module
112
+ # test_module.finish
113
+ # ```
114
+ #
115
+ # @return [Datadog::CI::TestModule] the active test module
116
+ # @return [nil] if no test module is active
117
+ def active_test_module
118
+ recorder.active_test_module
119
+ end
120
+
121
+ # Starts a {Datadog::CI::TestSuite ci_test_suite} that represents a single test suite.
122
+ # If a test suite with given name is running, returns the existing test suite.
123
+ #
124
+ # Read Datadog documentation on test suites
125
+ # [here](https://docs.datadoghq.com/continuous_integration/explorer/?tab=testruns#module).
126
+ #
127
+ # The {.start_test_suite} method is used to mark the start of a test suite:
128
+ # ```
129
+ # Datadog::CI.start_test_suite(
130
+ # "calculator_tests",
131
+ # service: "my-web-site-tests",
132
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
133
+ # )
134
+ #
135
+ # # Somewhere else after the suite has ended
136
+ # Datadog::CI.active_test_suite("calculator_tests").finish
137
+ # ```
138
+ #
139
+ # Remember that calling {Datadog::CI::TestSuite#finish} is mandatory.
140
+ #
141
+ # @param [String] test_suite_name the name of the test suite
142
+ # @param [String] service the service name for this test suite (optional, inherited from test session if not provided)
143
+ # @param [Hash<String,String>] tags extra tags which should be added to the test module (optional, some tags are inherited from test session)
144
+ # @return [Datadog::CI::TestSuite] returns the active, running {Datadog::CI::TestSuite}.
145
+ # @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled or if old Datadog agent is
146
+ # detected and test suite level visibility cannot be supported.
147
+ def start_test_suite(test_suite_name, service: nil, tags: {})
148
+ recorder.start_test_suite(test_suite_name, service: service, tags: tags)
149
+ end
150
+
151
+ # The active, unfinished test suite.
152
+ #
153
+ # Usage:
154
+ #
155
+ # ```
156
+ # # start a test suite
157
+ # Datadog::CI.start_test_suite(
158
+ # "calculator_tests",
159
+ # service: "my-web-site-tests",
160
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
161
+ # )
162
+ #
163
+ # # Somewhere else after the suite has ended
164
+ # test_suite = Datadog::CI.active_test_suite("calculator_tests")
165
+ # test_suite.finish
166
+ # ```
167
+ #
168
+ # @return [Datadog::CI::TestSuite] the active test suite
169
+ # @return [nil] if no test suite with given name is active
170
+ def active_test_suite(test_suite_name)
171
+ recorder.active_test_suite(test_suite_name)
172
+ end
173
+
174
+ # Return a {Datadog::CI::Test ci_test} that will trace a test called `test_name`.
175
+ # Raises an error if a test is already active.
176
+ # If there is an active test session, the new test will be connected to the session.
177
+ # The test will inherit service name and tags from the running test session if not provided
178
+ # in parameters.
179
+ #
180
+ # You could trace your test using a <tt>do-block</tt> like:
181
+ #
182
+ # ```
183
+ # Datadog::CI.trace_test(
184
+ # "test_add_two_numbers",
185
+ # "calculator_tests",
186
+ # service: "my-web-site-tests",
187
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
188
+ # ) do |ci_test|
189
+ # result = run_test
190
+ #
191
+ # if result.ok?
192
+ # ci_test.passed!
193
+ # else
194
+ # ci_test.failed!(exception: result.exception)
195
+ # end
196
+ # end
197
+ # ```
198
+ #
199
+ # The {.trace_test} method can also be used without a block in this way:
200
+ # ```
201
+ # ci_test = Datadog::CI.trace_test(
202
+ # "test_add_two_numbers",
203
+ # "calculator_tests",
204
+ # service: "my-web-site-tests",
205
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
206
+ # )
207
+ # # ... run test here ...
208
+ # ci_test.finish
209
+ # ```
210
+ #
211
+ # Remember that in this case, calling {Datadog::CI::Test#finish} is mandatory.
212
+ #
213
+ # @param [String] test_name {Datadog::CI::Test} name (example: "test_add_two_numbers").
214
+ # @param [String] test_suite_name name of test suite this test belongs to (example: "CalculatorTest").
215
+ # @param [String] service the service name for this test (optional, inherited from test session if not provided)
216
+ # @param [Hash<String,String>] tags extra tags which should be added to the test.
217
+ # @return [Object] If a block is provided, returns the result of the block execution.
218
+ # @return [Datadog::CI::Test] If no block is provided, returns the active,
219
+ # unfinished {Datadog::CI::Test}.
220
+ # @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
221
+ # @yield Optional block where newly created {Datadog::CI::Test} captures the execution.
222
+ # @yieldparam [Datadog::CI::Test] ci_test the newly created and active [Datadog::CI::Test]
223
+ # @yieldparam [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
224
+ def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
225
+ recorder.trace_test(test_name, test_suite_name, service: service, tags: tags, &block)
226
+ end
227
+
228
+ # Same as {.trace_test} but it does not accept a block.
229
+ # Raises an error if a test is already active.
230
+ #
231
+ # Usage:
232
+ #
233
+ # ```
234
+ # ci_test = Datadog::CI.start_test(
235
+ # "test_add_two_numbers",
236
+ # "calculator_tests",
237
+ # service: "my-web-site-tests",
238
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
239
+ # )
240
+ # # ... run test here ...
241
+ # ci_test.finish
242
+ # ```
243
+ #
244
+ # @param [String] test_name {Datadog::CI::Test} name (example: "test_add_two_numbers").
245
+ # @param [String] test_suite_name name of test suite this test belongs to (example: "CalculatorTest").
246
+ # @param [String] service the service name for this span (optional, inherited from test session if not provided)
247
+ # @param [Hash<String,String>] tags extra tags which should be added to the test.
248
+ # @return [Datadog::CI::Test] Returns the active, unfinished {Datadog::CI::Test}.
249
+ # @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
250
+ def start_test(test_name, test_suite_name, service: nil, tags: {})
251
+ recorder.trace_test(test_name, test_suite_name, service: service, tags: tags)
252
+ end
253
+
254
+ # Trace any custom span inside a test. For example, you could trace:
255
+ # - cucumber step
256
+ # - database query
257
+ # - any custom operation you want to see in your trace view
258
+ #
259
+ # You can use this method with a <tt>do-block</tt> like:
260
+ #
261
+ # ```
262
+ # Datadog::CI.trace(
263
+ # "step",
264
+ # "Given I have 42 cucumbers",
265
+ # tags: {}
266
+ # ) do
267
+ # run_operation
268
+ # end
269
+ # ```
270
+ #
271
+ # The {.trace} method can also be used without a block in this way:
272
+ # ```
273
+ # ci_span = Datadog::CI.trace(
274
+ # "step",
275
+ # "Given I have 42 cucumbers",
276
+ # tags: {}
277
+ # )
278
+ # # ... run test here ...
279
+ # ci_span.finish
280
+ # ```
281
+ # Remember that in this case, calling {Datadog::CI::Span#finish} is mandatory.
282
+ #
283
+ # @param [String] span_type custom, user-defined span type (for example "step" or "query").
284
+ # @param [String] span_name the resource this span refers, or `test` if it's missing
285
+ # @param [Hash<String,String>] tags extra tags which should be added to the span.
286
+ # @return [Object] If a block is provided, returns the result of the block execution.
287
+ # @return [Datadog::CI::Span] If no block is provided, returns the active,
288
+ # unfinished {Datadog::CI::Span}.
289
+ # @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
290
+ # @yield Optional block where newly created {Datadog::CI::Span} captures the execution.
291
+ # @yieldparam [Datadog::CI::Span] ci_span the newly created and active [Datadog::CI::Span]
292
+ # @yieldparam [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
293
+ def trace(span_type, span_name, tags: {}, &block)
294
+ recorder.trace(span_type, span_name, tags: tags, &block)
295
+ end
296
+
297
+ # The active, unfinished custom span if it matches given type.
298
+ # If no span is active, or if the active span is not a custom span with given type, returns nil.
299
+ #
300
+ # The active span belongs to an {.active_test}.
301
+ #
302
+ # Usage:
303
+ #
304
+ # ```
305
+ # # start span
306
+ # Datadog::CI.trace(
307
+ # "step",
308
+ # "Given I have 42 cucumbers",
309
+ # tags: {}
310
+ # )
311
+ #
312
+ # # somewhere else, access the active "step" span
313
+ # step_span = Datadog::CI.active_span("step")
314
+ # step_span.finish()
315
+ # ```
316
+ #
317
+ # @param [String] span_type type of the span to retrieve (for example "step" or "query") that was provided to {.trace}
318
+ # @return [Datadog::CI::Span] the active span
319
+ # @return [nil] if no span is active, or if the active span is not a custom span with given type
320
+ def active_span(span_type)
321
+ span = recorder.active_span
322
+ span if span && span.span_type == span_type
323
+ end
324
+
325
+ # The active, unfinished test span.
326
+ #
327
+ # Usage:
328
+ #
329
+ # ```
330
+ # # start a test
331
+ # Datadog::CI.start_test(
332
+ # "test_add_two_numbers",
333
+ # "calculator_tests",
334
+ # service: "my-web-site-tests",
335
+ # tags: { Datadog::CI::Ext::Test::TAG_FRAMEWORK => "my-test-framework" }
336
+ # )
337
+ #
338
+ # # somewhere else, access the active test
339
+ # test_span = Datadog::CI.active_test
340
+ # test_span.passed!
341
+ # test_span.finish
342
+ # ```
343
+ #
344
+ # @return [Datadog::CI::Test] the active test
345
+ # @return [nil] if no test is active
346
+ def active_test
347
+ recorder.active_test
348
+ end
349
+
350
+ # Internal only, to finish a test use {Datadog::CI::Test#finish}
351
+ # @private
352
+ def deactivate_test(test)
353
+ recorder.deactivate_test(test)
354
+ end
355
+
356
+ # Internal only, to finish a test session use {Datadog::CI::TestSession#finish}
357
+ # @private
358
+ def deactivate_test_session
359
+ recorder.deactivate_test_session
360
+ end
361
+
362
+ # Internal only, to finish a test module use {Datadog::CI::TestModule#finish}
363
+ # @private
364
+ def deactivate_test_module
365
+ recorder.deactivate_test_module
366
+ end
367
+
368
+ # Internal only, to finish a test suite use {Datadog::CI::TestSuite#finish}
369
+ # @private
370
+ def deactivate_test_suite(test_suite_name)
371
+ recorder.deactivate_test_suite(test_suite_name)
372
+ end
373
+
374
+ private
375
+
376
+ def components
377
+ Datadog.send(:components)
378
+ end
379
+
380
+ def recorder
381
+ components.ci_recorder
382
+ end
383
+ end
13
384
  end
14
385
  end
15
386
 
@@ -18,6 +389,6 @@ require_relative "ci/contrib/cucumber/integration"
18
389
  require_relative "ci/contrib/rspec/integration"
19
390
  require_relative "ci/contrib/minitest/integration"
20
391
 
21
- # Extensions
22
- require_relative "ci/extensions"
23
- Datadog::CI::Extensions.activate!
392
+ # Configuration extensions
393
+ require_relative "ci/configuration/extensions"
394
+ Datadog::CI::Configuration::Extensions.activate!
@@ -0,0 +1,23 @@
1
+ module Datadog
2
+ module CI
3
+ class ConcurrentSpan < Span
4
+ @mutex: Thread::Mutex
5
+
6
+ def initialize: (Datadog::Tracing::SpanOperation tracer_span) -> void
7
+ def passed!: () -> void
8
+ def failed!: (?exception: untyped?) -> void
9
+ def skipped!: (?exception: untyped?, ?reason: String?) -> void
10
+ def get_tag: (String key) -> untyped?
11
+ def set_tag: (String key, untyped? value) -> void
12
+ def set_metric: (String key, untyped value) -> void
13
+ def finish: () -> void
14
+ def set_tags: (Hash[untyped, untyped] tags) -> void
15
+
16
+ def set_environment_runtime_tags: () -> void
17
+
18
+ def set_default_tags: () -> void
19
+
20
+ def synchronize: () { () -> untyped } -> untyped
21
+ end
22
+ end
23
+ end
@@ -2,6 +2,10 @@ module Datadog
2
2
  module CI
3
3
  module Configuration
4
4
  module Components : Datadog::Core::Configuration::Components
5
+ @ci_recorder: Datadog::CI::TestVisibility::Recorder
6
+
7
+ attr_reader ci_recorder: Datadog::CI::TestVisibility::Recorder
8
+
5
9
  def initialize: (untyped settings) -> void
6
10
 
7
11
  def activate_ci!: (untyped settings) -> untyped
@@ -9,6 +13,8 @@ module Datadog
9
13
  def build_agentless_transport: (untyped settings) -> Datadog::CI::TestVisibility::Transport?
10
14
  def build_evp_proxy_transport: (untyped settings, untyped agent_settings) -> Datadog::CI::TestVisibility::Transport
11
15
  def can_use_evp_proxy?: (untyped settings, untyped agent_settings) -> bool
16
+ def serializers_factory: (untyped settings) -> (singleton(Datadog::CI::TestVisibility::Serializers::Factories::TestSuiteLevel) | singleton(Datadog::CI::TestVisibility::Serializers::Factories::TestLevel))
17
+ def check_dd_site: (untyped settings) -> void
12
18
  end
13
19
  end
14
20
  end