datadog-ci 1.5.0 → 1.7.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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -2
  3. data/README.md +1 -0
  4. data/lib/datadog/ci/configuration/components.rb +2 -1
  5. data/lib/datadog/ci/configuration/settings.rb +5 -0
  6. data/lib/datadog/ci/contrib/cucumber/formatter.rb +25 -3
  7. data/lib/datadog/ci/contrib/minitest/helpers.rb +4 -4
  8. data/lib/datadog/ci/contrib/minitest/runnable.rb +15 -2
  9. data/lib/datadog/ci/contrib/rspec/example_group.rb +7 -1
  10. data/lib/datadog/ci/contrib/simplecov/configuration/settings.rb +26 -0
  11. data/lib/datadog/ci/contrib/simplecov/ext.rb +15 -0
  12. data/lib/datadog/ci/contrib/simplecov/integration.rb +47 -0
  13. data/lib/datadog/ci/contrib/simplecov/patcher.rb +28 -0
  14. data/lib/datadog/ci/contrib/simplecov/result_extractor.rb +36 -0
  15. data/lib/datadog/ci/ext/environment/extractor.rb +5 -0
  16. data/lib/datadog/ci/ext/environment/providers/base.rb +4 -0
  17. data/lib/datadog/ci/ext/environment/providers/github_actions.rb +24 -0
  18. data/lib/datadog/ci/ext/git.rb +5 -0
  19. data/lib/datadog/ci/ext/settings.rb +1 -0
  20. data/lib/datadog/ci/ext/test.rb +9 -0
  21. data/lib/datadog/ci/span.rb +14 -0
  22. data/lib/datadog/ci/test.rb +0 -7
  23. data/lib/datadog/ci/test_session.rb +18 -0
  24. data/lib/datadog/ci/test_visibility/component.rb +23 -5
  25. data/lib/datadog/ci/test_visibility/context.rb +4 -0
  26. data/lib/datadog/ci/test_visibility/null_component.rb +7 -0
  27. data/lib/datadog/ci/test_visibility/telemetry.rb +1 -3
  28. data/lib/datadog/ci/test_visibility/total_coverage.rb +36 -0
  29. data/lib/datadog/ci/test_visibility/transport.rb +21 -3
  30. data/lib/datadog/ci/utils/test_run.rb +8 -0
  31. data/lib/datadog/ci/version.rb +1 -1
  32. data/lib/datadog/ci.rb +1 -0
  33. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 876a0e7ada3aeaf87b19dade6ee73fec0fe8d37387cde5fc31b43aaad76e99c5
4
- data.tar.gz: 8c46ad7c35a621ae03b7b42faa5b3c6934066e422ff4d3a8ac2249cd6466ecd3
3
+ metadata.gz: f4cb94bf0ef94f54289e38a26649d24eeaaca99ba91229f5ebb096c046bdc582
4
+ data.tar.gz: 9a88847a58121a1516b95fc1abac1fa89d4a1bab5c4593f932fc804410ee8a57
5
5
  SHA512:
6
- metadata.gz: 8f312e6920cad6072665c00dc5d253e66a7c3272abda20e79f86cf11beb38fffe0be789f644affb6f8920e458f00f221c7969fb84c2ee6f2198af6a140eafc64
7
- data.tar.gz: f9b7c2b184e7a140269eaa2069cbf5062270d6bb07410fd9b46cab4c521a8d0bd694a676086164c58300c264357e53e0118611053f6bdf0c2dee757b487b4769
6
+ metadata.gz: 7830a7b52821efbea8e0f86e878588ef96718e845fd7a33575a4a5e92d350e26e36bb4b78f7ce78b58ff59654c62973c4eca58f21c63b958d44f4d8feff122cc
7
+ data.tar.gz: da8d30e84f9dea71eb498cccb6e03cb092e27e773008dc7533188020ee5cb59de774e4d2be32821e3fd82e28f4ccb426572695fd532dc7f7fff6479a392bca85
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.7.0] - 2024-09-25
4
+
5
+ ### Added
6
+ * Report total lines coverage percentage to Datadog ([#240][])
7
+ * add source location info to test suites ([#239][])
8
+ * Add pull_request extra tags for GitHub Actions ([#238][])
9
+
10
+ ## [1.6.0] - 2024-09-20
11
+
12
+
13
+ ### Added
14
+ * support logical names for test sessions ([#235][])
15
+ * Send internal vCPU count metric ([#236][])
16
+
3
17
  ## [1.5.0] - 2024-09-18
4
18
 
5
19
  ### Added
@@ -325,7 +339,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
325
339
 
326
340
  - Ruby versions < 2.7 no longer supported ([#8][])
327
341
 
328
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.5.0...main
342
+ [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.7.0...main
343
+ [1.7.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.6.0...v1.7.0
344
+ [1.6.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.5.0...v1.6.0
329
345
  [1.5.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.4.1...v1.5.0
330
346
  [1.4.1]: https://github.com/DataDog/datadog-ci-rb/compare/v1.4.0...v1.4.1
331
347
  [1.4.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.3.0...v1.4.0
@@ -467,4 +483,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
467
483
  [#226]: https://github.com/DataDog/datadog-ci-rb/issues/226
468
484
  [#227]: https://github.com/DataDog/datadog-ci-rb/issues/227
469
485
  [#229]: https://github.com/DataDog/datadog-ci-rb/issues/229
470
- [#231]: https://github.com/DataDog/datadog-ci-rb/issues/231
486
+ [#231]: https://github.com/DataDog/datadog-ci-rb/issues/231
487
+ [#235]: https://github.com/DataDog/datadog-ci-rb/issues/235
488
+ [#236]: https://github.com/DataDog/datadog-ci-rb/issues/236
489
+ [#238]: https://github.com/DataDog/datadog-ci-rb/issues/238
490
+ [#239]: https://github.com/DataDog/datadog-ci-rb/issues/239
491
+ [#240]: https://github.com/DataDog/datadog-ci-rb/issues/240
data/README.md CHANGED
@@ -13,6 +13,7 @@ Learn more on our [official website](https://docs.datadoghq.com/tests/) and chec
13
13
  - [Test Visibility](https://docs.datadoghq.com/tests/) - collect metrics and results for your tests
14
14
  - [Intelligent test runner](https://docs.datadoghq.com/intelligent_test_runner/) - save time by selectively running only tests affected by code changes
15
15
  - [Auto test retries](https://docs.datadoghq.com/tests/auto_test_retries/?tab=ruby) - retrying failing tests up to N times to avoid failing your build due to flaky tests
16
+ - [Early flake detection](https://docs.datadoghq.com/tests/early_flake_detection?tab=ruby) - Datadog’s test flakiness solution that identifies flakes early by running newly added tests multiple times
16
17
  - [Search and manage CI tests](https://docs.datadoghq.com/tests/search/)
17
18
  - [Enhance developer workflows](https://docs.datadoghq.com/tests/developer_workflows)
18
19
  - [Flaky test management](https://docs.datadoghq.com/tests/guides/flaky_test_management/)
@@ -123,7 +123,8 @@ module Datadog
123
123
  # @type ivar @test_optimisation: Datadog::CI::TestOptimisation::Component
124
124
  @test_optimisation = build_test_optimisation(settings, test_visibility_api)
125
125
  @test_visibility = TestVisibility::Component.new(
126
- test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility
126
+ test_suite_level_visibility_enabled: !settings.ci.force_test_level_visibility,
127
+ logical_test_session_name: settings.ci.test_session_name
127
128
  )
128
129
  end
129
130
 
@@ -24,6 +24,11 @@ module Datadog
24
24
  o.default false
25
25
  end
26
26
 
27
+ option :test_session_name do |o|
28
+ o.type :string, nilable: true
29
+ o.env CI::Ext::Settings::ENV_TEST_SESSION_NAME
30
+ end
31
+
27
32
  option :agentless_mode_enabled do |o|
28
33
  o.type :bool
29
34
  o.env CI::Ext::Settings::ENV_AGENTLESS_MODE_ENABLED
@@ -70,7 +70,12 @@ module Datadog
70
70
  tags[CI::Ext::Test::TAG_PARAMETERS] = Utils::TestRun.test_parameters(arguments: parameters)
71
71
  end
72
72
 
73
- start_test_suite(test_suite_name) unless same_test_suite_as_current?(test_suite_name)
73
+ unless same_test_suite_as_current?(test_suite_name)
74
+ start_test_suite(
75
+ test_suite_name,
76
+ tags: test_suite_source_file_tags(event.test_case)
77
+ )
78
+ end
74
79
 
75
80
  test_span = test_visibility_component.trace_test(
76
81
  event.test_case.name,
@@ -146,10 +151,10 @@ module Datadog
146
151
  test_session.finish
147
152
  end
148
153
 
149
- def start_test_suite(test_suite_name)
154
+ def start_test_suite(test_suite_name, tags: {})
150
155
  finish_current_test_suite
151
156
 
152
- @current_test_suite = test_visibility_component.start_test_suite(test_suite_name)
157
+ @current_test_suite = test_visibility_component.start_test_suite(test_suite_name, tags: tags)
153
158
  end
154
159
 
155
160
  def finish_current_test_suite
@@ -201,6 +206,23 @@ module Datadog
201
206
  def test_visibility_component
202
207
  Datadog.send(:components).test_visibility
203
208
  end
209
+
210
+ def test_suite_source_file_tags(test_case)
211
+ if test_case.respond_to?(:parent_locations)
212
+ # supported in cucumber >= 9.0
213
+ source_file = test_case.parent_locations.file
214
+ line_number = test_case.parent_locations.line.to_s
215
+ else
216
+ # fallback for cucumber < 9.0
217
+ source_file = test_case.location.file
218
+ line_number = "1"
219
+ end
220
+
221
+ {
222
+ CI::Ext::Test::TAG_SOURCE_FILE => Git::LocalRepository.relative_to_root(source_file),
223
+ CI::Ext::Test::TAG_SOURCE_START => line_number.to_s
224
+ }
225
+ end
204
226
  end
205
227
  end
206
228
  end
@@ -6,7 +6,7 @@ module Datadog
6
6
  module Minitest
7
7
  module Helpers
8
8
  def self.test_suite_name(klass, method_name)
9
- source_location = extract_source_location_from_class(klass)
9
+ source_location = extract_source_location_from_class(klass)&.first
10
10
  # if we are in anonymous class, fallback to the method source location
11
11
  if source_location.nil?
12
12
  source_location, = klass.instance_method(method_name).source_location
@@ -23,11 +23,11 @@ module Datadog
23
23
  end
24
24
 
25
25
  def self.extract_source_location_from_class(klass)
26
- return nil if klass.nil? || klass.name.nil?
26
+ return [] if klass.nil? || klass.name.nil?
27
27
 
28
- klass.const_source_location(klass.name)&.first
28
+ klass.const_source_location(klass.name)
29
29
  rescue
30
- nil
30
+ []
31
31
  end
32
32
  end
33
33
  end
@@ -18,8 +18,21 @@ module Datadog
18
18
  return super if method.nil?
19
19
 
20
20
  test_suite_name = Helpers.test_suite_name(self, method)
21
-
22
- test_suite = test_visibility_component.start_test_suite(test_suite_name)
21
+ source_file, line_number = Helpers.extract_source_location_from_class(self)
22
+
23
+ test_suite_tags = if source_file
24
+ {
25
+ CI::Ext::Test::TAG_SOURCE_FILE => (Git::LocalRepository.relative_to_root(source_file) if source_file),
26
+ CI::Ext::Test::TAG_SOURCE_START => line_number&.to_s
27
+ }
28
+ else
29
+ {}
30
+ end
31
+
32
+ test_suite = test_visibility_component.start_test_suite(
33
+ test_suite_name,
34
+ tags: test_suite_tags
35
+ )
23
36
 
24
37
  results = super
25
38
  return results unless test_suite
@@ -21,7 +21,13 @@ module Datadog
21
21
  return super unless top_level?
22
22
 
23
23
  suite_name = "#{description} at #{file_path}"
24
- test_suite = test_visibility_component.start_test_suite(suite_name)
24
+ test_suite = test_visibility_component.start_test_suite(
25
+ suite_name,
26
+ tags: {
27
+ CI::Ext::Test::TAG_SOURCE_FILE => Git::LocalRepository.relative_to_root(metadata[:file_path]),
28
+ CI::Ext::Test::TAG_SOURCE_START => metadata[:line_number].to_s
29
+ }
30
+ )
25
31
 
26
32
  success = super
27
33
  return success unless test_suite
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/core"
4
+
5
+ require_relative "../ext"
6
+ require_relative "../../settings"
7
+
8
+ module Datadog
9
+ module CI
10
+ module Contrib
11
+ module Simplecov
12
+ module Configuration
13
+ # Custom settings for the Simplecov integration
14
+ # @public_api
15
+ class Settings < Datadog::CI::Contrib::Settings
16
+ option :enabled do |o|
17
+ o.type :bool
18
+ o.env Ext::ENV_ENABLED
19
+ o.default true
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module CI
5
+ module Contrib
6
+ module Simplecov
7
+ # Simplecov integration constants
8
+ # @public_api
9
+ module Ext
10
+ ENV_ENABLED = "DD_CIVISIBILITY_SIMPLECOV_INSTRUMENTATION_ENABLED"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../integration"
4
+ require_relative "configuration/settings"
5
+ require_relative "patcher"
6
+
7
+ module Datadog
8
+ module CI
9
+ module Contrib
10
+ module Simplecov
11
+ # Description of Simplecov integration
12
+ class Integration
13
+ include Datadog::CI::Contrib::Integration
14
+
15
+ MINIMUM_VERSION = Gem::Version.new("0.18.0")
16
+
17
+ register_as :simplecov
18
+
19
+ def self.version
20
+ Gem.loaded_specs["simplecov"]&.version
21
+ end
22
+
23
+ def self.loaded?
24
+ !defined?(::SimpleCov).nil?
25
+ end
26
+
27
+ def self.compatible?
28
+ super && version >= MINIMUM_VERSION
29
+ end
30
+
31
+ # additional instrumentations for test helpers are auto instrumented on test session start
32
+ def auto_instrument?
33
+ true
34
+ end
35
+
36
+ def new_configuration
37
+ Configuration::Settings.new
38
+ end
39
+
40
+ def patcher
41
+ Patcher
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/tracing/contrib/patcher"
4
+
5
+ require_relative "result_extractor"
6
+
7
+ module Datadog
8
+ module CI
9
+ module Contrib
10
+ module Simplecov
11
+ # Patcher enables patching of 'SimpleCov' module.
12
+ module Patcher
13
+ include Datadog::Tracing::Contrib::Patcher
14
+
15
+ module_function
16
+
17
+ def target_version
18
+ Integration.version
19
+ end
20
+
21
+ def patch
22
+ ::SimpleCov.include(ResultExtractor)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "coverage"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Contrib
8
+ module Simplecov
9
+ module ResultExtractor
10
+ def self.included(base)
11
+ base.singleton_class.prepend(ClassMethods)
12
+ end
13
+
14
+ module ClassMethods
15
+ def __dd_peek_result
16
+ unless datadog_configuration[:enabled]
17
+ Datadog.logger.debug("SimpleCov instrumentation is disabled")
18
+ return nil
19
+ end
20
+
21
+ result = ::SimpleCov::UselessResultsRemover.call(
22
+ ::SimpleCov::ResultAdapter.call(::Coverage.peek_result)
23
+ )
24
+
25
+ ::SimpleCov::Result.new(add_not_loaded_files(result))
26
+ end
27
+
28
+ def datadog_configuration
29
+ Datadog.configuration.ci[:simplecov]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -49,6 +49,11 @@ module Datadog
49
49
  Git::TAG_COMMIT_SHA => @provider.git_commit_sha
50
50
  }
51
51
 
52
+ # set additional tags if provider needs them
53
+ @provider.additional_tags.each do |key, value|
54
+ @tags[key] = value
55
+ end
56
+
52
57
  # Normalize Git references and filter sensitive data
53
58
  normalize_git!
54
59
  # Expand ~
@@ -96,6 +96,10 @@ module Datadog
96
96
  def git_commit_sha
97
97
  end
98
98
 
99
+ def additional_tags
100
+ {}
101
+ end
102
+
99
103
  private
100
104
 
101
105
  def set_branch_and_tag
@@ -75,6 +75,30 @@ module Datadog
75
75
  }.reject { |_, v| v.nil? }.to_json
76
76
  end
77
77
 
78
+ def additional_tags
79
+ base_ref = env["GITHUB_BASE_REF"]
80
+ return {} if base_ref.nil? || base_ref.empty?
81
+
82
+ # @type var result: Hash[String, String]
83
+ result = {
84
+ Git::TAG_PULL_REQUEST_BASE_BRANCH => base_ref
85
+ }
86
+
87
+ event_path = env["GITHUB_EVENT_PATH"]
88
+ event_json = JSON.parse(File.read(event_path))
89
+
90
+ head_sha = event_json.dig("pull_request", "head", "sha")
91
+ result[Git::TAG_COMMIT_HEAD_SHA] = head_sha if head_sha
92
+
93
+ base_sha = event_json.dig("pull_request", "base", "sha")
94
+ result[Git::TAG_PULL_REQUEST_BASE_BRANCH_SHA] = base_sha if base_sha
95
+
96
+ result
97
+ rescue => e
98
+ Datadog.logger.error("Failed to extract additional tags from GitHub Actions: #{e}")
99
+ {}
100
+ end
101
+
78
102
  private
79
103
 
80
104
  def github_server_url
@@ -20,6 +20,11 @@ module Datadog
20
20
  TAG_COMMIT_MESSAGE = "git.commit.message"
21
21
  TAG_COMMIT_SHA = "git.commit.sha"
22
22
 
23
+ # additional tags that we use for github actions jobs with "pull_request" target
24
+ TAG_COMMIT_HEAD_SHA = "git.commit.head_sha"
25
+ TAG_PULL_REQUEST_BASE_BRANCH = "git.pull_request.base_branch"
26
+ TAG_PULL_REQUEST_BASE_BRANCH_SHA = "git.pull_request.base_branch_sha"
27
+
23
28
  ENV_REPOSITORY_URL = "DD_GIT_REPOSITORY_URL"
24
29
  ENV_COMMIT_SHA = "DD_GIT_COMMIT_SHA"
25
30
  ENV_BRANCH = "DD_GIT_BRANCH"
@@ -19,6 +19,7 @@ module Datadog
19
19
  ENV_RETRY_FAILED_TESTS_MAX_ATTEMPTS = "DD_CIVISIBILITY_FLAKY_RETRY_COUNT"
20
20
  ENV_RETRY_FAILED_TESTS_TOTAL_LIMIT = "DD_CIVISIBILITY_TOTAL_FLAKY_RETRY_COUNT"
21
21
  ENV_RETRY_NEW_TESTS_ENABLED = "DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED"
22
+ ENV_TEST_SESSION_NAME = "DD_TEST_SESSION_NAME"
22
23
 
23
24
  # Source: https://docs.datadoghq.com/getting_started/site/
24
25
  DD_SITE_ALLOWLIST = %w[
@@ -64,10 +64,19 @@ module Datadog
64
64
  TAG_EARLY_FLAKE_ENABLED = "test.early_flake.enabled" # true if early flake detection is enabled
65
65
  TAG_EARLY_FLAKE_ABORT_REASON = "test.early_flake.abort_reason" # reason why early flake detection was aborted
66
66
 
67
+ # Tags for total code coverage
68
+ TAG_CODE_COVERAGE_LINES_PCT = "test.code_coverage.lines_pct"
69
+
67
70
  # internal APM tag to mark a span as a test span
68
71
  TAG_SPAN_KIND = "span.kind"
69
72
  SPAN_KIND_TEST = "test"
70
73
 
74
+ # common tags that are serialized directly in msgpack header in metadata field
75
+ METADATA_TAG_TEST_SESSION_NAME = "test_session.name"
76
+
77
+ # internal metric with the number of virtual CPUs
78
+ METRIC_CPU_COUNT = "_dd.host.vcpu_count"
79
+
71
80
  # tags that are common for the whole session and can be inherited from the test session
72
81
  INHERITABLE_TAGS = [TAG_FRAMEWORK, TAG_FRAMEWORK_VERSION].freeze
73
82
 
@@ -114,6 +114,13 @@ module Datadog
114
114
  tracer_span.clear_tag(key)
115
115
  end
116
116
 
117
+ # Gets metric value by key.
118
+ # @param [String] key the key of the metric.
119
+ # @return [Numeric] value the value of the metric.
120
+ def get_metric(key)
121
+ tracer_span.get_metric(key)
122
+ end
123
+
117
124
  # Sets metric value by key.
118
125
  # @param [String] key the key of the metric.
119
126
  # @param [Numeric] value the value of the metric.
@@ -183,6 +190,13 @@ module Datadog
183
190
  tracer_span.get_tag(Ext::Test::TAG_RUNTIME_VERSION)
184
191
  end
185
192
 
193
+ # Source file path where the test or test suite defined (relative to git repository root).
194
+ # @return [String] the source file path of the test
195
+ # @return [nil] if the source file path is not found
196
+ def source_file
197
+ get_tag(Ext::Test::TAG_SOURCE_FILE)
198
+ end
199
+
186
200
  def set_environment_runtime_tags
187
201
  tracer_span.set_tag(Ext::Test::TAG_OS_ARCHITECTURE, ::RbConfig::CONFIG["host_cpu"])
188
202
  tracer_span.set_tag(Ext::Test::TAG_OS_PLATFORM, ::RbConfig::CONFIG["host_os"])
@@ -57,13 +57,6 @@ module Datadog
57
57
  get_tag(Ext::Test::TAG_TEST_SESSION_ID)
58
58
  end
59
59
 
60
- # Source file path of the test relative to git repository root.
61
- # @return [String] the source file path of the test
62
- # @return [nil] if the source file path is not found
63
- def source_file
64
- get_tag(Ext::Test::TAG_SOURCE_FILE)
65
- end
66
-
67
60
  # Returns "true" if the test is skipped by the intelligent test runner.
68
61
  # @return [Boolean] true if the test is skipped by the intelligent test runner, false otherwise.
69
62
  def skipped_by_itr?
@@ -28,6 +28,24 @@ module Datadog
28
28
  get_tag(Ext::Test::TAG_COMMAND)
29
29
  end
30
30
 
31
+ # Return the test session's command used to run the tests
32
+ # @return [String] the command for this test session.
33
+ def test_command
34
+ get_tag(Ext::Test::TAG_COMMAND)
35
+ end
36
+
37
+ # Return the test session's CI provider name (e.g. "travis", "circleci", etc.)
38
+ # @return [String] the provider name for this test session.
39
+ def ci_provider
40
+ get_tag(Ext::Environment::TAG_PROVIDER_NAME)
41
+ end
42
+
43
+ # Return the test session's CI job name (e.g. "build", "test", etc.)
44
+ # @return [String] the job name for this test session.
45
+ def ci_job_name
46
+ get_tag(Ext::Environment::TAG_JOB_NAME)
47
+ end
48
+
31
49
  def skipping_tests?
32
50
  get_tag(Ext::Test::TAG_ITR_TEST_SKIPPING_ENABLED) == "true"
33
51
  end
@@ -4,6 +4,7 @@ require "rbconfig"
4
4
 
5
5
  require_relative "context"
6
6
  require_relative "telemetry"
7
+ require_relative "total_coverage"
7
8
 
8
9
  require_relative "../codeowners/parser"
9
10
  require_relative "../contrib/contrib"
@@ -17,15 +18,17 @@ module Datadog
17
18
  module TestVisibility
18
19
  # Common behavior for CI tests
19
20
  class Component
20
- attr_reader :test_suite_level_visibility_enabled
21
+ attr_reader :test_suite_level_visibility_enabled, :logical_test_session_name
21
22
 
22
23
  def initialize(
23
24
  test_suite_level_visibility_enabled: false,
24
- codeowners: Codeowners::Parser.new(Git::LocalRepository.root).parse
25
+ codeowners: Codeowners::Parser.new(Git::LocalRepository.root).parse,
26
+ logical_test_session_name: nil
25
27
  )
26
28
  @test_suite_level_visibility_enabled = test_suite_level_visibility_enabled
27
29
  @context = Context.new
28
30
  @codeowners = codeowners
31
+ @logical_test_session_name = logical_test_session_name
29
32
  end
30
33
 
31
34
  def start_test_session(service: nil, tags: {}, total_tests_count: 0)
@@ -152,6 +155,9 @@ module Datadog
152
155
  Telemetry.test_session_started(test_session)
153
156
  Telemetry.event_created(test_session)
154
157
 
158
+ # sets logical test session name if none provided by the user
159
+ override_logical_test_session_name!(test_session) if logical_test_session_name.nil?
160
+
155
161
  # signal Remote::Component to configure the library
156
162
  remote.configure(test_session)
157
163
  end
@@ -161,6 +167,8 @@ module Datadog
161
167
  end
162
168
 
163
169
  def on_test_suite_started(test_suite)
170
+ set_codeowners(test_suite)
171
+
164
172
  Telemetry.event_created(test_suite)
165
173
  end
166
174
 
@@ -181,6 +189,8 @@ module Datadog
181
189
  def on_test_session_finished(test_session)
182
190
  test_optimisation.write_test_session_tags(test_session)
183
191
 
192
+ TotalCoverage.extract_lines_pct(test_session)
193
+
184
194
  Telemetry.event_finished(test_session)
185
195
  end
186
196
 
@@ -218,10 +228,10 @@ module Datadog
218
228
  end
219
229
  end
220
230
 
221
- def set_codeowners(test)
222
- source = test.source_file
231
+ def set_codeowners(span)
232
+ source = span.source_file
223
233
  owners = @codeowners.list_owners(source) if source
224
- test.set_tag(Ext::Test::TAG_CODEOWNERS, owners) unless owners.nil?
234
+ span.set_tag(Ext::Test::TAG_CODEOWNERS, owners) unless owners.nil?
225
235
  end
226
236
 
227
237
  def fix_test_suite!(test)
@@ -269,6 +279,14 @@ module Datadog
269
279
  end
270
280
  end
271
281
 
282
+ def override_logical_test_session_name!(test_session)
283
+ @logical_test_session_name = test_session.test_command
284
+ ci_job_name = test_session.ci_job_name
285
+ if ci_job_name
286
+ @logical_test_session_name = "#{ci_job_name}-#{@logical_test_session_name}"
287
+ end
288
+ end
289
+
272
290
  def test_optimisation
273
291
  Datadog.send(:components).test_optimisation
274
292
  end
@@ -11,6 +11,8 @@ require_relative "../ext/app_types"
11
11
  require_relative "../ext/environment"
12
12
  require_relative "../ext/test"
13
13
 
14
+ require_relative "../utils/test_run"
15
+
14
16
  require_relative "../span"
15
17
  require_relative "../test"
16
18
  require_relative "../test_session"
@@ -203,6 +205,8 @@ module Datadog
203
205
 
204
206
  ci_span.set_tags(tags)
205
207
  ci_span.set_tags(@environment_tags)
208
+
209
+ ci_span.set_metric(Ext::Test::METRIC_CPU_COUNT, Utils::TestRun.virtual_cpu_count)
206
210
  end
207
211
 
208
212
  # PROPAGATING CONTEXT FROM TOP-LEVEL TO THE LOWER LEVELS
@@ -53,6 +53,13 @@ module Datadog
53
53
  def remove_test_finished_callback
54
54
  end
55
55
 
56
+ def test_suite_level_visibility_enabled
57
+ false
58
+ end
59
+
60
+ def logical_test_session_name
61
+ end
62
+
56
63
  private
57
64
 
58
65
  def skip_tracing(block = nil)
@@ -34,9 +34,7 @@ module Datadog
34
34
  1,
35
35
  {
36
36
  Ext::Telemetry::TAG_AUTO_INJECTED => "false", # ruby doesn't support auto injection yet
37
- Ext::Telemetry::TAG_PROVIDER =>
38
- test_session.get_tag(Ext::Environment::TAG_PROVIDER_NAME) ||
39
- Ext::Telemetry::Provider::UNSUPPORTED
37
+ Ext::Telemetry::TAG_PROVIDER => test_session.ci_provider || Ext::Telemetry::Provider::UNSUPPORTED
40
38
  }
41
39
  )
42
40
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../ext/test"
4
+
5
+ module Datadog
6
+ module CI
7
+ module TestVisibility
8
+ module TotalCoverage
9
+ def self.extract_lines_pct(test_session)
10
+ unless defined?(::SimpleCov)
11
+ Datadog.logger.debug("SimpleCov is not loaded, skipping code coverage extraction")
12
+ return
13
+ end
14
+
15
+ unless ::SimpleCov.running
16
+ Datadog.logger.debug("SimpleCov is not running, skipping code coverage extraction")
17
+ return
18
+ end
19
+
20
+ unless ::SimpleCov.respond_to?(:__dd_peek_result)
21
+ Datadog.logger.debug("SimpleCov is not patched, skipping code coverage extraction")
22
+ return
23
+ end
24
+
25
+ result = ::SimpleCov.__dd_peek_result
26
+ unless result
27
+ Datadog.logger.debug("SimpleCov result is nil, skipping code coverage extraction")
28
+ return
29
+ end
30
+
31
+ test_session.set_tag(Ext::Test::TAG_CODE_COVERAGE_LINES_PCT, result.covered_percent)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -3,6 +3,7 @@
3
3
  require "datadog/core/environment/identity"
4
4
 
5
5
  require_relative "serializers/factories/test_level"
6
+ require_relative "../ext/app_types"
6
7
  require_relative "../ext/telemetry"
7
8
  require_relative "../ext/transport"
8
9
  require_relative "../transport/event_platform_transport"
@@ -51,7 +52,12 @@ module Datadog
51
52
  end
52
53
 
53
54
  def encode_span(trace, span)
54
- serializer = serializers_factory.serializer(trace, span, options: {itr_correlation_id: itr&.correlation_id})
55
+ serializer = serializers_factory.serializer(
56
+ trace,
57
+ span,
58
+ options: {itr_correlation_id: test_optimisation&.correlation_id}
59
+ )
60
+
55
61
  if serializer.valid?
56
62
  encoded = encoder.encode(serializer)
57
63
  return nil if event_too_large?(span, encoded)
@@ -75,7 +81,7 @@ module Datadog
75
81
  packer.write(1)
76
82
 
77
83
  packer.write("metadata")
78
- packer.write_map_header(1)
84
+ packer.write_map_header(1 + Ext::AppTypes::CI_SPAN_TYPES.size)
79
85
 
80
86
  packer.write("*")
81
87
  metadata_fields_count = dd_env ? 4 : 3
@@ -95,12 +101,24 @@ module Datadog
95
101
  packer.write("library_version")
96
102
  packer.write(Datadog::CI::VERSION::STRING)
97
103
 
104
+ Ext::AppTypes::CI_SPAN_TYPES.each do |ci_span_type|
105
+ packer.write(ci_span_type)
106
+ packer.write_map_header(1)
107
+
108
+ packer.write(Ext::Test::METADATA_TAG_TEST_SESSION_NAME)
109
+ packer.write(test_visibility&.logical_test_session_name)
110
+ end
111
+
98
112
  packer.write("events")
99
113
  end
100
114
 
101
- def itr
115
+ def test_optimisation
102
116
  @test_optimisation ||= Datadog::CI.send(:test_optimisation)
103
117
  end
118
+
119
+ def test_visibility
120
+ @test_visibility ||= Datadog::CI.send(:test_visibility)
121
+ end
104
122
  end
105
123
  end
106
124
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "etc"
4
+
3
5
  module Datadog
4
6
  module CI
5
7
  module Utils
@@ -34,6 +36,12 @@ module Datadog
34
36
  end
35
37
  res
36
38
  end
39
+
40
+ def self.virtual_cpu_count
41
+ return @virtual_cpu_count if defined?(@virtual_cpu_count)
42
+
43
+ @virtual_cpu_count = ::Etc.nprocessors
44
+ end
37
45
  end
38
46
  end
39
47
  end
@@ -4,7 +4,7 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = 1
7
- MINOR = 5
7
+ MINOR = 7
8
8
  PATCH = 0
9
9
  PRE = nil
10
10
  BUILD = nil
data/lib/datadog/ci.rb CHANGED
@@ -410,6 +410,7 @@ require_relative "ci/contrib/cucumber/integration"
410
410
  require_relative "ci/contrib/rspec/integration"
411
411
  require_relative "ci/contrib/minitest/integration"
412
412
  require_relative "ci/contrib/selenium/integration"
413
+ require_relative "ci/contrib/simplecov/integration"
413
414
 
414
415
  # Configuration extensions
415
416
  require_relative "ci/configuration/extensions"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datadog-ci
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Datadog, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-18 00:00:00.000000000 Z
11
+ date: 2024-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: datadog
@@ -103,6 +103,11 @@ files:
103
103
  - lib/datadog/ci/contrib/selenium/patcher.rb
104
104
  - lib/datadog/ci/contrib/selenium/rum.rb
105
105
  - lib/datadog/ci/contrib/settings.rb
106
+ - lib/datadog/ci/contrib/simplecov/configuration/settings.rb
107
+ - lib/datadog/ci/contrib/simplecov/ext.rb
108
+ - lib/datadog/ci/contrib/simplecov/integration.rb
109
+ - lib/datadog/ci/contrib/simplecov/patcher.rb
110
+ - lib/datadog/ci/contrib/simplecov/result_extractor.rb
106
111
  - lib/datadog/ci/ext/app_types.rb
107
112
  - lib/datadog/ci/ext/environment.rb
108
113
  - lib/datadog/ci/ext/environment/extractor.rb
@@ -179,6 +184,7 @@ files:
179
184
  - lib/datadog/ci/test_visibility/store/global.rb
180
185
  - lib/datadog/ci/test_visibility/store/local.rb
181
186
  - lib/datadog/ci/test_visibility/telemetry.rb
187
+ - lib/datadog/ci/test_visibility/total_coverage.rb
182
188
  - lib/datadog/ci/test_visibility/transport.rb
183
189
  - lib/datadog/ci/transport/adapters/net.rb
184
190
  - lib/datadog/ci/transport/adapters/net_http_client.rb