datadog-ci 0.3.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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