datadog-ci 0.6.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -2
  3. data/README.md +21 -2
  4. data/lib/datadog/ci/codeowners/matcher.rb +102 -0
  5. data/lib/datadog/ci/codeowners/parser.rb +42 -0
  6. data/lib/datadog/ci/codeowners/rule.rb +33 -0
  7. data/lib/datadog/ci/concurrent_span.rb +2 -1
  8. data/lib/datadog/ci/configuration/components.rb +59 -57
  9. data/lib/datadog/ci/configuration/settings.rb +21 -0
  10. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +4 -1
  11. data/lib/datadog/ci/contrib/cucumber/formatter.rb +69 -38
  12. data/lib/datadog/ci/contrib/cucumber/instrumentation.rb +2 -1
  13. data/lib/datadog/ci/contrib/minitest/configuration/settings.rb +4 -1
  14. data/lib/datadog/ci/contrib/minitest/helpers.rb +2 -1
  15. data/lib/datadog/ci/contrib/minitest/hooks.rb +9 -22
  16. data/lib/datadog/ci/contrib/minitest/patcher.rb +9 -6
  17. data/lib/datadog/ci/contrib/minitest/reporter.rb +50 -0
  18. data/lib/datadog/ci/contrib/minitest/runnable.rb +1 -1
  19. data/lib/datadog/ci/contrib/minitest/runner.rb +41 -0
  20. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +4 -1
  21. data/lib/datadog/ci/contrib/rspec/example.rb +55 -14
  22. data/lib/datadog/ci/contrib/rspec/example_group.rb +12 -7
  23. data/lib/datadog/ci/contrib/rspec/patcher.rb +10 -1
  24. data/lib/datadog/ci/contrib/rspec/runner.rb +7 -8
  25. data/lib/datadog/ci/ext/app_types.rb +2 -0
  26. data/lib/datadog/ci/ext/environment/providers/local_git.rb +8 -29
  27. data/lib/datadog/ci/ext/settings.rb +2 -0
  28. data/lib/datadog/ci/ext/test.rb +29 -7
  29. data/lib/datadog/ci/ext/transport.rb +19 -1
  30. data/lib/datadog/ci/itr/runner.rb +67 -0
  31. data/lib/datadog/ci/span.rb +51 -2
  32. data/lib/datadog/ci/test.rb +67 -2
  33. data/lib/datadog/ci/test_module.rb +1 -1
  34. data/lib/datadog/ci/test_session.rb +10 -2
  35. data/lib/datadog/ci/test_suite.rb +53 -2
  36. data/lib/datadog/ci/test_visibility/context/local.rb +3 -9
  37. data/lib/datadog/ci/test_visibility/null_recorder.rb +2 -22
  38. data/lib/datadog/ci/test_visibility/recorder.rb +46 -20
  39. data/lib/datadog/ci/test_visibility/serializers/base.rb +6 -5
  40. data/lib/datadog/ci/test_visibility/serializers/span.rb +1 -1
  41. data/lib/datadog/ci/test_visibility/serializers/test_module.rb +1 -1
  42. data/lib/datadog/ci/test_visibility/serializers/test_session.rb +1 -1
  43. data/lib/datadog/ci/test_visibility/serializers/test_suite.rb +1 -1
  44. data/lib/datadog/ci/test_visibility/serializers/test_v1.rb +1 -1
  45. data/lib/datadog/ci/test_visibility/transport.rb +1 -5
  46. data/lib/datadog/ci/transport/api/agentless.rb +63 -0
  47. data/lib/datadog/ci/transport/api/base.rb +10 -14
  48. data/lib/datadog/ci/transport/api/builder.rb +25 -22
  49. data/lib/datadog/ci/transport/api/evp_proxy.rb +47 -7
  50. data/lib/datadog/ci/transport/http.rb +7 -1
  51. data/lib/datadog/ci/transport/remote_settings_api.rb +96 -0
  52. data/lib/datadog/ci/utils/configuration.rb +15 -0
  53. data/lib/datadog/ci/utils/git.rb +70 -0
  54. data/lib/datadog/ci/version.rb +1 -1
  55. data/lib/datadog/ci.rb +40 -56
  56. metadata +12 -90
  57. data/lib/datadog/ci/contrib/minitest/plugin.rb +0 -73
  58. data/lib/datadog/ci/null_span.rb +0 -63
  59. data/lib/datadog/ci/transport/api/ci_test_cycle.rb +0 -30
  60. data/sig/datadog/ci/concurrent_span.rbs +0 -23
  61. data/sig/datadog/ci/configuration/components.rbs +0 -21
  62. data/sig/datadog/ci/configuration/extensions.rbs +0 -9
  63. data/sig/datadog/ci/configuration/settings.rbs +0 -16
  64. data/sig/datadog/ci/contrib/cucumber/configuration/settings.rbs +0 -12
  65. data/sig/datadog/ci/contrib/cucumber/ext.rbs +0 -21
  66. data/sig/datadog/ci/contrib/cucumber/formatter.rbs +0 -48
  67. data/sig/datadog/ci/contrib/cucumber/instrumentation.rbs +0 -16
  68. data/sig/datadog/ci/contrib/cucumber/integration.rbs +0 -26
  69. data/sig/datadog/ci/contrib/cucumber/patcher.rbs +0 -15
  70. data/sig/datadog/ci/contrib/integration.rbs +0 -44
  71. data/sig/datadog/ci/contrib/minitest/configuration/settings.rbs +0 -12
  72. data/sig/datadog/ci/contrib/minitest/ext.rbs +0 -19
  73. data/sig/datadog/ci/contrib/minitest/helpers.rbs +0 -13
  74. data/sig/datadog/ci/contrib/minitest/hooks.rbs +0 -27
  75. data/sig/datadog/ci/contrib/minitest/integration.rbs +0 -26
  76. data/sig/datadog/ci/contrib/minitest/patcher.rbs +0 -15
  77. data/sig/datadog/ci/contrib/minitest/plugin.rbs +0 -31
  78. data/sig/datadog/ci/contrib/minitest/runnable.rbs +0 -24
  79. data/sig/datadog/ci/contrib/rspec/configuration/settings.rbs +0 -12
  80. data/sig/datadog/ci/contrib/rspec/example.rbs +0 -20
  81. data/sig/datadog/ci/contrib/rspec/example_group.rbs +0 -21
  82. data/sig/datadog/ci/contrib/rspec/ext.rbs +0 -17
  83. data/sig/datadog/ci/contrib/rspec/integration.rbs +0 -26
  84. data/sig/datadog/ci/contrib/rspec/patcher.rbs +0 -15
  85. data/sig/datadog/ci/contrib/rspec/runner.rbs +0 -21
  86. data/sig/datadog/ci/contrib/settings.rbs +0 -25
  87. data/sig/datadog/ci/ext/app_types.rbs +0 -14
  88. data/sig/datadog/ci/ext/environment/extractor.rbs +0 -25
  89. data/sig/datadog/ci/ext/environment/providers/appveyor.rbs +0 -48
  90. data/sig/datadog/ci/ext/environment/providers/aws_code_pipeline.rbs +0 -19
  91. data/sig/datadog/ci/ext/environment/providers/azure.rbs +0 -56
  92. data/sig/datadog/ci/ext/environment/providers/base.rbs +0 -71
  93. data/sig/datadog/ci/ext/environment/providers/bitbucket.rbs +0 -37
  94. data/sig/datadog/ci/ext/environment/providers/bitrise.rbs +0 -41
  95. data/sig/datadog/ci/ext/environment/providers/buddy.rbs +0 -37
  96. data/sig/datadog/ci/ext/environment/providers/buildkite.rbs +0 -45
  97. data/sig/datadog/ci/ext/environment/providers/circleci.rbs +0 -41
  98. data/sig/datadog/ci/ext/environment/providers/codefresh.rbs +0 -25
  99. data/sig/datadog/ci/ext/environment/providers/github_actions.rbs +0 -42
  100. data/sig/datadog/ci/ext/environment/providers/gitlab.rbs +0 -57
  101. data/sig/datadog/ci/ext/environment/providers/jenkins.rbs +0 -35
  102. data/sig/datadog/ci/ext/environment/providers/local_git.rbs +0 -66
  103. data/sig/datadog/ci/ext/environment/providers/teamcity.rbs +0 -17
  104. data/sig/datadog/ci/ext/environment/providers/travis.rbs +0 -35
  105. data/sig/datadog/ci/ext/environment/providers/user_defined_tags.rbs +0 -33
  106. data/sig/datadog/ci/ext/environment/providers.rbs +0 -13
  107. data/sig/datadog/ci/ext/environment.rbs +0 -44
  108. data/sig/datadog/ci/ext/git.rbs +0 -53
  109. data/sig/datadog/ci/ext/settings.rbs +0 -14
  110. data/sig/datadog/ci/ext/test.rbs +0 -60
  111. data/sig/datadog/ci/ext/transport.rbs +0 -29
  112. data/sig/datadog/ci/null_span.rbs +0 -37
  113. data/sig/datadog/ci/span.rbs +0 -47
  114. data/sig/datadog/ci/test.rbs +0 -12
  115. data/sig/datadog/ci/test_module.rbs +0 -6
  116. data/sig/datadog/ci/test_session.rbs +0 -9
  117. data/sig/datadog/ci/test_suite.rbs +0 -6
  118. data/sig/datadog/ci/test_visibility/context/global.rbs +0 -39
  119. data/sig/datadog/ci/test_visibility/context/local.rbs +0 -23
  120. data/sig/datadog/ci/test_visibility/flush.rbs +0 -17
  121. data/sig/datadog/ci/test_visibility/null_recorder.rbs +0 -45
  122. data/sig/datadog/ci/test_visibility/recorder.rbs +0 -85
  123. data/sig/datadog/ci/test_visibility/serializers/base.rbs +0 -94
  124. data/sig/datadog/ci/test_visibility/serializers/factories/test_level.rbs +0 -13
  125. data/sig/datadog/ci/test_visibility/serializers/factories/test_suite_level.rbs +0 -13
  126. data/sig/datadog/ci/test_visibility/serializers/span.rbs +0 -18
  127. data/sig/datadog/ci/test_visibility/serializers/test_module.rbs +0 -26
  128. data/sig/datadog/ci/test_visibility/serializers/test_session.rbs +0 -26
  129. data/sig/datadog/ci/test_visibility/serializers/test_suite.rbs +0 -26
  130. data/sig/datadog/ci/test_visibility/serializers/test_v1.rbs +0 -23
  131. data/sig/datadog/ci/test_visibility/serializers/test_v2.rbs +0 -25
  132. data/sig/datadog/ci/test_visibility/transport.rbs +0 -35
  133. data/sig/datadog/ci/transport/api/base.rbs +0 -21
  134. data/sig/datadog/ci/transport/api/builder.rbs +0 -12
  135. data/sig/datadog/ci/transport/api/ci_test_cycle.rbs +0 -21
  136. data/sig/datadog/ci/transport/api/evp_proxy.rbs +0 -19
  137. data/sig/datadog/ci/transport/gzip.rbs +0 -9
  138. data/sig/datadog/ci/transport/http.rbs +0 -36
  139. data/sig/datadog/ci/utils/git.rbs +0 -11
  140. data/sig/datadog/ci/utils/test_run.rbs +0 -11
  141. data/sig/datadog/ci/utils/url.rbs +0 -9
  142. data/sig/datadog/ci/version.rbs +0 -16
  143. data/sig/datadog/ci.rbs +0 -37
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../../ext/test"
4
+ require_relative "../../utils/git"
4
5
  require_relative "ext"
5
6
 
6
7
  module Datadog
@@ -13,11 +14,12 @@ module Datadog
13
14
  private :config
14
15
 
15
16
  def initialize(config)
17
+ @ast_lookup = ::Cucumber::Formatter::AstLookup.new(config) if defined?(::Cucumber::Formatter::AstLookup)
16
18
  @config = config
17
- @failed_tests_count = 0
18
19
 
19
20
  @current_test_suite = nil
20
- @failed_tests_in_current_test_suite = 0
21
+
22
+ @failed_tests_count = 0
21
23
 
22
24
  bind_events(config)
23
25
  end
@@ -32,15 +34,14 @@ module Datadog
32
34
  end
33
35
 
34
36
  def on_test_run_started(event)
35
- test_session = CI.start_test_session(
37
+ CI.start_test_session(
36
38
  tags: {
37
39
  CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
38
- CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::Cucumber::Integration.version.to_s,
39
- CI::Ext::Test::TAG_TYPE => CI::Ext::Test::TEST_TYPE
40
+ CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::Cucumber::Integration.version.to_s
40
41
  },
41
42
  service: configuration[:service_name]
42
43
  )
43
- CI.start_test_module(test_session.name)
44
+ CI.start_test_module(Ext::FRAMEWORK)
44
45
  end
45
46
 
46
47
  def on_test_run_finished(event)
@@ -52,58 +53,71 @@ module Datadog
52
53
  end
53
54
 
54
55
  def on_test_case_started(event)
55
- test_suite_name = event.test_case.location.file
56
+ test_suite_name = test_suite_name(event.test_case)
57
+
58
+ tags = {
59
+ CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
60
+ CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::Cucumber::Integration.version.to_s,
61
+ CI::Ext::Test::TAG_SOURCE_FILE => Utils::Git.relative_to_root(event.test_case.location.file),
62
+ CI::Ext::Test::TAG_SOURCE_START => event.test_case.location.line.to_s
63
+ }
56
64
 
57
65
  start_test_suite(test_suite_name) unless same_test_suite_as_current?(test_suite_name)
58
66
 
59
- CI.start_test(
67
+ test_span = CI.start_test(
60
68
  event.test_case.name,
61
69
  test_suite_name,
62
- tags: {
63
- CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
64
- CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::Cucumber::Integration.version.to_s,
65
- CI::Ext::Test::TAG_TYPE => CI::Ext::Test::TEST_TYPE
66
- },
70
+ tags: tags,
67
71
  service: configuration[:service_name]
68
72
  )
73
+
74
+ if test_span && (parameters = extract_parameters_hash(event.test_case))
75
+ test_span.set_parameters(parameters)
76
+ end
69
77
  end
70
78
 
71
79
  def on_test_case_finished(event)
72
80
  test_span = CI.active_test
73
81
  return if test_span.nil?
74
82
 
75
- # We need to track overall test failures manually if we are using cucumber < 8.0 because
76
- # TestRunFinished event does not have a success attribute before 8.0.
77
- #
78
- # To track whether test suite failed or passed we need to
79
- # track the number of failed tests in the current test suite.
80
- if event.result.failed?
81
- @failed_tests_count += 1
82
- @failed_tests_in_current_test_suite += 1
83
- end
84
-
85
- finish_test(test_span, event.result)
83
+ finish_span(test_span, event.result)
84
+ @failed_tests_count += 1 if test_span.failed?
86
85
  end
87
86
 
88
87
  def on_test_step_started(event)
89
- CI.trace(Ext::STEP_SPAN_TYPE, event.test_step.to_s)
88
+ CI.trace(event.test_step.to_s, type: Ext::STEP_SPAN_TYPE)
90
89
  end
91
90
 
92
91
  def on_test_step_finished(event)
93
- current_step_span = CI.active_span(Ext::STEP_SPAN_TYPE)
92
+ current_step_span = CI.active_span
94
93
  return if current_step_span.nil?
95
94
 
96
- finish_test(current_step_span, event.result)
95
+ finish_span(current_step_span, event.result)
97
96
  end
98
97
 
99
98
  private
100
99
 
101
- def finish_test(span, result)
102
- if result.skipped?
103
- span.skipped!
104
- elsif result.ok?
100
+ def test_suite_name(test_case)
101
+ feature = if test_case.respond_to?(:feature)
102
+ test_case.feature
103
+ elsif @ast_lookup
104
+ gherkin_doc = @ast_lookup.gherkin_document(test_case.location.file)
105
+ gherkin_doc.feature if gherkin_doc
106
+ end
107
+
108
+ if feature
109
+ "#{feature.name} at #{test_case.location.file}"
110
+ else
111
+ test_case.location.file
112
+ end
113
+ end
114
+
115
+ def finish_span(span, result)
116
+ if !result.passed? && result.ok?(@config.strict)
117
+ span.skipped!(reason: result.message)
118
+ elsif result.passed?
105
119
  span.passed!
106
- elsif result.failed?
120
+ else
107
121
  span.failed!(exception: result.exception)
108
122
  end
109
123
  span.finish
@@ -139,13 +153,9 @@ module Datadog
139
153
  test_suite = @current_test_suite
140
154
  return unless test_suite
141
155
 
142
- if @failed_tests_in_current_test_suite.zero?
143
- test_suite.passed!
144
- else
145
- test_suite.failed!
146
- end
147
- @failed_tests_in_current_test_suite = 0
148
156
  test_suite.finish
157
+
158
+ @current_test_suite = nil
149
159
  end
150
160
 
151
161
  def same_test_suite_as_current?(test_suite_name)
@@ -155,6 +165,27 @@ module Datadog
155
165
  test_suite.name == test_suite_name
156
166
  end
157
167
 
168
+ def extract_parameters_hash(test_case)
169
+ # not supported in cucumber < 4.0
170
+ return nil unless @ast_lookup
171
+
172
+ scenario_source = @ast_lookup.scenario_source(test_case)
173
+
174
+ # cucumber examples are only supported for scenario outlines
175
+ return nil unless scenario_source.type == :ScenarioOutline
176
+
177
+ scenario_source.examples.table_header.cells.map(&:value).zip(
178
+ scenario_source.row.cells.map(&:value)
179
+ ).to_h
180
+ rescue => e
181
+ Datadog.logger.warn do
182
+ "Unable to extract parameters from test case #{test_case.name}: " \
183
+ "#{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
184
+ end
185
+
186
+ nil
187
+ end
188
+
158
189
  def configuration
159
190
  Datadog.configuration.ci[:cucumber]
160
191
  end
@@ -17,8 +17,9 @@ module Datadog
17
17
  attr_reader :datadog_formatter
18
18
 
19
19
  def formatters
20
+ existing_formatters = super
20
21
  @datadog_formatter ||= CI::Contrib::Cucumber::Formatter.new(@configuration)
21
- [@datadog_formatter] + super
22
+ [@datadog_formatter] + existing_formatters
22
23
  end
23
24
  end
24
25
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "../ext"
4
4
  require_relative "../../settings"
5
+ require_relative "../../../utils/configuration"
5
6
 
6
7
  module Datadog
7
8
  module CI
@@ -19,7 +20,9 @@ module Datadog
19
20
 
20
21
  option :service_name do |o|
21
22
  o.type :string
22
- o.default { Datadog.configuration.service_without_fallback || Ext::DEFAULT_SERVICE_NAME }
23
+ o.default do
24
+ Utils::Configuration.fetch_service_name(Ext::DEFAULT_SERVICE_NAME)
25
+ end
23
26
  end
24
27
 
25
28
  # @deprecated Will be removed in 1.0
@@ -13,7 +13,8 @@ module Datadog
13
13
  end
14
14
 
15
15
  def self.parallel?(klass)
16
- klass.ancestors.include?(::Minitest::Parallel::Test)
16
+ klass.ancestors.include?(::Minitest::Parallel::Test) ||
17
+ (defined?(::Minitest::Queue) && ::Minitest.singleton_class.ancestors.include?(::Minitest::Queue))
17
18
  end
18
19
  end
19
20
  end
@@ -14,8 +14,6 @@ module Datadog
14
14
  super
15
15
  return unless datadog_configuration[:enabled]
16
16
 
17
- test_name = "#{class_name}##{name}"
18
-
19
17
  test_suite_name = Helpers.test_suite_name(self.class, name)
20
18
  if Helpers.parallel?(self.class)
21
19
  test_suite_name = "#{test_suite_name} (#{name} concurrently)"
@@ -24,13 +22,16 @@ module Datadog
24
22
  CI.start_test_suite(test_suite_name)
25
23
  end
26
24
 
25
+ source_file, line_number = method(name).source_location
26
+
27
27
  CI.start_test(
28
- test_name,
28
+ name,
29
29
  test_suite_name,
30
30
  tags: {
31
31
  CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
32
32
  CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::Minitest::Integration.version.to_s,
33
- CI::Ext::Test::TAG_TYPE => CI::Ext::Test::TEST_TYPE
33
+ CI::Ext::Test::TAG_SOURCE_FILE => Utils::Git.relative_to_root(source_file),
34
+ CI::Ext::Test::TAG_SOURCE_START => line_number.to_s
34
35
  },
35
36
  service: datadog_configuration[:service_name]
36
37
  )
@@ -40,9 +41,9 @@ module Datadog
40
41
  test_span = CI.active_test
41
42
  return super unless test_span
42
43
 
43
- finish_test(test_span, result_code)
44
+ finish_with_result(test_span, result_code)
44
45
  if Helpers.parallel?(self.class)
45
- finish_test_suite(test_span.test_suite, result_code)
46
+ finish_with_result(test_span.test_suite, result_code)
46
47
  end
47
48
 
48
49
  super
@@ -50,23 +51,9 @@ module Datadog
50
51
 
51
52
  private
52
53
 
53
- def finish_test(test_span, result_code)
54
- finish_with_result(test_span, result_code)
55
-
56
- # mark test suite as failed if any test failed
57
- if test_span.failed?
58
- test_suite = test_span.test_suite
59
- test_suite.failed! if test_suite
60
- end
61
- end
62
-
63
- def finish_test_suite(test_suite, result_code)
64
- return unless test_suite
65
-
66
- finish_with_result(test_suite, result_code)
67
- end
68
-
69
54
  def finish_with_result(span, result_code)
55
+ return unless span
56
+
70
57
  case result_code
71
58
  when "."
72
59
  span.passed!
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "runner"
4
+ require_relative "reporter"
3
5
  require_relative "hooks"
4
6
  require_relative "runnable"
5
7
 
@@ -18,13 +20,14 @@ module Datadog
18
20
  end
19
21
 
20
22
  def patch
21
- require_relative "plugin"
22
-
23
- ::Minitest::Test.include(Hooks)
24
- ::Minitest.include(Plugin)
23
+ # test session start
24
+ ::Minitest.include(Runner)
25
+ # test suites (when not executed concurrently)
25
26
  ::Minitest::Runnable.include(Runnable)
26
-
27
- ::Minitest.extensions << "datadog_ci"
27
+ # tests; test suites (when executed concurrently)
28
+ ::Minitest::Test.include(Hooks)
29
+ # test session finish
30
+ ::Minitest::CompositeReporter.include(Reporter)
28
31
  end
29
32
  end
30
33
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../ext/test"
4
+ require_relative "ext"
5
+
6
+ module Datadog
7
+ module CI
8
+ module Contrib
9
+ module Minitest
10
+ module Reporter
11
+ def self.included(base)
12
+ base.prepend(InstanceMethods)
13
+ end
14
+
15
+ module InstanceMethods
16
+ def report(*)
17
+ return super unless datadog_configuration[:enabled]
18
+
19
+ res = super
20
+
21
+ active_test_session = CI.active_test_session
22
+ active_test_module = CI.active_test_module
23
+
24
+ return res if active_test_session.nil? || active_test_module.nil?
25
+
26
+ if passed?
27
+ active_test_module.passed!
28
+ active_test_session.passed!
29
+ else
30
+ active_test_module.failed!
31
+ active_test_session.failed!
32
+ end
33
+
34
+ active_test_module.finish
35
+ active_test_session.finish
36
+
37
+ res
38
+ end
39
+
40
+ private
41
+
42
+ def datadog_configuration
43
+ Datadog.configuration.ci[:minitest]
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -20,9 +20,9 @@ module Datadog
20
20
  test_suite_name = Helpers.test_suite_name(self, method)
21
21
 
22
22
  test_suite = Datadog::CI.start_test_suite(test_suite_name)
23
- test_suite.passed! # will be overridden if any test fails
24
23
 
25
24
  results = super
25
+ return results unless test_suite
26
26
 
27
27
  test_suite.finish
28
28
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../ext/test"
4
+ require_relative "ext"
5
+
6
+ module Datadog
7
+ module CI
8
+ module Contrib
9
+ module Minitest
10
+ module Runner
11
+ def self.included(base)
12
+ base.singleton_class.prepend(ClassMethods)
13
+ end
14
+
15
+ module ClassMethods
16
+ def init_plugins(*)
17
+ super
18
+
19
+ return unless datadog_configuration[:enabled]
20
+
21
+ CI.start_test_session(
22
+ tags: {
23
+ CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
24
+ CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::Minitest::Integration.version.to_s
25
+ },
26
+ service: datadog_configuration[:service_name]
27
+ )
28
+ CI.start_test_module(Ext::FRAMEWORK)
29
+ end
30
+
31
+ private
32
+
33
+ def datadog_configuration
34
+ Datadog.configuration.ci[:minitest]
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "../ext"
4
4
  require_relative "../../settings"
5
+ require_relative "../../../utils/configuration"
5
6
 
6
7
  module Datadog
7
8
  module CI
@@ -19,7 +20,9 @@ module Datadog
19
20
 
20
21
  option :service_name do |o|
21
22
  o.type :string
22
- o.default { Datadog.configuration.service_without_fallback || Ext::DEFAULT_SERVICE_NAME }
23
+ o.default do
24
+ Utils::Configuration.fetch_service_name(Ext::DEFAULT_SERVICE_NAME)
25
+ end
23
26
  end
24
27
 
25
28
  # @deprecated Will be removed in 1.0
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../../ext/test"
4
+ require_relative "../../utils/git"
4
5
  require_relative "ext"
5
6
 
6
7
  module Datadog
@@ -13,10 +14,9 @@ module Datadog
13
14
  base.prepend(InstanceMethods)
14
15
  end
15
16
 
16
- # Instance methods for configuration
17
17
  module InstanceMethods
18
- def run(example_group_instance, reporter)
19
- return super unless configuration[:enabled]
18
+ def run(*)
19
+ return super unless datadog_configuration[:enabled]
20
20
 
21
21
  test_name = full_description.strip
22
22
  if metadata[:description].empty?
@@ -24,36 +24,77 @@ module Datadog
24
24
  test_name += " #{description}"
25
25
  end
26
26
 
27
+ test_suite_description = fetch_top_level_example_group[:description]
28
+ suite_name = "#{test_suite_description} at #{metadata[:example_group][:rerun_file_path]}"
29
+
30
+ # remove example group description from test name to avoid duplication
31
+ test_name = test_name.sub(test_suite_description, "").strip
32
+
33
+ if ci_queue?
34
+ suite_name += " (ci-queue running example [#{test_name}])"
35
+ test_suite_span = CI.start_test_suite(suite_name)
36
+ end
37
+
27
38
  CI.trace_test(
28
39
  test_name,
29
- metadata[:example_group][:rerun_file_path],
40
+ suite_name,
30
41
  tags: {
31
42
  CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
32
43
  CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::RSpec::Integration.version.to_s,
33
- CI::Ext::Test::TAG_TYPE => CI::Ext::Test::TEST_TYPE
44
+ CI::Ext::Test::TAG_SOURCE_FILE => Utils::Git.relative_to_root(metadata[:file_path]),
45
+ CI::Ext::Test::TAG_SOURCE_START => metadata[:line_number].to_s
34
46
  },
35
- service: configuration[:service_name]
47
+ service: datadog_configuration[:service_name]
36
48
  ) do |test_span|
37
49
  result = super
38
50
 
39
- case execution_result.status
40
- when :passed
41
- test_span.passed!
42
- when :failed
43
- test_span.failed!(exception: execution_result.exception)
44
- else
45
- test_span.skipped!(exception: execution_result.exception) if execution_result.example_skipped?
51
+ if test_span
52
+ test_span.set_parameters({}, {"scoped_id" => metadata[:scoped_id]})
53
+
54
+ case execution_result.status
55
+ when :passed
56
+ test_span.passed!
57
+ test_suite_span.passed! if test_suite_span
58
+ when :failed
59
+ test_span.failed!(exception: execution_result.exception)
60
+ test_suite_span.failed! if test_suite_span
61
+ else
62
+ # :pending or nil
63
+ test_span.skipped!(
64
+ reason: execution_result.pending_message,
65
+ exception: execution_result.pending_exception
66
+ )
67
+
68
+ test_suite_span.skipped! if test_suite_span
69
+ end
46
70
  end
47
71
 
72
+ test_suite_span.finish if test_suite_span
73
+
48
74
  result
49
75
  end
50
76
  end
51
77
 
52
78
  private
53
79
 
54
- def configuration
80
+ def fetch_top_level_example_group
81
+ return metadata[:example_group] unless metadata[:example_group][:parent_example_group]
82
+
83
+ res = metadata[:example_group][:parent_example_group]
84
+ while (parent = res[:parent_example_group])
85
+ res = parent
86
+ end
87
+ res
88
+ end
89
+
90
+ def datadog_configuration
55
91
  Datadog.configuration.ci[:rspec]
56
92
  end
93
+
94
+ def ci_queue?
95
+ defined?(::RSpec::Queue::ExampleExtension) &&
96
+ self.class.ancestors.include?(::RSpec::Queue::ExampleExtension)
97
+ end
57
98
  end
58
99
  end
59
100
  end
@@ -7,7 +7,7 @@ module Datadog
7
7
  module CI
8
8
  module Contrib
9
9
  module RSpec
10
- # Instrument RSpec::Core::Example
10
+ # Instrument RSpec::Core::ExampleGroup
11
11
  module ExampleGroup
12
12
  def self.included(base)
13
13
  base.singleton_class.prepend(ClassMethods)
@@ -16,26 +16,31 @@ module Datadog
16
16
  # Instance methods for configuration
17
17
  module ClassMethods
18
18
  def run(reporter = ::RSpec::Core::NullReporter)
19
- return super unless configuration[:enabled]
19
+ return super unless datadog_configuration[:enabled]
20
20
  return super unless top_level?
21
21
 
22
- test_suite = Datadog::CI.start_test_suite(file_path)
22
+ suite_name = "#{description} at #{file_path}"
23
+ test_suite = Datadog::CI.start_test_suite(suite_name)
23
24
 
24
- result = super
25
+ success = super
26
+ return success unless test_suite
25
27
 
26
- if result
28
+ if success && test_suite.passed_tests_count > 0
27
29
  test_suite.passed!
30
+ elsif success
31
+ test_suite.skipped!
28
32
  else
29
33
  test_suite.failed!
30
34
  end
35
+
31
36
  test_suite.finish
32
37
 
33
- result
38
+ success
34
39
  end
35
40
 
36
41
  private
37
42
 
38
- def configuration
43
+ def datadog_configuration
39
44
  Datadog.configuration.ci[:rspec]
40
45
  end
41
46
  end
@@ -21,10 +21,19 @@ module Datadog
21
21
  end
22
22
 
23
23
  def patch
24
- ::RSpec::Core::Example.include(Example)
24
+ if ci_queue?
25
+ ::RSpec::Queue::Runner.include(Runner)
26
+ end
27
+
25
28
  ::RSpec::Core::Runner.include(Runner)
29
+ ::RSpec::Core::Example.include(Example)
26
30
  ::RSpec::Core::ExampleGroup.include(ExampleGroup)
27
31
  end
32
+
33
+ def ci_queue?
34
+ # ::RSpec::Queue::Runner is a ci-queue runner
35
+ defined?(::RSpec::Queue::Runner)
36
+ end
28
37
  end
29
38
  end
30
39
  end
@@ -14,24 +14,23 @@ module Datadog
14
14
  end
15
15
 
16
16
  module InstanceMethods
17
- def run_specs(example_groups)
18
- return super unless configuration[:enabled]
17
+ def run_specs(*)
18
+ return super unless datadog_configuration[:enabled]
19
19
 
20
20
  test_session = CI.start_test_session(
21
21
  tags: {
22
22
  CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
23
- CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::RSpec::Integration.version.to_s,
24
- CI::Ext::Test::TAG_TYPE => CI::Ext::Test::TEST_TYPE
23
+ CI::Ext::Test::TAG_FRAMEWORK_VERSION => CI::Contrib::RSpec::Integration.version.to_s
25
24
  },
26
- service: configuration[:service_name]
25
+ service: datadog_configuration[:service_name]
27
26
  )
28
27
 
29
- test_module = CI.start_test_module(test_session.name)
28
+ test_module = CI.start_test_module(Ext::FRAMEWORK)
30
29
 
31
30
  result = super
31
+ return result unless test_module && test_session
32
32
 
33
33
  if result != 0
34
- # TODO: repeating this twice feels clunky, we need to remove test_module API before GA
35
34
  test_module.failed!
36
35
  test_session.failed!
37
36
  else
@@ -46,7 +45,7 @@ module Datadog
46
45
 
47
46
  private
48
47
 
49
- def configuration
48
+ def datadog_configuration
50
49
  Datadog.configuration.ci[:rspec]
51
50
  end
52
51
  end
@@ -3,6 +3,8 @@
3
3
  module Datadog
4
4
  module CI
5
5
  module Ext
6
+ # Defines span types for CI visibility
7
+ # @public_api
6
8
  module AppTypes
7
9
  TYPE_TEST = "test"
8
10
  TYPE_TEST_SESSION = "test_session_end"