datadog-ci 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -2
  3. data/README.md +1 -1
  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 +5 -5
  9. data/lib/datadog/ci/configuration/settings.rb +15 -0
  10. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +4 -1
  11. data/lib/datadog/ci/contrib/cucumber/formatter.rb +68 -37
  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 -7
  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 +1 -0
  28. data/lib/datadog/ci/ext/test.rb +19 -8
  29. data/lib/datadog/ci/span.rb +9 -2
  30. data/lib/datadog/ci/test.rb +67 -2
  31. data/lib/datadog/ci/test_module.rb +1 -1
  32. data/lib/datadog/ci/test_session.rb +2 -2
  33. data/lib/datadog/ci/test_suite.rb +53 -2
  34. data/lib/datadog/ci/test_visibility/context/local.rb +3 -9
  35. data/lib/datadog/ci/test_visibility/null_recorder.rb +2 -22
  36. data/lib/datadog/ci/test_visibility/recorder.rb +25 -19
  37. data/lib/datadog/ci/test_visibility/serializers/base.rb +6 -5
  38. data/lib/datadog/ci/test_visibility/serializers/span.rb +1 -1
  39. data/lib/datadog/ci/test_visibility/serializers/test_module.rb +1 -1
  40. data/lib/datadog/ci/test_visibility/serializers/test_session.rb +1 -1
  41. data/lib/datadog/ci/test_visibility/serializers/test_suite.rb +1 -1
  42. data/lib/datadog/ci/test_visibility/serializers/test_v1.rb +1 -1
  43. data/lib/datadog/ci/utils/configuration.rb +15 -0
  44. data/lib/datadog/ci/utils/git.rb +70 -0
  45. data/lib/datadog/ci/version.rb +1 -1
  46. data/lib/datadog/ci.rb +40 -56
  47. metadata +9 -89
  48. data/lib/datadog/ci/contrib/minitest/plugin.rb +0 -73
  49. data/lib/datadog/ci/null_span.rb +0 -63
  50. data/sig/datadog/ci/concurrent_span.rbs +0 -23
  51. data/sig/datadog/ci/configuration/components.rbs +0 -21
  52. data/sig/datadog/ci/configuration/extensions.rbs +0 -9
  53. data/sig/datadog/ci/configuration/settings.rbs +0 -16
  54. data/sig/datadog/ci/contrib/cucumber/configuration/settings.rbs +0 -12
  55. data/sig/datadog/ci/contrib/cucumber/ext.rbs +0 -21
  56. data/sig/datadog/ci/contrib/cucumber/formatter.rbs +0 -48
  57. data/sig/datadog/ci/contrib/cucumber/instrumentation.rbs +0 -16
  58. data/sig/datadog/ci/contrib/cucumber/integration.rbs +0 -26
  59. data/sig/datadog/ci/contrib/cucumber/patcher.rbs +0 -15
  60. data/sig/datadog/ci/contrib/integration.rbs +0 -44
  61. data/sig/datadog/ci/contrib/minitest/configuration/settings.rbs +0 -12
  62. data/sig/datadog/ci/contrib/minitest/ext.rbs +0 -19
  63. data/sig/datadog/ci/contrib/minitest/helpers.rbs +0 -13
  64. data/sig/datadog/ci/contrib/minitest/hooks.rbs +0 -27
  65. data/sig/datadog/ci/contrib/minitest/integration.rbs +0 -26
  66. data/sig/datadog/ci/contrib/minitest/patcher.rbs +0 -15
  67. data/sig/datadog/ci/contrib/minitest/plugin.rbs +0 -31
  68. data/sig/datadog/ci/contrib/minitest/runnable.rbs +0 -24
  69. data/sig/datadog/ci/contrib/rspec/configuration/settings.rbs +0 -12
  70. data/sig/datadog/ci/contrib/rspec/example.rbs +0 -20
  71. data/sig/datadog/ci/contrib/rspec/example_group.rbs +0 -21
  72. data/sig/datadog/ci/contrib/rspec/ext.rbs +0 -17
  73. data/sig/datadog/ci/contrib/rspec/integration.rbs +0 -26
  74. data/sig/datadog/ci/contrib/rspec/patcher.rbs +0 -15
  75. data/sig/datadog/ci/contrib/rspec/runner.rbs +0 -21
  76. data/sig/datadog/ci/contrib/settings.rbs +0 -25
  77. data/sig/datadog/ci/ext/app_types.rbs +0 -14
  78. data/sig/datadog/ci/ext/environment/extractor.rbs +0 -25
  79. data/sig/datadog/ci/ext/environment/providers/appveyor.rbs +0 -48
  80. data/sig/datadog/ci/ext/environment/providers/aws_code_pipeline.rbs +0 -19
  81. data/sig/datadog/ci/ext/environment/providers/azure.rbs +0 -56
  82. data/sig/datadog/ci/ext/environment/providers/base.rbs +0 -71
  83. data/sig/datadog/ci/ext/environment/providers/bitbucket.rbs +0 -37
  84. data/sig/datadog/ci/ext/environment/providers/bitrise.rbs +0 -41
  85. data/sig/datadog/ci/ext/environment/providers/buddy.rbs +0 -37
  86. data/sig/datadog/ci/ext/environment/providers/buildkite.rbs +0 -45
  87. data/sig/datadog/ci/ext/environment/providers/circleci.rbs +0 -41
  88. data/sig/datadog/ci/ext/environment/providers/codefresh.rbs +0 -25
  89. data/sig/datadog/ci/ext/environment/providers/github_actions.rbs +0 -42
  90. data/sig/datadog/ci/ext/environment/providers/gitlab.rbs +0 -57
  91. data/sig/datadog/ci/ext/environment/providers/jenkins.rbs +0 -35
  92. data/sig/datadog/ci/ext/environment/providers/local_git.rbs +0 -66
  93. data/sig/datadog/ci/ext/environment/providers/teamcity.rbs +0 -17
  94. data/sig/datadog/ci/ext/environment/providers/travis.rbs +0 -35
  95. data/sig/datadog/ci/ext/environment/providers/user_defined_tags.rbs +0 -33
  96. data/sig/datadog/ci/ext/environment/providers.rbs +0 -13
  97. data/sig/datadog/ci/ext/environment.rbs +0 -44
  98. data/sig/datadog/ci/ext/git.rbs +0 -53
  99. data/sig/datadog/ci/ext/settings.rbs +0 -14
  100. data/sig/datadog/ci/ext/test.rbs +0 -60
  101. data/sig/datadog/ci/ext/transport.rbs +0 -29
  102. data/sig/datadog/ci/null_span.rbs +0 -37
  103. data/sig/datadog/ci/span.rbs +0 -47
  104. data/sig/datadog/ci/test.rbs +0 -12
  105. data/sig/datadog/ci/test_module.rbs +0 -6
  106. data/sig/datadog/ci/test_session.rbs +0 -9
  107. data/sig/datadog/ci/test_suite.rbs +0 -6
  108. data/sig/datadog/ci/test_visibility/context/global.rbs +0 -39
  109. data/sig/datadog/ci/test_visibility/context/local.rbs +0 -23
  110. data/sig/datadog/ci/test_visibility/flush.rbs +0 -17
  111. data/sig/datadog/ci/test_visibility/null_recorder.rbs +0 -45
  112. data/sig/datadog/ci/test_visibility/recorder.rbs +0 -85
  113. data/sig/datadog/ci/test_visibility/serializers/base.rbs +0 -94
  114. data/sig/datadog/ci/test_visibility/serializers/factories/test_level.rbs +0 -13
  115. data/sig/datadog/ci/test_visibility/serializers/factories/test_suite_level.rbs +0 -13
  116. data/sig/datadog/ci/test_visibility/serializers/span.rbs +0 -18
  117. data/sig/datadog/ci/test_visibility/serializers/test_module.rbs +0 -26
  118. data/sig/datadog/ci/test_visibility/serializers/test_session.rbs +0 -26
  119. data/sig/datadog/ci/test_visibility/serializers/test_suite.rbs +0 -26
  120. data/sig/datadog/ci/test_visibility/serializers/test_v1.rbs +0 -23
  121. data/sig/datadog/ci/test_visibility/serializers/test_v2.rbs +0 -25
  122. data/sig/datadog/ci/test_visibility/transport.rbs +0 -35
  123. data/sig/datadog/ci/transport/api/base.rbs +0 -21
  124. data/sig/datadog/ci/transport/api/builder.rbs +0 -12
  125. data/sig/datadog/ci/transport/api/ci_test_cycle.rbs +0 -21
  126. data/sig/datadog/ci/transport/api/evp_proxy.rbs +0 -19
  127. data/sig/datadog/ci/transport/gzip.rbs +0 -9
  128. data/sig/datadog/ci/transport/http.rbs +0 -36
  129. data/sig/datadog/ci/utils/git.rbs +0 -11
  130. data/sig/datadog/ci/utils/test_run.rbs +0 -11
  131. data/sig/datadog/ci/utils/url.rbs +0 -9
  132. data/sig/datadog/ci/version.rbs +0 -16
  133. data/sig/datadog/ci.rbs +0 -37
@@ -13,12 +13,63 @@ module Datadog
13
13
  #
14
14
  # @public_api
15
15
  class TestSuite < ConcurrentSpan
16
+ def initialize(tracer_span)
17
+ super
18
+
19
+ @test_suite_stats = Hash.new(0)
20
+ end
21
+
16
22
  # Finishes this test suite.
17
23
  # @return [void]
18
24
  def finish
19
- super
25
+ synchronize do
26
+ # we try to derive test suite status from execution stats if no status was set explicitly
27
+ set_status_from_stats! if undefined?
28
+
29
+ super
30
+
31
+ recorder.deactivate_test_suite(name)
32
+ end
33
+ end
34
+
35
+ # @internal
36
+ def record_test_result(datadog_test_status)
37
+ synchronize do
38
+ @test_suite_stats[datadog_test_status] += 1
39
+ end
40
+ end
41
+
42
+ # @internal
43
+ def passed_tests_count
44
+ synchronize do
45
+ @test_suite_stats[Ext::Test::Status::PASS]
46
+ end
47
+ end
48
+
49
+ # @internal
50
+ def skipped_tests_count
51
+ synchronize do
52
+ @test_suite_stats[Ext::Test::Status::SKIP]
53
+ end
54
+ end
55
+
56
+ # @internal
57
+ def failed_tests_count
58
+ synchronize do
59
+ @test_suite_stats[Ext::Test::Status::FAIL]
60
+ end
61
+ end
62
+
63
+ private
20
64
 
21
- CI.deactivate_test_suite(name)
65
+ def set_status_from_stats!
66
+ if failed_tests_count > 0
67
+ failed!
68
+ elsif passed_tests_count == 0
69
+ skipped!
70
+ else
71
+ passed!
72
+ end
22
73
  end
23
74
  end
24
75
  end
@@ -11,7 +11,7 @@ module Datadog
11
11
  self.active_test = nil
12
12
  end
13
13
 
14
- def activate_test!(test)
14
+ def activate_test(test)
15
15
  raise "Nested tests are not supported. Currently active test: #{active_test}" unless active_test.nil?
16
16
 
17
17
  if block_given?
@@ -26,14 +26,8 @@ module Datadog
26
26
  end
27
27
  end
28
28
 
29
- def deactivate_test!(test)
30
- return if active_test.nil?
31
-
32
- if active_test == test
33
- self.active_test = nil
34
- else
35
- raise "Trying to deactivate test #{test}, but currently active test is #{active_test}"
36
- end
29
+ def deactivate_test
30
+ self.active_test = nil
37
31
  end
38
32
 
39
33
  def active_test
@@ -23,7 +23,7 @@ module Datadog
23
23
  skip_tracing(block)
24
24
  end
25
25
 
26
- def trace(span_type, span_name, tags: {}, &block)
26
+ def trace(type, span_name, tags: {}, &block)
27
27
  skip_tracing(block)
28
28
  end
29
29
 
@@ -42,30 +42,10 @@ module Datadog
42
42
  def active_test_suite(test_suite_name)
43
43
  end
44
44
 
45
- def deactivate_test(test)
46
- end
47
-
48
- def deactivate_test_session
49
- end
50
-
51
- def deactivate_test_module
52
- end
53
-
54
- def deactivate_test_suite(test_suite_name)
55
- end
56
-
57
45
  private
58
46
 
59
47
  def skip_tracing(block = nil)
60
- if block
61
- block.call(null_span)
62
- else
63
- null_span
64
- end
65
- end
66
-
67
- def null_span
68
- @null_span ||= NullSpan.new
48
+ block.call(nil) if block
69
49
  end
70
50
  end
71
51
  end
@@ -8,12 +8,13 @@ require "rbconfig"
8
8
  require_relative "context/global"
9
9
  require_relative "context/local"
10
10
 
11
+ require_relative "../codeowners/parser"
11
12
  require_relative "../ext/app_types"
12
13
  require_relative "../ext/test"
13
14
  require_relative "../ext/environment"
15
+ require_relative "../utils/git"
14
16
 
15
17
  require_relative "../span"
16
- require_relative "../null_span"
17
18
  require_relative "../test"
18
19
  require_relative "../test_session"
19
20
  require_relative "../test_module"
@@ -27,12 +28,16 @@ module Datadog
27
28
  class Recorder
28
29
  attr_reader :environment_tags, :test_suite_level_visibility_enabled
29
30
 
30
- def initialize(test_suite_level_visibility_enabled: false)
31
+ def initialize(
32
+ test_suite_level_visibility_enabled: false,
33
+ codeowners: Codeowners::Parser.new(Utils::Git.root).parse
34
+ )
31
35
  @test_suite_level_visibility_enabled = test_suite_level_visibility_enabled
32
36
 
33
37
  @environment_tags = Ext::Environment.tags(ENV).freeze
34
38
  @local_context = Context::Local.new
35
39
  @global_context = Context::Global.new
40
+ @codeowners = codeowners
36
41
  end
37
42
 
38
43
  def start_test_session(service: nil, tags: {})
@@ -88,6 +93,7 @@ module Datadog
88
93
  set_suite_context(tags, name: test_suite_name)
89
94
 
90
95
  tags[Ext::Test::TAG_NAME] = test_name
96
+ tags[Ext::Test::TAG_TYPE] ||= Ext::Test::Type::TEST
91
97
 
92
98
  span_options = build_span_options(
93
99
  service,
@@ -101,7 +107,7 @@ module Datadog
101
107
  start_datadog_tracer_span(test_name, span_options) do |tracer_span|
102
108
  test = build_test(tracer_span, tags)
103
109
 
104
- @local_context.activate_test!(test) do
110
+ @local_context.activate_test(test) do
105
111
  block.call(test)
106
112
  end
107
113
  end
@@ -109,15 +115,15 @@ module Datadog
109
115
  tracer_span = start_datadog_tracer_span(test_name, span_options)
110
116
 
111
117
  test = build_test(tracer_span, tags)
112
- @local_context.activate_test!(test)
118
+ @local_context.activate_test(test)
113
119
  test
114
120
  end
115
121
  end
116
122
 
117
- def trace(span_type, span_name, tags: {}, &block)
123
+ def trace(span_name, type: "span", tags: {}, &block)
118
124
  span_options = build_span_options(
119
125
  nil, # service name is completely optional for custom spans
120
- span_type,
126
+ type,
121
127
  {resource: span_name}
122
128
  )
123
129
 
@@ -153,8 +159,8 @@ module Datadog
153
159
  @global_context.active_test_suite(test_suite_name)
154
160
  end
155
161
 
156
- def deactivate_test(test)
157
- @local_context.deactivate_test!(test)
162
+ def deactivate_test
163
+ @local_context.deactivate_test
158
164
  end
159
165
 
160
166
  def deactivate_test_session
@@ -172,11 +178,7 @@ module Datadog
172
178
  private
173
179
 
174
180
  def skip_tracing(block = nil)
175
- if block
176
- block.call(null_span)
177
- else
178
- null_span
179
- end
181
+ block.call(nil) if block
180
182
  end
181
183
 
182
184
  # Sets trace's origin to ciapp-test
@@ -206,6 +208,8 @@ module Datadog
206
208
  test = Test.new(tracer_span)
207
209
  set_initial_tags(test, tags)
208
210
  validate_test_suite_level_visibility_correctness(test)
211
+ set_codeowners(test)
212
+
209
213
  test
210
214
  end
211
215
 
@@ -215,9 +219,9 @@ module Datadog
215
219
  span
216
220
  end
217
221
 
218
- def build_span_options(service, span_type, other_options = {})
222
+ def build_span_options(service, type, other_options = {})
219
223
  other_options[:service] = service || @global_context.service
220
- other_options[:span_type] = span_type
224
+ other_options[:type] = type
221
225
 
222
226
  other_options
223
227
  end
@@ -251,6 +255,12 @@ module Datadog
251
255
  end
252
256
  end
253
257
 
258
+ def set_codeowners(test)
259
+ source = test.source_file
260
+ owners = @codeowners.list_owners(source) if source
261
+ test.set_tag(Ext::Test::TAG_CODEOWNERS, owners) unless owners.nil?
262
+ end
263
+
254
264
  def set_suite_context(tags, span: nil, name: nil)
255
265
  return if span.nil? && name.nil?
256
266
 
@@ -280,10 +290,6 @@ module Datadog
280
290
  end
281
291
  end
282
292
 
283
- def null_span
284
- @null_span ||= NullSpan.new
285
- end
286
-
287
293
  def validate_test_suite_level_visibility_correctness(test)
288
294
  return unless test_suite_level_visibility_enabled
289
295
 
@@ -34,7 +34,7 @@ module Datadog
34
34
  @trace = trace
35
35
  @span = span
36
36
 
37
- @meta = @span.meta.reject { |key, _| Ext::Test::SPECIAL_TAGS.include?(key) }
37
+ @meta = @span.meta.reject { |key, _| Ext::Test::TRANSIENT_TAGS.include?(key) }
38
38
 
39
39
  @errors = {}
40
40
  @validated = false
@@ -45,7 +45,7 @@ module Datadog
45
45
 
46
46
  packer.write_map_header(3)
47
47
 
48
- write_field(packer, "type")
48
+ write_field(packer, "type", "event_type")
49
49
  write_field(packer, "version")
50
50
 
51
51
  packer.write("content")
@@ -119,9 +119,6 @@ module Datadog
119
119
  to_integer(@span.get_tag(Ext::Test::TAG_TEST_SUITE_ID))
120
120
  end
121
121
 
122
- def type
123
- end
124
-
125
122
  def version
126
123
  1
127
124
  end
@@ -130,6 +127,10 @@ module Datadog
130
127
  @span.type
131
128
  end
132
129
 
130
+ def event_type
131
+ "span"
132
+ end
133
+
133
134
  def name
134
135
  @span.name
135
136
  end
@@ -21,7 +21,7 @@ module Datadog
21
21
  CONTENT_MAP_SIZE
22
22
  end
23
23
 
24
- def type
24
+ def event_type
25
25
  "span"
26
26
  end
27
27
 
@@ -22,7 +22,7 @@ module Datadog
22
22
  CONTENT_MAP_SIZE
23
23
  end
24
24
 
25
- def type
25
+ def event_type
26
26
  Ext::AppTypes::TYPE_TEST_MODULE
27
27
  end
28
28
 
@@ -22,7 +22,7 @@ module Datadog
22
22
  CONTENT_MAP_SIZE
23
23
  end
24
24
 
25
- def type
25
+ def event_type
26
26
  Ext::AppTypes::TYPE_TEST_SESSION
27
27
  end
28
28
 
@@ -22,7 +22,7 @@ module Datadog
22
22
  CONTENT_MAP_SIZE
23
23
  end
24
24
 
25
- def type
25
+ def event_type
26
26
  Ext::AppTypes::TYPE_TEST_SUITE
27
27
  end
28
28
 
@@ -22,7 +22,7 @@ module Datadog
22
22
  CONTENT_MAP_SIZE
23
23
  end
24
24
 
25
- def type
25
+ def event_type
26
26
  Ext::AppTypes::TYPE_TEST
27
27
  end
28
28
 
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "git"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Utils
8
+ module Configuration
9
+ def self.fetch_service_name(default)
10
+ Datadog.configuration.service_without_fallback || Git.repository_name || default
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "open3"
4
+ require "pathname"
5
+
3
6
  module Datadog
4
7
  module CI
5
8
  module Utils
@@ -16,6 +19,73 @@ module Datadog
16
19
  def self.is_git_tag?(ref)
17
20
  !ref.nil? && ref.include?("tags/")
18
21
  end
22
+
23
+ def self.root
24
+ return @root if defined?(@root)
25
+
26
+ @root = exec_git_command("git rev-parse --show-toplevel")
27
+ rescue => e
28
+ Datadog.logger.debug(
29
+ "Unable to read git root: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
30
+ )
31
+ @root = nil
32
+ end
33
+
34
+ def self.relative_to_root(path)
35
+ return nil if path.nil?
36
+
37
+ git_root = root
38
+ return path if git_root.nil?
39
+
40
+ path = Pathname.new(File.expand_path(path))
41
+ git_root = Pathname.new(git_root)
42
+
43
+ path.relative_path_from(git_root).to_s
44
+ end
45
+
46
+ def self.repository_name
47
+ return @repository_name if defined?(@repository_name)
48
+
49
+ git_remote_url = exec_git_command("git ls-remote --get-url origin")
50
+
51
+ # return git repository name from remote url without .git extension
52
+ last_path_segment = git_remote_url.split("/").last if git_remote_url
53
+ @repository_name = last_path_segment.gsub(".git", "") if last_path_segment
54
+ @repository_name ||= current_folder_name
55
+ rescue => e
56
+ Datadog.logger.debug(
57
+ "Unable to get git remote: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
58
+ )
59
+ @repository_name = current_folder_name
60
+ end
61
+
62
+ def self.current_folder_name
63
+ root_folder = root
64
+ if root_folder.nil?
65
+ File.basename(Dir.pwd)
66
+ else
67
+ File.basename(root_folder)
68
+ end
69
+ end
70
+
71
+ def self.exec_git_command(cmd)
72
+ out, status = Open3.capture2e(cmd)
73
+
74
+ raise "Failed to run git command #{cmd}: #{out}" unless status.success?
75
+
76
+ # Sometimes Encoding.default_external is somehow set to US-ASCII which breaks
77
+ # commit messages with UTF-8 characters like emojis
78
+ # We force output's encoding to be UTF-8 in this case
79
+ # This is safe to do as UTF-8 is compatible with US-ASCII
80
+ if Encoding.default_external == Encoding::US_ASCII
81
+ out = out.force_encoding(Encoding::UTF_8)
82
+ end
83
+ out.strip! # There's always a "\n" at the end of the command output
84
+
85
+ return nil if out.empty?
86
+
87
+ out
88
+ end
19
89
  end
20
90
  end
21
91
  end
@@ -4,7 +4,7 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = "0"
7
- MINOR = "6"
7
+ MINOR = "7"
8
8
  PATCH = "0"
9
9
  PRE = nil
10
10
  BUILD = nil
data/lib/datadog/ci.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "ci/version"
4
+ require_relative "ci/utils/configuration"
5
+ require_relative "ci/ext/app_types"
4
6
 
5
7
  require "datadog/core"
6
8
 
@@ -9,6 +11,8 @@ module Datadog
9
11
  #
10
12
  # @public_api
11
13
  module CI
14
+ class ReservedTypeError < StandardError; end
15
+
12
16
  class << self
13
17
  # Starts a {Datadog::CI::TestSession ci_test_session} that represents the whole test session run.
14
18
  #
@@ -30,13 +34,11 @@ module Datadog
30
34
  #
31
35
  # Remember that calling {Datadog::CI::TestSession#finish} is mandatory.
32
36
  #
33
- # @param [String] service the service name for this session (optional, defaults to DD_SERVICE)
37
+ # @param [String] service the service name for this session (optional, defaults to DD_SERVICE or repository name)
34
38
  # @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
39
+ # @return [Datadog::CI::TestSession] the active, running {Datadog::CI::TestSession}.
40
+ # @return [nil] if test suite level visibility is disabled or CI mode is disabled.
41
+ def start_test_session(service: Utils::Configuration.fetch_service_name("test"), tags: {})
40
42
  recorder.start_test_session(service: service, tags: tags)
41
43
  end
42
44
 
@@ -88,9 +90,8 @@ module Datadog
88
90
  # @param [String] test_module_name the name for this module
89
91
  # @param [String] service the service name for this session (optional, inherited from test session if not provided)
90
92
  # @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.
93
+ # @return [Datadog::CI::TestModule] the active, running {Datadog::CI::TestModule}.
94
+ # @return [nil] if test suite level visibility is disabled or CI mode is disabled.
94
95
  def start_test_module(test_module_name, service: nil, tags: {})
95
96
  recorder.start_test_module(test_module_name, service: service, tags: tags)
96
97
  end
@@ -141,9 +142,8 @@ module Datadog
141
142
  # @param [String] test_suite_name the name of the test suite
142
143
  # @param [String] service the service name for this test suite (optional, inherited from test session if not provided)
143
144
  # @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.
145
+ # @return [Datadog::CI::TestSuite] the active, running {Datadog::CI::TestSuite}.
146
+ # @return [nil] if test suite level visibility is disabled or CI mode is disabled.
147
147
  def start_test_suite(test_suite_name, service: nil, tags: {})
148
148
  recorder.start_test_suite(test_suite_name, service: service, tags: tags)
149
149
  end
@@ -217,10 +217,10 @@ module Datadog
217
217
  # @return [Object] If a block is provided, returns the result of the block execution.
218
218
  # @return [Datadog::CI::Test] If no block is provided, returns the active,
219
219
  # unfinished {Datadog::CI::Test}.
220
- # @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
220
+ # @return [nil] if no block is provided and CI mode is disabled.
221
221
  # @yield Optional block where newly created {Datadog::CI::Test} captures the execution.
222
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
223
+ # @yieldparam [nil] if CI mode is disabled
224
224
  def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
225
225
  recorder.trace_test(test_name, test_suite_name, service: service, tags: tags, &block)
226
226
  end
@@ -245,8 +245,8 @@ module Datadog
245
245
  # @param [String] test_suite_name name of test suite this test belongs to (example: "CalculatorTest").
246
246
  # @param [String] service the service name for this span (optional, inherited from test session if not provided)
247
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
248
+ # @return [Datadog::CI::Test] the active, unfinished {Datadog::CI::Test}.
249
+ # @return [nil] if CI mode is disabled.
250
250
  def start_test(test_name, test_suite_name, service: nil, tags: {})
251
251
  recorder.trace_test(test_name, test_suite_name, service: service, tags: tags)
252
252
  end
@@ -260,8 +260,8 @@ module Datadog
260
260
  #
261
261
  # ```
262
262
  # Datadog::CI.trace(
263
- # "step",
264
263
  # "Given I have 42 cucumbers",
264
+ # type: "step",
265
265
  # tags: {}
266
266
  # ) do
267
267
  # run_operation
@@ -271,8 +271,8 @@ module Datadog
271
271
  # The {.trace} method can also be used without a block in this way:
272
272
  # ```
273
273
  # ci_span = Datadog::CI.trace(
274
- # "step",
275
274
  # "Given I have 42 cucumbers",
275
+ # type: "step",
276
276
  # tags: {}
277
277
  # )
278
278
  # # ... run test here ...
@@ -280,22 +280,31 @@ module Datadog
280
280
  # ```
281
281
  # Remember that in this case, calling {Datadog::CI::Span#finish} is mandatory.
282
282
  #
283
- # @param [String] span_type custom, user-defined span type (for example "step" or "query").
284
283
  # @param [String] span_name the resource this span refers, or `test` if it's missing
284
+ # @param [String] type custom, user-defined span type (for example "step" or "query").
285
285
  # @param [Hash<String,String>] tags extra tags which should be added to the span.
286
286
  # @return [Object] If a block is provided, returns the result of the block execution.
287
287
  # @return [Datadog::CI::Span] If no block is provided, returns the active,
288
288
  # unfinished {Datadog::CI::Span}.
289
- # @return [Datadog::CI::NullSpan] ci_span null object if CI visibility is disabled
289
+ # @return [nil] if CI visibility is disabled
290
+ # @raise [ReservedTypeError] if provided type is reserved for Datadog CI visibility
290
291
  # @yield Optional block where newly created {Datadog::CI::Span} captures the execution.
291
292
  # @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)
293
+ # @yieldparam [nil] ci_span if CI visibility is disabled
294
+ def trace(span_name, type: "span", tags: {}, &block)
295
+ if Ext::AppTypes::CI_SPAN_TYPES.include?(type)
296
+ raise(
297
+ ReservedTypeError,
298
+ "Span type #{type} is reserved for Datadog CI visibility. " \
299
+ "Reserved types are: #{Ext::AppTypes::CI_SPAN_TYPES}"
300
+ )
301
+ end
302
+
303
+ recorder.trace(span_name, type: type, tags: tags, &block)
295
304
  end
296
305
 
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.
306
+ # The active, unfinished custom (i.e. not test/suite/module/session) span.
307
+ # If no span is active, or if the active span is not a custom span, returns nil.
299
308
  #
300
309
  # The active span belongs to an {.active_test}.
301
310
  #
@@ -304,22 +313,21 @@ module Datadog
304
313
  # ```
305
314
  # # start span
306
315
  # Datadog::CI.trace(
307
- # "step",
308
316
  # "Given I have 42 cucumbers",
317
+ # type: "step",
309
318
  # tags: {}
310
319
  # )
311
320
  #
312
- # # somewhere else, access the active "step" span
313
- # step_span = Datadog::CI.active_span("step")
321
+ # # somewhere else, access the active step span
322
+ # step_span = Datadog::CI.active_span
314
323
  # step_span.finish()
315
324
  # ```
316
325
  #
317
- # @param [String] span_type type of the span to retrieve (for example "step" or "query") that was provided to {.trace}
318
326
  # @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)
327
+ # @return [nil] if no span is active, or if the active span is not a custom span
328
+ def active_span
321
329
  span = recorder.active_span
322
- span if span && span.span_type == span_type
330
+ span if span && !Ext::AppTypes::CI_SPAN_TYPES.include?(span.type)
323
331
  end
324
332
 
325
333
  # The active, unfinished test span.
@@ -347,30 +355,6 @@ module Datadog
347
355
  recorder.active_test
348
356
  end
349
357
 
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
358
  private
375
359
 
376
360
  def components