datadog-ci 1.3.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -2
  3. data/README.md +1 -0
  4. data/ext/datadog_cov/datadog_cov.c +1 -1
  5. data/lib/datadog/ci/configuration/components.rb +25 -11
  6. data/lib/datadog/ci/configuration/settings.rb +19 -1
  7. data/lib/datadog/ci/contrib/cucumber/configuration_override.rb +37 -0
  8. data/lib/datadog/ci/contrib/cucumber/formatter.rb +5 -5
  9. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +9 -1
  10. data/lib/datadog/ci/contrib/cucumber/patcher.rb +3 -3
  11. data/lib/datadog/ci/contrib/minitest/runner.rb +16 -0
  12. data/lib/datadog/ci/contrib/minitest/test.rb +1 -0
  13. data/lib/datadog/ci/contrib/rspec/example.rb +67 -39
  14. data/lib/datadog/ci/contrib/rspec/example_group.rb +1 -1
  15. data/lib/datadog/ci/ext/settings.rb +3 -0
  16. data/lib/datadog/ci/ext/telemetry.rb +1 -0
  17. data/lib/datadog/ci/ext/test.rb +11 -11
  18. data/lib/datadog/ci/ext/transport.rb +1 -0
  19. data/lib/datadog/ci/git/local_repository.rb +32 -13
  20. data/lib/datadog/ci/remote/component.rb +50 -0
  21. data/lib/datadog/ci/remote/library_settings.rb +91 -0
  22. data/lib/datadog/ci/{transport/remote_settings_api.rb → remote/library_settings_client.rb} +11 -56
  23. data/lib/datadog/ci/test.rb +8 -1
  24. data/lib/datadog/ci/test_optimisation/component.rb +12 -16
  25. data/lib/datadog/ci/test_retries/component.rb +84 -0
  26. data/lib/datadog/ci/test_retries/null_component.rb +28 -0
  27. data/lib/datadog/ci/test_retries/strategy/base.rb +19 -0
  28. data/lib/datadog/ci/test_retries/strategy/no_retry.rb +16 -0
  29. data/lib/datadog/ci/test_retries/strategy/retry_failed.rb +37 -0
  30. data/lib/datadog/ci/test_suite.rb +39 -18
  31. data/lib/datadog/ci/test_visibility/component.rb +45 -47
  32. data/lib/datadog/ci/test_visibility/null_component.rb +6 -0
  33. data/lib/datadog/ci/test_visibility/telemetry.rb +3 -0
  34. data/lib/datadog/ci/version.rb +2 -2
  35. metadata +13 -6
  36. data/lib/datadog/ci/contrib/cucumber/step.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 57da167788887f67dc501a3dc2869c425754fec3cdefa45770af22364003fb20
4
- data.tar.gz: ed6645a822db10fbae793c5b226b9d41ca4dbea67449f545135f2571be3894c1
3
+ metadata.gz: 0ddc261b14aac25efcc4c94bf30e18962e714a83e35d47cb3a1f3210d640fd5a
4
+ data.tar.gz: 47acdc6af95b2ab2e7385a22d0c82359e63ff0eabb8f0dfdf1bd0197f73eb6ee
5
5
  SHA512:
6
- metadata.gz: f4586bbf8a10b5bf2b262bafefd222ef981624ced261755bd9d43652506400f6b939e5cd3595b7af0c66a193581328937aabe5b9246efd4cb3a0fa088b9e0ccf
7
- data.tar.gz: 4169cf67306d9d080e264897ed2cffb5103a9b98ca176fea2784ff3293d4b9dd3decd62df3848b2a7ade783f5dfe6925b86fa7d4727b45de51764af5bc6e1b4a
6
+ metadata.gz: 1a774a633e3da98fc313dcf2bfeb14c02e231fc52fc7abced54ae4246afd9930fe4598d5885e39a999ede252da6c9aa0262e041aad7b4873d4fcdb8349dab673
7
+ data.tar.gz: ed05b4354183b31a619f9f18aa22c547dc0ccbfdd829e8fa24e250fe98becd2a434855bb71839325214d017d6e1b79c99dcf681eeb7f820e1508991516722070
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.4.1] - 2024-08-28
4
+
5
+ ### Fixed
6
+
7
+ * fix datadog_cov crash when doing allocation profiling ([#224][])
8
+
9
+ ## [1.4.0] - 2024-08-26
10
+
11
+ ### Added
12
+
13
+ * Auto test retries for cucumber ([#212][])
14
+ * Auto test retries for RSpec ([#213][])
15
+ * Auto test retries for minitest ([#214][])
16
+ * implement auto test retries RFC ([#219][])
17
+
18
+ ### Changed
19
+
20
+ * Skip Before/After hooks in cucumber when scenario is skipped by intelligent test runner ([#211][])
21
+ * gem datadog 2.3 is now minimal required version ([#220][])
22
+ * Enable agentless telemetry when library is running in agentless mode ([#221][])
23
+ * Add Ruby 3.4 to the testing matrix ([#217][])
24
+ * add different fallbacks for unshallowing remotes ([#218][])
25
+ * make itr_enabled config parameter true by default ([#216][])
26
+ * RSpec - don't report test errors if rspec process is quitting ([#215][])
27
+
3
28
  ## [1.3.0] - 2024-07-30
4
29
 
5
30
  ### Added
@@ -290,7 +315,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
290
315
 
291
316
  - Ruby versions < 2.7 no longer supported ([#8][])
292
317
 
293
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.3.0...main
318
+ [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.4.1...main
319
+ [1.4.1]: https://github.com/DataDog/datadog-ci-rb/compare/v1.4.0...v1.4.1
320
+ [1.4.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.3.0...v1.4.0
294
321
  [1.3.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.2.0...v1.3.0
295
322
  [1.2.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.1.0...v1.2.0
296
323
  [1.1.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.0.1...v1.1.0
@@ -413,4 +440,16 @@ Currently test suite level visibility is not used by our instrumentation: it wil
413
440
  [#204]: https://github.com/DataDog/datadog-ci-rb/issues/204
414
441
  [#205]: https://github.com/DataDog/datadog-ci-rb/issues/205
415
442
  [#206]: https://github.com/DataDog/datadog-ci-rb/issues/206
416
- [#207]: https://github.com/DataDog/datadog-ci-rb/issues/207
443
+ [#207]: https://github.com/DataDog/datadog-ci-rb/issues/207
444
+ [#211]: https://github.com/DataDog/datadog-ci-rb/issues/211
445
+ [#212]: https://github.com/DataDog/datadog-ci-rb/issues/212
446
+ [#213]: https://github.com/DataDog/datadog-ci-rb/issues/213
447
+ [#214]: https://github.com/DataDog/datadog-ci-rb/issues/214
448
+ [#215]: https://github.com/DataDog/datadog-ci-rb/issues/215
449
+ [#216]: https://github.com/DataDog/datadog-ci-rb/issues/216
450
+ [#217]: https://github.com/DataDog/datadog-ci-rb/issues/217
451
+ [#218]: https://github.com/DataDog/datadog-ci-rb/issues/218
452
+ [#219]: https://github.com/DataDog/datadog-ci-rb/issues/219
453
+ [#220]: https://github.com/DataDog/datadog-ci-rb/issues/220
454
+ [#221]: https://github.com/DataDog/datadog-ci-rb/issues/221
455
+ [#224]: https://github.com/DataDog/datadog-ci-rb/issues/224
data/README.md CHANGED
@@ -12,6 +12,7 @@ Learn more on our [official website](https://docs.datadoghq.com/tests/) and chec
12
12
 
13
13
  - [Test Visibility](https://docs.datadoghq.com/tests/) - collect metrics and results for your tests
14
14
  - [Intelligent test runner](https://docs.datadoghq.com/intelligent_test_runner/) - save time by selectively running only tests affected by code changes
15
+ - [Auto test retries](https://docs.datadoghq.com/tests/auto_test_retries/?tab=ruby) - retrying failing tests up to N times to avoid failing your build due to flaky tests
15
16
  - [Search and manage CI tests](https://docs.datadoghq.com/tests/search/)
16
17
  - [Enhance developer workflows](https://docs.datadoghq.com/tests/developer_workflows)
17
18
  - [Flaky test management](https://docs.datadoghq.com/tests/guides/flaky_test_management/)
@@ -249,7 +249,7 @@ static int process_instantiated_klass(st_data_t key, st_data_t _value, st_data_t
249
249
  }
250
250
 
251
251
  VALUE filename = RARRAY_AREF(source_location, 0);
252
- if (filename == Qnil)
252
+ if (filename == Qnil || !RB_TYPE_P(filename, T_STRING))
253
253
  {
254
254
  return ST_CONTINUE;
255
255
  }
@@ -4,9 +4,13 @@ require "datadog/core/telemetry/ext"
4
4
 
5
5
  require_relative "../ext/settings"
6
6
  require_relative "../git/tree_uploader"
7
+ require_relative "../remote/component"
8
+ require_relative "../remote/library_settings_client"
7
9
  require_relative "../test_optimisation/component"
8
10
  require_relative "../test_optimisation/coverage/transport"
9
11
  require_relative "../test_optimisation/coverage/writer"
12
+ require_relative "../test_retries/component"
13
+ require_relative "../test_retries/null_component"
10
14
  require_relative "../test_visibility/component"
11
15
  require_relative "../test_visibility/flush"
12
16
  require_relative "../test_visibility/null_component"
@@ -15,7 +19,6 @@ require_relative "../test_visibility/serializers/factories/test_suite_level"
15
19
  require_relative "../test_visibility/transport"
16
20
  require_relative "../transport/adapters/telemetry_webmock_safe_adapter"
17
21
  require_relative "../transport/api/builder"
18
- require_relative "../transport/remote_settings_api"
19
22
  require_relative "../utils/identity"
20
23
  require_relative "../utils/parsing"
21
24
  require_relative "../utils/test_run"
@@ -26,11 +29,14 @@ module Datadog
26
29
  module Configuration
27
30
  # Adds CI behavior to Datadog trace components
28
31
  module Components
29
- attr_reader :test_visibility, :test_optimisation
32
+ attr_reader :test_visibility, :test_optimisation, :git_tree_upload_worker, :ci_remote, :test_retries
30
33
 
31
34
  def initialize(settings)
32
35
  @test_optimisation = nil
33
36
  @test_visibility = TestVisibility::NullComponent.new
37
+ @git_tree_upload_worker = DummyWorker.new
38
+ @ci_remote = nil
39
+ @test_retries = TestRetries::NullComponent.new
34
40
 
35
41
  # Activate CI mode if enabled
36
42
  if settings.ci.enabled
@@ -45,6 +51,7 @@ module Datadog
45
51
 
46
52
  @test_visibility&.shutdown!
47
53
  @test_optimisation&.shutdown!
54
+ @git_tree_upload_worker&.stop
48
55
  end
49
56
 
50
57
  def activate_ci!(settings)
@@ -102,14 +109,19 @@ module Datadog
102
109
 
103
110
  settings.tracing.test_mode.writer_options = trace_writer_options
104
111
 
112
+ @git_tree_upload_worker = build_git_upload_worker(settings, test_visibility_api)
113
+ @ci_remote = Remote::Component.new(
114
+ library_settings_client: build_library_settings_client(settings, test_visibility_api)
115
+ )
116
+ @test_retries = TestRetries::Component.new(
117
+ retry_failed_tests_enabled: settings.ci.retry_failed_tests_enabled,
118
+ retry_failed_tests_max_attempts: settings.ci.retry_failed_tests_max_attempts,
119
+ retry_failed_tests_total_limit: settings.ci.retry_failed_tests_total_limit
120
+ )
105
121
  # @type ivar @test_optimisation: Datadog::CI::TestOptimisation::Component
106
122
  @test_optimisation = build_test_optimisation(settings, test_visibility_api)
107
-
108
123
  @test_visibility = TestVisibility::Component.new(
109
- test_optimisation: @test_optimisation,
110
- test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility,
111
- remote_settings_api: build_remote_settings_client(settings, test_visibility_api),
112
- git_tree_upload_worker: build_git_upload_worker(settings, test_visibility_api)
124
+ test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility
113
125
  )
114
126
  end
115
127
 
@@ -216,8 +228,8 @@ module Datadog
216
228
  end
217
229
  end
218
230
 
219
- def build_remote_settings_client(settings, api)
220
- Transport::RemoteSettingsApi.new(
231
+ def build_library_settings_client(settings, api)
232
+ Remote::LibrarySettingsClient.new(
221
233
  api: api,
222
234
  dd_env: settings.env,
223
235
  config_tags: custom_configuration(settings)
@@ -254,11 +266,13 @@ module Datadog
254
266
  # for test visibility we want to enable it by default unless explicitly disabled
255
267
  # NOTE: before agentless mode is released, we only enable telemetry when running with Datadog Agent
256
268
  env_telemetry_enabled = ENV[Core::Telemetry::Ext::ENV_ENABLED]
257
- settings.telemetry.enabled = !settings.ci.agentless_mode_enabled &&
258
- (env_telemetry_enabled.nil? || Utils::Parsing.convert_to_bool(env_telemetry_enabled))
269
+ settings.telemetry.enabled = env_telemetry_enabled.nil? || Utils::Parsing.convert_to_bool(env_telemetry_enabled)
259
270
 
260
271
  return unless settings.telemetry.enabled
261
272
 
273
+ settings.telemetry.agentless_enabled = true if settings.ci.agentless_mode_enabled
274
+ settings.telemetry.shutdown_timeout_seconds = 60.0
275
+
262
276
  begin
263
277
  require "datadog/core/environment/identity"
264
278
  require "datadog/core/telemetry/http/adapters/net"
@@ -59,7 +59,7 @@ module Datadog
59
59
  option :itr_enabled do |o|
60
60
  o.type :bool
61
61
  o.env CI::Ext::Settings::ENV_ITR_ENABLED
62
- o.default false
62
+ o.default true
63
63
  end
64
64
 
65
65
  option :git_metadata_upload_enabled do |o|
@@ -88,6 +88,24 @@ module Datadog
88
88
  o.default true
89
89
  end
90
90
 
91
+ option :retry_failed_tests_enabled do |o|
92
+ o.type :bool
93
+ o.env CI::Ext::Settings::ENV_RETRY_FAILED_TESTS_ENABLED
94
+ o.default true
95
+ end
96
+
97
+ option :retry_failed_tests_max_attempts do |o|
98
+ o.type :int
99
+ o.env CI::Ext::Settings::ENV_RETRY_FAILED_TESTS_MAX_ATTEMPTS
100
+ o.default 5
101
+ end
102
+
103
+ option :retry_failed_tests_total_limit do |o|
104
+ o.type :int
105
+ o.env CI::Ext::Settings::ENV_RETRY_FAILED_TESTS_TOTAL_LIMIT
106
+ o.default 1000
107
+ end
108
+
91
109
  define_method(:instrument) do |integration_name, options = {}, &block|
92
110
  return unless enabled
93
111
 
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "formatter"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Contrib
8
+ module Cucumber
9
+ # Changes behaviour of Cucumber::Configuration class
10
+ module ConfigurationOverride
11
+ def self.included(base)
12
+ base.prepend(InstanceMethods)
13
+ end
14
+
15
+ # Instance methods for configuration
16
+ module InstanceMethods
17
+ def retry_attempts
18
+ super if !datadog_test_retries_component&.retry_failed_tests_enabled
19
+
20
+ datadog_test_retries_component&.retry_failed_tests_max_attempts
21
+ end
22
+
23
+ def retry_total_tests
24
+ super if !datadog_test_retries_component&.retry_failed_tests_enabled
25
+
26
+ datadog_test_retries_component&.retry_failed_tests_total_limit
27
+ end
28
+
29
+ def datadog_test_retries_component
30
+ Datadog.send(:components).test_retries
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -20,7 +20,7 @@ module Datadog
20
20
 
21
21
  @current_test_suite = nil
22
22
 
23
- @failed_tests_count = 0
23
+ @failed_test_suites_count = 0
24
24
 
25
25
  bind_events(config)
26
26
  end
@@ -46,10 +46,12 @@ module Datadog
46
46
  end
47
47
 
48
48
  def on_test_run_finished(event)
49
+ finish_current_test_suite
50
+
49
51
  if event.respond_to?(:success)
50
52
  finish_session(event.success)
51
53
  else
52
- finish_session(@failed_tests_count.zero?)
54
+ finish_session(@failed_test_suites_count.zero?)
53
55
  end
54
56
  end
55
57
 
@@ -86,7 +88,6 @@ module Datadog
86
88
  return if test_span.nil?
87
89
 
88
90
  finish_span(test_span, event.result)
89
- @failed_tests_count += 1 if test_span.failed?
90
91
  end
91
92
 
92
93
  def on_test_step_started(event)
@@ -128,8 +129,6 @@ module Datadog
128
129
  end
129
130
 
130
131
  def finish_session(result)
131
- finish_current_test_suite
132
-
133
132
  test_session = test_visibility_component.active_test_session
134
133
  test_module = test_visibility_component.active_test_module
135
134
 
@@ -155,6 +154,7 @@ module Datadog
155
154
 
156
155
  def finish_current_test_suite
157
156
  @current_test_suite&.finish
157
+ @failed_test_suites_count += 1 if @current_test_suite&.failed?
158
158
 
159
159
  @current_test_suite = nil
160
160
  end
@@ -6,7 +6,7 @@ module Datadog
6
6
  module CI
7
7
  module Contrib
8
8
  module Cucumber
9
- # Instrumentation for Cucumber
9
+ # Instrumentation for Cucumber::Runtime class
10
10
  module Instrumentation
11
11
  def self.included(base)
12
12
  base.prepend(InstanceMethods)
@@ -21,6 +21,14 @@ module Datadog
21
21
  @datadog_formatter ||= CI::Contrib::Cucumber::Formatter.new(@configuration)
22
22
  [@datadog_formatter] + existing_formatters
23
23
  end
24
+
25
+ def begin_scenario(test_case)
26
+ if Datadog::CI.active_test&.skipped_by_itr?
27
+ raise ::Cucumber::Core::Test::Result::Skipped, CI::Ext::Test::ITR_TEST_SKIP_REASON
28
+ end
29
+
30
+ super
31
+ end
24
32
  end
25
33
  end
26
34
  end
@@ -3,13 +3,13 @@
3
3
  require "datadog/tracing/contrib/patcher"
4
4
 
5
5
  require_relative "instrumentation"
6
- require_relative "step"
6
+ require_relative "configuration_override"
7
7
 
8
8
  module Datadog
9
9
  module CI
10
10
  module Contrib
11
11
  module Cucumber
12
- # Patcher enables patching of 'cucumber' module.
12
+ # Patches 'cucumber' gem.
13
13
  module Patcher
14
14
  include Datadog::Tracing::Contrib::Patcher
15
15
 
@@ -21,7 +21,7 @@ module Datadog
21
21
 
22
22
  def patch
23
23
  ::Cucumber::Runtime.include(Instrumentation)
24
- ::Cucumber::Core::Test::Step.include(Datadog::CI::Contrib::Cucumber::Step)
24
+ ::Cucumber::Configuration.include(ConfigurationOverride)
25
25
  end
26
26
  end
27
27
  end
@@ -28,6 +28,18 @@ module Datadog
28
28
  test_visibility_component.start_test_module(Ext::FRAMEWORK)
29
29
  end
30
30
 
31
+ def run_one_method(klass, method_name)
32
+ return super unless datadog_configuration[:enabled]
33
+
34
+ result = nil
35
+
36
+ test_retries_component.with_retries do
37
+ result = super
38
+ end
39
+
40
+ result
41
+ end
42
+
31
43
  private
32
44
 
33
45
  def datadog_configuration
@@ -37,6 +49,10 @@ module Datadog
37
49
  def test_visibility_component
38
50
  Datadog.send(:components).test_visibility
39
51
  end
52
+
53
+ def test_retries_component
54
+ Datadog.send(:components).test_retries
55
+ end
40
56
  end
41
57
  end
42
58
  end
@@ -71,6 +71,7 @@ module Datadog
71
71
  when "S"
72
72
  span.skipped!(reason: failure.message)
73
73
  end
74
+
74
75
  span.finish
75
76
  end
76
77
 
@@ -34,50 +34,74 @@ module Datadog
34
34
 
35
35
  if ci_queue?
36
36
  suite_name = "#{suite_name} (ci-queue running example [#{test_name}])"
37
- test_suite_span = test_visibility_component.start_test_suite(suite_name)
37
+ ci_queue_test_span = test_visibility_component.start_test_suite(suite_name)
38
38
  end
39
39
 
40
- test_visibility_component.trace_test(
41
- test_name,
42
- suite_name,
43
- tags: {
44
- CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
45
- CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::RSpec::Integration.version.to_s,
46
- CI::Ext::Test::TAG_SOURCE_FILE => Git::LocalRepository.relative_to_root(metadata[:file_path]),
47
- CI::Ext::Test::TAG_SOURCE_START => metadata[:line_number].to_s,
48
- CI::Ext::Test::TAG_PARAMETERS => Utils::TestRun.test_parameters(
49
- metadata: {"scoped_id" => metadata[:scoped_id]}
50
- )
51
- },
52
- service: datadog_configuration[:service_name]
53
- ) do |test_span|
54
- test_span&.itr_unskippable! if metadata[CI::Ext::Test::ITR_UNSKIPPABLE_OPTION]
55
-
56
- metadata[:skip] = CI::Ext::Test::ITR_TEST_SKIP_REASON if test_span&.skipped_by_itr?
57
-
58
- result = super
59
-
60
- case execution_result.status
61
- when :passed
62
- test_span&.passed!
63
- test_suite_span&.passed!
64
- when :failed
65
- test_span&.failed!(exception: execution_result.exception)
66
- test_suite_span&.failed!
67
- else
68
- # :pending or nil
69
- test_span&.skipped!(
70
- reason: execution_result.pending_message,
71
- exception: execution_result.pending_exception
72
- )
73
-
74
- test_suite_span&.skipped!
40
+ # don't report test to RSpec::Core::Reporter until retries are done
41
+ @skip_reporting = true
42
+
43
+ test_retries_component.with_retries do
44
+ test_visibility_component.trace_test(
45
+ test_name,
46
+ suite_name,
47
+ tags: {
48
+ CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
49
+ CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::RSpec::Integration.version.to_s,
50
+ CI::Ext::Test::TAG_SOURCE_FILE => Git::LocalRepository.relative_to_root(metadata[:file_path]),
51
+ CI::Ext::Test::TAG_SOURCE_START => metadata[:line_number].to_s,
52
+ CI::Ext::Test::TAG_PARAMETERS => Utils::TestRun.test_parameters(
53
+ metadata: {"scoped_id" => metadata[:scoped_id]}
54
+ )
55
+ },
56
+ service: datadog_configuration[:service_name]
57
+ ) do |test_span|
58
+ test_span&.itr_unskippable! if metadata[CI::Ext::Test::ITR_UNSKIPPABLE_OPTION]
59
+
60
+ metadata[:skip] = CI::Ext::Test::ITR_TEST_SKIP_REASON if test_span&.skipped_by_itr?
61
+
62
+ # before each run remove any previous exception
63
+ @exception = nil
64
+
65
+ result = super
66
+
67
+ # In case when test job is canceled and RSpec is quitting we don't want to report the last test
68
+ # before RSpec context unwinds. This test might have some unrelated errors that we don't want to
69
+ # report.
70
+ return result if ::RSpec.world.wants_to_quit
71
+
72
+ case execution_result.status
73
+ when :passed
74
+ test_span&.passed!
75
+ when :failed
76
+ test_span&.failed!(exception: execution_result.exception)
77
+ else
78
+ # :pending or nil
79
+ test_span&.skipped!(
80
+ reason: execution_result.pending_message,
81
+ exception: execution_result.pending_exception
82
+ )
83
+ end
75
84
  end
85
+ end
76
86
 
77
- test_suite_span&.finish
87
+ # after retries are done, we can report the test to RSpec
88
+ @skip_reporting = false
78
89
 
79
- result
80
- end
90
+ # this is a special case for ci-queue, we need to finish the test suite span
91
+ ci_queue_test_span&.finish
92
+
93
+ # Finish spec with latest retry's result
94
+ # TODO: when implementing new test retries make sure to clean @exception before calling this method
95
+ # if test passed at least once
96
+ finish(reporter)
97
+ end
98
+
99
+ def finish(reporter)
100
+ # by default finish test but do not report it to RSpec::Core::Reporter
101
+ # it is going to be reported once after retries are done
102
+ return super unless @skip_reporting
103
+
104
+ super(::RSpec::Core::NullReporter)
81
105
  end
82
106
 
83
107
  private
@@ -103,6 +127,10 @@ module Datadog
103
127
  Datadog.send(:components).test_visibility
104
128
  end
105
129
 
130
+ def test_retries_component
131
+ Datadog.send(:components).test_retries
132
+ end
133
+
106
134
  def ci_queue?
107
135
  !!defined?(::RSpec::Queue::ExampleExtension) &&
108
136
  self.class.ancestors.include?(::RSpec::Queue::ExampleExtension)
@@ -26,7 +26,7 @@ module Datadog
26
26
  success = super
27
27
  return success unless test_suite
28
28
 
29
- if success && test_suite.passed_tests_count > 0
29
+ if success && test_suite.any_passed?
30
30
  test_suite.passed!
31
31
  elsif success
32
32
  test_suite.skipped!
@@ -15,6 +15,9 @@ module Datadog
15
15
  ENV_ITR_CODE_COVERAGE_EXCLUDED_BUNDLE_PATH = "DD_CIVISIBILITY_ITR_CODE_COVERAGE_EXCLUDED_BUNDLE_PATH"
16
16
  ENV_ITR_CODE_COVERAGE_USE_SINGLE_THREADED_MODE = "DD_CIVISIBILITY_ITR_CODE_COVERAGE_USE_SINGLE_THREADED_MODE"
17
17
  ENV_ITR_TEST_IMPACT_ANALYSIS_USE_ALLOCATION_TRACING = "DD_CIVISIBILITY_ITR_TEST_IMPACT_ANALYSIS_USE_ALLOCATION_TRACING"
18
+ ENV_RETRY_FAILED_TESTS_ENABLED = "DD_CIVISIBILITY_FLAKY_RETRY_ENABLED"
19
+ ENV_RETRY_FAILED_TESTS_MAX_ATTEMPTS = "DD_CIVISIBILITY_FLAKY_RETRY_COUNT"
20
+ ENV_RETRY_FAILED_TESTS_TOTAL_LIMIT = "DD_CIVISIBILITY_TOTAL_FLAKY_RETRY_COUNT"
18
21
 
19
22
  # Source: https://docs.datadoghq.com/getting_started/site/
20
23
  DD_SITE_ALLOWLIST = %w[
@@ -62,6 +62,7 @@ module Datadog
62
62
  TAG_IS_UNSUPPORTED_CI = "is_unsupported_ci"
63
63
  TAG_BROWSER_DRIVER = "browser_driver"
64
64
  TAG_IS_RUM = "is_rum"
65
+ TAG_IS_RETRY = "is_retry"
65
66
  TAG_LIBRARY = "library"
66
67
  TAG_ENDPOINT = "endpoint"
67
68
  TAG_ERROR_TYPE = "error_type"
@@ -8,7 +8,7 @@ module Datadog
8
8
  module Test
9
9
  CONTEXT_ORIGIN = "ciapp-test"
10
10
 
11
- # Base test visibility tags
11
+ # Test visibility tags
12
12
  TAG_FRAMEWORK = "test.framework"
13
13
  TAG_FRAMEWORK_VERSION = "test.framework_version"
14
14
  TAG_NAME = "test.name"
@@ -23,7 +23,8 @@ module Datadog
23
23
  TAG_CODEOWNERS = "test.codeowners"
24
24
  TAG_PARAMETERS = "test.parameters"
25
25
 
26
- # ITR tags
26
+ # Test optimisation tags
27
+ TAG_CODE_COVERAGE_ENABLED = "test.code_coverage.enabled"
27
28
  TAG_ITR_TEST_SKIPPING_ENABLED = "test.itr.tests_skipping.enabled"
28
29
  TAG_ITR_TEST_SKIPPING_TYPE = "test.itr.tests_skipping.type"
29
30
  TAG_ITR_TEST_SKIPPING_COUNT = "test.itr.tests_skipping.count"
@@ -32,11 +33,9 @@ module Datadog
32
33
  TAG_ITR_UNSKIPPABLE = "test.itr.unskippable"
33
34
  TAG_ITR_FORCED_RUN = "test.itr.forced_run"
34
35
 
35
- # Code coverage tags
36
- TAG_CODE_COVERAGE_ENABLED = "test.code_coverage.enabled"
37
-
38
- # Special tags, not sent to the backend.
39
- # these tags are special and used to correlate tests with the test sessions, suites, and modules
36
+ # Internal tags, they are not sent to the backend.
37
+ # These tags are internal to this library and used to correlate tests with
38
+ # the test sessions, suites, and modules.
40
39
  TAG_TEST_SESSION_ID = "_test.session_id"
41
40
  TAG_TEST_MODULE_ID = "_test.module_id"
42
41
  TAG_TEST_SUITE_ID = "_test.suite_id"
@@ -50,8 +49,7 @@ module Datadog
50
49
  TAG_RUNTIME_VERSION = "runtime.version"
51
50
 
52
51
  # Tags for browser tests
53
- # true if Datadog RUM was detected in the page(s) loaded by Selenium
54
- TAG_IS_RUM_ACTIVE = "test.is_rum_active"
52
+ TAG_IS_RUM_ACTIVE = "test.is_rum_active" # true if Datadog RUM was detected in the page(s) loaded by Selenium
55
53
  TAG_BROWSER_DRIVER = "test.browser.driver"
56
54
  # version of selenium driver used
57
55
  TAG_BROWSER_DRIVER_VERSION = "test.browser.driver_version"
@@ -60,6 +58,9 @@ module Datadog
60
58
  # version of the browser, if multiple browsers or multiple versions then this tag is empty
61
59
  TAG_BROWSER_VERSION = "test.browser.version"
62
60
 
61
+ # Tags for test retries
62
+ TAG_IS_RETRY = "test.is_retry" # true if test was retried by datadog-ci library
63
+
63
64
  # internal APM tag to mark a span as a test span
64
65
  TAG_SPAN_KIND = "span.kind"
65
66
  SPAN_KIND_TEST = "test"
@@ -68,8 +69,7 @@ module Datadog
68
69
  INHERITABLE_TAGS = [TAG_FRAMEWORK, TAG_FRAMEWORK_VERSION].freeze
69
70
 
70
71
  # could be either "test" or "suite" depending on whether we skip individual tests or whole suites
71
- # we use test skipping for Ruby
72
- ITR_TEST_SKIPPING_MODE = "test"
72
+ ITR_TEST_SKIPPING_MODE = "test" # we always skip tests (not suites) in Ruby
73
73
  ITR_TEST_SKIP_REASON = "Skipped by Datadog's intelligent test runner"
74
74
  ITR_UNSKIPPABLE_OPTION = :datadog_itr_unskippable
75
75
 
@@ -36,6 +36,7 @@ module Datadog
36
36
  DD_API_SETTINGS_RESPONSE_CODE_COVERAGE_KEY = "code_coverage"
37
37
  DD_API_SETTINGS_RESPONSE_TESTS_SKIPPING_KEY = "tests_skipping"
38
38
  DD_API_SETTINGS_RESPONSE_REQUIRE_GIT_KEY = "require_git"
39
+ DD_API_SETTINGS_RESPONSE_FLAKY_TEST_RETRIES_KEY = "flaky_test_retries_enabled"
39
40
  DD_API_SETTINGS_RESPONSE_DEFAULT = {DD_API_SETTINGS_RESPONSE_ITR_ENABLED_KEY => false}.freeze
40
41
 
41
42
  DD_API_GIT_SEARCH_COMMITS_PATH = "/api/v2/git/repository/search_commits"