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
@@ -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
+ test_session = 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(test_session.name) if test_session
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,21 +14,21 @@ 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(test_session.name) if test_session
30
29
 
31
30
  result = super
31
+ return result unless test_module && test_session
32
32
 
33
33
  if result != 0
34
34
  # TODO: repeating this twice feels clunky, we need to remove test_module API before GA
@@ -46,7 +46,7 @@ module Datadog
46
46
 
47
47
  private
48
48
 
49
- def configuration
49
+ def datadog_configuration
50
50
  Datadog.configuration.ci[:rspec]
51
51
  end
52
52
  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"
@@ -1,9 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "open3"
4
-
5
3
  require_relative "base"
6
- require_relative "../../git"
4
+ require_relative "../../../utils/git"
7
5
 
8
6
  module Datadog
9
7
  module CI
@@ -13,7 +11,7 @@ module Datadog
13
11
  # As a fallback we try to fetch git information from the local git repository
14
12
  class LocalGit < Base
15
13
  def git_repository_url
16
- exec_git_command("git ls-remote --get-url")
14
+ Utils::Git.exec_git_command("git ls-remote --get-url")
17
15
  rescue => e
18
16
  Datadog.logger.debug(
19
17
  "Unable to read git repository url: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
@@ -22,7 +20,7 @@ module Datadog
22
20
  end
23
21
 
24
22
  def git_commit_sha
25
- exec_git_command("git rev-parse HEAD")
23
+ Utils::Git.exec_git_command("git rev-parse HEAD")
26
24
  rescue => e
27
25
  Datadog.logger.debug(
28
26
  "Unable to read git commit SHA: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
@@ -31,7 +29,7 @@ module Datadog
31
29
  end
32
30
 
33
31
  def git_branch
34
- exec_git_command("git rev-parse --abbrev-ref HEAD")
32
+ Utils::Git.exec_git_command("git rev-parse --abbrev-ref HEAD")
35
33
  rescue => e
36
34
  Datadog.logger.debug(
37
35
  "Unable to read git branch: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
@@ -40,7 +38,7 @@ module Datadog
40
38
  end
41
39
 
42
40
  def git_tag
43
- exec_git_command("git tag --points-at HEAD")
41
+ Utils::Git.exec_git_command("git tag --points-at HEAD")
44
42
  rescue => e
45
43
  Datadog.logger.debug(
46
44
  "Unable to read git tag: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
@@ -49,7 +47,7 @@ module Datadog
49
47
  end
50
48
 
51
49
  def git_commit_message
52
- exec_git_command("git show -s --format=%s")
50
+ Utils::Git.exec_git_command("git show -s --format=%s")
53
51
  rescue => e
54
52
  Datadog.logger.debug(
55
53
  "Unable to read git commit message: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
@@ -82,7 +80,7 @@ module Datadog
82
80
  end
83
81
 
84
82
  def workspace_path
85
- exec_git_command("git rev-parse --show-toplevel")
83
+ Utils::Git.exec_git_command("git rev-parse --show-toplevel")
86
84
  rescue => e
87
85
  Datadog.logger.debug(
88
86
  "Unable to read git base directory: #{e.class.name} #{e.message} at #{Array(e.backtrace).first}"
@@ -92,25 +90,6 @@ module Datadog
92
90
 
93
91
  private
94
92
 
95
- def exec_git_command(cmd)
96
- out, status = Open3.capture2e(cmd)
97
-
98
- raise "Failed to run git command #{cmd}: #{out}" unless status.success?
99
-
100
- # Sometimes Encoding.default_external is somehow set to US-ASCII which breaks
101
- # commit messages with UTF-8 characters like emojis
102
- # We force output's encoding to be UTF-8 in this case
103
- # This is safe to do as UTF-8 is compatible with US-ASCII
104
- if Encoding.default_external == Encoding::US_ASCII
105
- out = out.force_encoding(Encoding::UTF_8)
106
- end
107
- out.strip! # There's always a "\n" at the end of the command output
108
-
109
- return nil if out.empty?
110
-
111
- out
112
- end
113
-
114
93
  def author
115
94
  return @author if defined?(@author)
116
95
 
@@ -127,7 +106,7 @@ module Datadog
127
106
 
128
107
  def set_git_commit_users
129
108
  # Get committer and author information in one command.
130
- output = exec_git_command("git show -s --format='%an\t%ae\t%at\t%cn\t%ce\t%ct'")
109
+ output = Utils::Git.exec_git_command("git show -s --format='%an\t%ae\t%at\t%cn\t%ce\t%ct'")
131
110
  unless output
132
111
  Datadog.logger.debug(
133
112
  "Unable to read git commit users: git command output is nil"
@@ -9,6 +9,7 @@ module Datadog
9
9
  ENV_AGENTLESS_MODE_ENABLED = "DD_CIVISIBILITY_AGENTLESS_ENABLED"
10
10
  ENV_AGENTLESS_URL = "DD_CIVISIBILITY_AGENTLESS_URL"
11
11
  ENV_EXPERIMENTAL_TEST_SUITE_LEVEL_VISIBILITY_ENABLED = "DD_CIVISIBILITY_EXPERIMENTAL_TEST_SUITE_LEVEL_VISIBILITY_ENABLED"
12
+ ENV_FORCE_TEST_LEVEL_VISIBILITY = "DD_CIVISIBILITY_FORCE_TEST_LEVEL_VISIBILITY"
12
13
 
13
14
  # Source: https://docs.datadoghq.com/getting_started/site/
14
15
  DD_SITE_ALLOWLIST = [
@@ -12,24 +12,26 @@ module Datadog
12
12
  TAG_FRAMEWORK = "test.framework"
13
13
  TAG_FRAMEWORK_VERSION = "test.framework_version"
14
14
  TAG_NAME = "test.name"
15
- TAG_SKIP_REASON = "test.skip_reason" # DEV: Not populated yet
15
+ TAG_SKIP_REASON = "test.skip_reason"
16
16
  TAG_STATUS = "test.status"
17
17
  TAG_SUITE = "test.suite"
18
18
  TAG_MODULE = "test.module"
19
- TAG_TRAITS = "test.traits"
20
19
  TAG_TYPE = "test.type"
21
20
  TAG_COMMAND = "test.command"
21
+ TAG_SOURCE_FILE = "test.source.file"
22
+ TAG_SOURCE_START = "test.source.start"
23
+ TAG_CODEOWNERS = "test.codeowners"
24
+ TAG_PARAMETERS = "test.parameters"
22
25
 
23
- TEST_TYPE = "test"
24
-
25
- # those tags are special and they are used to correlate tests with the test sessions, suites, and modules
26
+ # those tags are special and used to correlate tests with the test sessions, suites, and modules
27
+ # they are transient and not sent to the backend
26
28
  TAG_TEST_SESSION_ID = "_test.session_id"
27
29
  TAG_TEST_MODULE_ID = "_test.module_id"
28
30
  TAG_TEST_SUITE_ID = "_test.suite_id"
29
- SPECIAL_TAGS = [TAG_TEST_SESSION_ID, TAG_TEST_MODULE_ID, TAG_TEST_SUITE_ID].freeze
31
+ TRANSIENT_TAGS = [TAG_TEST_SESSION_ID, TAG_TEST_MODULE_ID, TAG_TEST_SUITE_ID].freeze
30
32
 
31
- # tags that can be inherited from the test session
32
- INHERITABLE_TAGS = [TAG_FRAMEWORK, TAG_FRAMEWORK_VERSION, TAG_TYPE].freeze
33
+ # tags that are common for the whole session and can be inherited from the test session
34
+ INHERITABLE_TAGS = [TAG_FRAMEWORK, TAG_FRAMEWORK_VERSION].freeze
33
35
 
34
36
  # Environment runtime tags
35
37
  TAG_OS_ARCHITECTURE = "os.architecture"
@@ -37,13 +39,22 @@ module Datadog
37
39
  TAG_RUNTIME_NAME = "runtime.name"
38
40
  TAG_RUNTIME_VERSION = "runtime.version"
39
41
 
42
+ # internal APM tag to mark a span as a test span
40
43
  TAG_SPAN_KIND = "span.kind"
44
+ SPAN_KIND_TEST = "test"
41
45
 
46
+ # test status as recognized by Datadog
42
47
  module Status
43
48
  PASS = "pass"
44
49
  FAIL = "fail"
45
50
  SKIP = "skip"
46
51
  end
52
+
53
+ # test types (e.g. test, benchmark, browser)
54
+ module Type
55
+ TEST = "test"
56
+ BENCHMARK = "benchmark" # DEV: not used yet, will be used when benchmarks are supported
57
+ end
47
58
  end
48
59
  end
49
60
  end
@@ -32,7 +32,7 @@ module Datadog
32
32
  end
33
33
 
34
34
  # @return [String] the type of the span (for example "test" or type that was provided to [Datadog::CI.trace]).
35
- def span_type
35
+ def type
36
36
  tracer_span.type
37
37
  end
38
38
 
@@ -130,12 +130,19 @@ module Datadog
130
130
  end
131
131
 
132
132
  def set_default_tags
133
- tracer_span.set_tag(Ext::Test::TAG_SPAN_KIND, Ext::AppTypes::TYPE_TEST)
133
+ tracer_span.set_tag(Ext::Test::TAG_SPAN_KIND, Ext::Test::SPAN_KIND_TEST)
134
134
  end
135
135
 
136
136
  def to_s
137
137
  "#{self.class}(name:#{name},tracer_span:#{@tracer_span})"
138
138
  end
139
+
140
+ private
141
+
142
+ # provides access to global CI recorder for CI models to deactivate themselves
143
+ def recorder
144
+ Datadog.send(:components).ci_recorder
145
+ end
139
146
  end
140
147
  end
141
148
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "json"
4
+
3
5
  require_relative "span"
4
6
 
5
7
  module Datadog
@@ -18,7 +20,7 @@ module Datadog
18
20
  def finish
19
21
  super
20
22
 
21
- CI.deactivate_test(self)
23
+ recorder.deactivate_test
22
24
  end
23
25
 
24
26
  # Running test suite that this test is part of (if any).
@@ -35,6 +37,8 @@ module Datadog
35
37
  get_tag(Ext::Test::TAG_TEST_SUITE_ID)
36
38
  end
37
39
 
40
+ # Name of the running test suite this test belongs to.
41
+ # @return [String] the name of the test suite.
38
42
  def test_suite_name
39
43
  get_tag(Ext::Test::TAG_SUITE)
40
44
  end
@@ -45,11 +49,72 @@ module Datadog
45
49
  get_tag(Ext::Test::TAG_TEST_MODULE_ID)
46
50
  end
47
51
 
48
- # Span id of the running test module this test belongs to.
52
+ # Span id of the running test session this test belongs to.
49
53
  # @return [String] the span id of the test session.
50
54
  def test_session_id
51
55
  get_tag(Ext::Test::TAG_TEST_SESSION_ID)
52
56
  end
57
+
58
+ # Source file path of the test relative to git repository root.
59
+ # @return [String] the source file path of the test
60
+ # @return [nil] if the source file path is not found
61
+ def source_file
62
+ get_tag(Ext::Test::TAG_SOURCE_FILE)
63
+ end
64
+
65
+ # Sets the status of the span to "pass".
66
+ # @return [void]
67
+ def passed!
68
+ super
69
+
70
+ record_test_result(Ext::Test::Status::PASS)
71
+ end
72
+
73
+ # Sets the status of the span to "fail".
74
+ # @param [Exception] exception the exception that caused the test to fail.
75
+ # @return [void]
76
+ def failed!(exception: nil)
77
+ super
78
+
79
+ record_test_result(Ext::Test::Status::FAIL)
80
+ end
81
+
82
+ # Sets the status of the span to "skip".
83
+ # @param [Exception] exception the exception that caused the test to fail.
84
+ # @param [String] reason the reason why the test was skipped.
85
+ # @return [void]
86
+ def skipped!(exception: nil, reason: nil)
87
+ super
88
+
89
+ record_test_result(Ext::Test::Status::SKIP)
90
+ end
91
+
92
+ # Sets the parameters for this test (e.g. Cucumber example or RSpec shared specs).
93
+ # Parameters are needed to compute test fingerprint to distinguish between different tests having same names.
94
+ #
95
+ # @param [Hash] arguments the arguments that test accepts as key-value hash
96
+ # @param [Hash] metadata optional metadata
97
+ # @return [void]
98
+ def set_parameters(arguments, metadata = {})
99
+ return if arguments.nil?
100
+
101
+ set_tag(
102
+ Ext::Test::TAG_PARAMETERS,
103
+ JSON.generate(
104
+ {
105
+ arguments: arguments,
106
+ metadata: metadata
107
+ }
108
+ )
109
+ )
110
+ end
111
+
112
+ private
113
+
114
+ def record_test_result(datadog_status)
115
+ suite = test_suite
116
+ suite.record_test_result(datadog_status) if suite
117
+ end
53
118
  end
54
119
  end
55
120
  end
@@ -16,7 +16,7 @@ module Datadog
16
16
  def finish
17
17
  super
18
18
 
19
- CI.deactivate_test_module
19
+ recorder.deactivate_test_module
20
20
  end
21
21
  end
22
22
  end
@@ -17,7 +17,7 @@ module Datadog
17
17
  def finish
18
18
  super
19
19
 
20
- CI.deactivate_test_session
20
+ recorder.deactivate_test_session
21
21
  end
22
22
 
23
23
  # Return the test session's name which is equal to test command used
@@ -32,7 +32,7 @@ module Datadog
32
32
  return @inheritable_tags if defined?(@inheritable_tags)
33
33
 
34
34
  # this method is not synchronized because it does not iterate over the tags collection, but rather
35
- # uses synchronized method to get each tag value
35
+ # uses synchronized method #get_tag to get each tag value
36
36
  res = {}
37
37
  Ext::Test::INHERITABLE_TAGS.each do |tag|
38
38
  res[tag] = get_tag(tag)