datadog-ci 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -2
  3. data/lib/datadog/ci/configuration/components.rb +25 -11
  4. data/lib/datadog/ci/configuration/settings.rb +19 -1
  5. data/lib/datadog/ci/contrib/cucumber/configuration_override.rb +37 -0
  6. data/lib/datadog/ci/contrib/cucumber/formatter.rb +5 -5
  7. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +9 -1
  8. data/lib/datadog/ci/contrib/cucumber/patcher.rb +3 -3
  9. data/lib/datadog/ci/contrib/minitest/runner.rb +16 -0
  10. data/lib/datadog/ci/contrib/minitest/test.rb +1 -0
  11. data/lib/datadog/ci/contrib/rspec/example.rb +67 -39
  12. data/lib/datadog/ci/contrib/rspec/example_group.rb +1 -1
  13. data/lib/datadog/ci/ext/settings.rb +3 -0
  14. data/lib/datadog/ci/ext/telemetry.rb +1 -0
  15. data/lib/datadog/ci/ext/test.rb +11 -11
  16. data/lib/datadog/ci/ext/transport.rb +1 -0
  17. data/lib/datadog/ci/git/local_repository.rb +32 -13
  18. data/lib/datadog/ci/remote/component.rb +50 -0
  19. data/lib/datadog/ci/remote/library_settings.rb +91 -0
  20. data/lib/datadog/ci/{transport/remote_settings_api.rb → remote/library_settings_client.rb} +11 -56
  21. data/lib/datadog/ci/test.rb +8 -1
  22. data/lib/datadog/ci/test_optimisation/component.rb +12 -16
  23. data/lib/datadog/ci/test_retries/component.rb +84 -0
  24. data/lib/datadog/ci/test_retries/null_component.rb +28 -0
  25. data/lib/datadog/ci/test_retries/strategy/base.rb +19 -0
  26. data/lib/datadog/ci/test_retries/strategy/no_retry.rb +16 -0
  27. data/lib/datadog/ci/test_retries/strategy/retry_failed.rb +37 -0
  28. data/lib/datadog/ci/test_suite.rb +39 -18
  29. data/lib/datadog/ci/test_visibility/component.rb +45 -47
  30. data/lib/datadog/ci/test_visibility/null_component.rb +6 -0
  31. data/lib/datadog/ci/test_visibility/telemetry.rb +3 -0
  32. data/lib/datadog/ci/version.rb +1 -1
  33. metadata +13 -6
  34. 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: 614d612dad9b7e29104499934b7e80b44a0cd5f60ec5135593a3bccd9df5fc9c
4
+ data.tar.gz: bb498cfa7db7871f2ac03aedb2dbbb94fac878ea34ff33d0a205e216fe856735
5
5
  SHA512:
6
- metadata.gz: f4586bbf8a10b5bf2b262bafefd222ef981624ced261755bd9d43652506400f6b939e5cd3595b7af0c66a193581328937aabe5b9246efd4cb3a0fa088b9e0ccf
7
- data.tar.gz: 4169cf67306d9d080e264897ed2cffb5103a9b98ca176fea2784ff3293d4b9dd3decd62df3848b2a7ade783f5dfe6925b86fa7d4727b45de51764af5bc6e1b4a
6
+ metadata.gz: 7edc6574a2a647e49da0c5ae487f98c89fa097aae064cbfd42b2a08b88ae1611fee948632dca90c6b2bb9166e5f3e02ea3aaffeb0f419f6f84f3905eac384b53
7
+ data.tar.gz: 815bdb39b87e95ee1a8fe7ed5c9ae9b545491ff0c59beb117a7ff0202b73aede9c14ee4fc5179195d726ed4f4dd0572de95f3bb795f26124062f332e138e8bbe
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.4.0] - 2024-08-26
4
+
5
+ ### Added
6
+
7
+ * Auto test retries for cucumber ([#212][])
8
+ * Auto test retries for RSpec ([#213][])
9
+ * Auto test retries for minitest ([#214][])
10
+ * implement auto test retries RFC ([#219][])
11
+
12
+ ### Changed
13
+
14
+ * Skip Before/After hooks in cucumber when scenario is skipped by intelligent test runner ([#211][])
15
+ * gem datadog 2.3 is now minimal required version ([#220][])
16
+ * Enable agentless telemetry when library is running in agentless mode ([#221][])
17
+ * Add Ruby 3.4 to the testing matrix ([#217][])
18
+ * add different fallbacks for unshallowing remotes ([#218][])
19
+ * make itr_enabled config parameter true by default ([#216][])
20
+ * RSpec - don't report test errors if rspec process is quitting ([#215][])
21
+
3
22
  ## [1.3.0] - 2024-07-30
4
23
 
5
24
  ### Added
@@ -290,7 +309,8 @@ Currently test suite level visibility is not used by our instrumentation: it wil
290
309
 
291
310
  - Ruby versions < 2.7 no longer supported ([#8][])
292
311
 
293
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.3.0...main
312
+ [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.4.0...main
313
+ [1.4.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.3.0...v1.4.0
294
314
  [1.3.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.2.0...v1.3.0
295
315
  [1.2.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.1.0...v1.2.0
296
316
  [1.1.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.0.1...v1.1.0
@@ -413,4 +433,15 @@ Currently test suite level visibility is not used by our instrumentation: it wil
413
433
  [#204]: https://github.com/DataDog/datadog-ci-rb/issues/204
414
434
  [#205]: https://github.com/DataDog/datadog-ci-rb/issues/205
415
435
  [#206]: https://github.com/DataDog/datadog-ci-rb/issues/206
416
- [#207]: https://github.com/DataDog/datadog-ci-rb/issues/207
436
+ [#207]: https://github.com/DataDog/datadog-ci-rb/issues/207
437
+ [#211]: https://github.com/DataDog/datadog-ci-rb/issues/211
438
+ [#212]: https://github.com/DataDog/datadog-ci-rb/issues/212
439
+ [#213]: https://github.com/DataDog/datadog-ci-rb/issues/213
440
+ [#214]: https://github.com/DataDog/datadog-ci-rb/issues/214
441
+ [#215]: https://github.com/DataDog/datadog-ci-rb/issues/215
442
+ [#216]: https://github.com/DataDog/datadog-ci-rb/issues/216
443
+ [#217]: https://github.com/DataDog/datadog-ci-rb/issues/217
444
+ [#218]: https://github.com/DataDog/datadog-ci-rb/issues/218
445
+ [#219]: https://github.com/DataDog/datadog-ci-rb/issues/219
446
+ [#220]: https://github.com/DataDog/datadog-ci-rb/issues/220
447
+ [#221]: https://github.com/DataDog/datadog-ci-rb/issues/221
@@ -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"
@@ -238,23 +238,42 @@ module Datadog
238
238
  Telemetry.git_command(Ext::Telemetry::Command::UNSHALLOW)
239
239
  res = nil
240
240
 
241
+ unshallow_command =
242
+ "git fetch " \
243
+ "--shallow-since=\"1 month ago\" " \
244
+ "--update-shallow " \
245
+ "--filter=\"blob:none\" " \
246
+ "--recurse-submodules=no " \
247
+ "$(git config --default origin --get clone.defaultRemoteName)"
248
+
249
+ unshallow_remotes = [
250
+ "$(git rev-parse HEAD)",
251
+ "$(git rev-parse --abbrev-ref --symbolic-full-name @{upstream})",
252
+ nil
253
+ ]
254
+
241
255
  duration_ms = Core::Utils::Time.measure(:float_millisecond) do
242
- res = exec_git_command(
243
- "git fetch " \
244
- "--shallow-since=\"1 month ago\" " \
245
- "--update-shallow " \
246
- "--filter=\"blob:none\" " \
247
- "--recurse-submodules=no " \
248
- "$(git config --default origin --get clone.defaultRemoteName) $(git rev-parse HEAD)"
249
- )
256
+ unshallow_remotes.each do |remote|
257
+ unshallowing_errored = false
258
+
259
+ res =
260
+ begin
261
+ exec_git_command(
262
+ "#{unshallow_command} #{remote}"
263
+ )
264
+ rescue => e
265
+ log_failure(e, "git unshallow")
266
+ telemetry_track_error(e, Ext::Telemetry::Command::UNSHALLOW)
267
+ unshallowing_errored = true
268
+ nil
269
+ end
270
+
271
+ break unless unshallowing_errored
272
+ end
250
273
  end
251
- Telemetry.git_command_ms(Ext::Telemetry::Command::UNSHALLOW, duration_ms)
252
274
 
275
+ Telemetry.git_command_ms(Ext::Telemetry::Command::UNSHALLOW, duration_ms)
253
276
  res
254
- rescue => e
255
- log_failure(e, "git unshallow")
256
- telemetry_track_error(e, Ext::Telemetry::Command::UNSHALLOW)
257
- nil
258
277
  end
259
278
 
260
279
  # makes .exec_git_command private to make sure that this method