datadog-ci 1.8.1 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -2
- data/README.md +6 -8
- data/exe/ddcirb +3 -1
- data/lib/datadog/ci/auto_instrument.rb +8 -0
- data/lib/datadog/ci/cli/cli.rb +5 -1
- data/lib/datadog/ci/cli/command/exec.rb +29 -0
- data/lib/datadog/ci/configuration/settings.rb +3 -21
- data/lib/datadog/ci/contrib/ciqueue/integration.rb +34 -0
- data/lib/datadog/ci/contrib/ciqueue/patcher.rb +23 -0
- data/lib/datadog/ci/contrib/cucumber/formatter.rb +10 -5
- data/lib/datadog/ci/contrib/cucumber/integration.rb +5 -14
- data/lib/datadog/ci/contrib/cucumber/patcher.rb +2 -6
- data/lib/datadog/ci/contrib/instrumentation.rb +173 -0
- data/lib/datadog/ci/contrib/integration.rb +101 -117
- data/lib/datadog/ci/contrib/knapsack/extension.rb +27 -0
- data/lib/datadog/ci/contrib/knapsack/integration.rb +36 -0
- data/lib/datadog/ci/contrib/knapsack/patcher.rb +29 -0
- data/lib/datadog/ci/contrib/knapsack/runner.rb +66 -0
- data/lib/datadog/ci/contrib/minitest/integration.rb +6 -14
- data/lib/datadog/ci/contrib/minitest/patcher.rb +1 -5
- data/lib/datadog/ci/contrib/minitest/runner.rb +6 -1
- data/lib/datadog/ci/contrib/minitest/test.rb +6 -1
- data/lib/datadog/ci/contrib/patcher.rb +62 -0
- data/lib/datadog/ci/contrib/rspec/example.rb +64 -25
- data/lib/datadog/ci/contrib/rspec/example_group.rb +18 -1
- data/lib/datadog/ci/contrib/rspec/integration.rb +10 -13
- data/lib/datadog/ci/contrib/rspec/patcher.rb +2 -33
- data/lib/datadog/ci/contrib/rspec/runner.rb +6 -1
- data/lib/datadog/ci/contrib/selenium/capybara_driver.rb +1 -1
- data/lib/datadog/ci/contrib/selenium/driver.rb +1 -1
- data/lib/datadog/ci/contrib/selenium/integration.rb +6 -10
- data/lib/datadog/ci/contrib/selenium/navigation.rb +6 -2
- data/lib/datadog/ci/contrib/selenium/patcher.rb +2 -6
- data/lib/datadog/ci/contrib/selenium/rum.rb +0 -2
- data/lib/datadog/ci/contrib/simplecov/integration.rb +6 -10
- data/lib/datadog/ci/contrib/simplecov/patcher.rb +2 -6
- data/lib/datadog/ci/test.rb +8 -7
- data/lib/datadog/ci/test_optimisation/component.rb +9 -4
- data/lib/datadog/ci/test_retries/strategy/retry_new.rb +1 -1
- data/lib/datadog/ci/test_visibility/component.rb +2 -2
- data/lib/datadog/ci/test_visibility/telemetry.rb +2 -1
- data/lib/datadog/ci/version.rb +2 -2
- data/lib/datadog/ci.rb +9 -1
- metadata +13 -7
- data/lib/datadog/ci/contrib/contrib.rb +0 -31
- data/lib/datadog/ci/contrib/rspec/knapsack_pro/extension.rb +0 -29
- data/lib/datadog/ci/contrib/rspec/knapsack_pro/patcher.rb +0 -26
- data/lib/datadog/ci/contrib/rspec/knapsack_pro/runner.rb +0 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 651794a9813c4b1b10909b0de41e4d25f90b95736815894f83356e03f9fa86d5
|
4
|
+
data.tar.gz: 1f8c32423bb4527c7faf6232acf842fcc6c3db404baf1e836e0d57bbd57a7d93
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c81e9f43de5457aa57aacfbacf2d432c47e0e8f9de68477d45ea9e20da3773687a0d85e79df51e73ce2c133c6e8432c9f8f9a83c35c65d0fe0f587e58968857
|
7
|
+
data.tar.gz: c37907789e0c3f0bbd9cc283d245f8be60d90c0c888bd707db7119b0e36375d3ae10227a7d08d43d448d2af6d42e339ffd4bdfce479028aef1e3b3de1549870b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [1.10.0] - 2024-12-05
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
* Skip before(:all) context hooks when all examples are skipped ([#262][])
|
8
|
+
|
9
|
+
## [1.9.0] - 2024-11-26
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
* Auto instrumentation ([#259][])
|
14
|
+
|
3
15
|
## [1.8.1] - 2024-10-18
|
4
16
|
|
5
17
|
|
@@ -356,7 +368,9 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
356
368
|
|
357
369
|
- Ruby versions < 2.7 no longer supported ([#8][])
|
358
370
|
|
359
|
-
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.
|
371
|
+
[Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v1.10.0...main
|
372
|
+
[1.10.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.9.0...v1.10.0
|
373
|
+
[1.9.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.8.1...v1.9.0
|
360
374
|
[1.8.1]: https://github.com/DataDog/datadog-ci-rb/compare/v1.8.0...v1.8.1
|
361
375
|
[1.8.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.7.0...v1.8.0
|
362
376
|
[1.7.0]: https://github.com/DataDog/datadog-ci-rb/compare/v1.6.0...v1.7.0
|
@@ -513,4 +527,6 @@ Currently test suite level visibility is not used by our instrumentation: it wil
|
|
513
527
|
[#243]: https://github.com/DataDog/datadog-ci-rb/issues/243
|
514
528
|
[#244]: https://github.com/DataDog/datadog-ci-rb/issues/244
|
515
529
|
[#248]: https://github.com/DataDog/datadog-ci-rb/issues/248
|
516
|
-
[#250]: https://github.com/DataDog/datadog-ci-rb/issues/250
|
530
|
+
[#250]: https://github.com/DataDog/datadog-ci-rb/issues/250
|
531
|
+
[#259]: https://github.com/DataDog/datadog-ci-rb/issues/259
|
532
|
+
[#262]: https://github.com/DataDog/datadog-ci-rb/issues/262
|
data/README.md
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
-
# Datadog Test
|
1
|
+
# Datadog Test Optimization for Ruby
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/datadog-ci.svg)](https://badge.fury.io/rb/datadog-ci)
|
4
4
|
[![YARD documentation](https://img.shields.io/badge/YARD-documentation-blue)](https://datadoghq.dev/datadog-ci-rb/)
|
5
|
-
[![codecov](https://codecov.io/gh/DataDog/datadog-ci-rb/branch/main/graph/badge.svg)](https://app.codecov.io/gh/DataDog/datadog-ci-rb/branch/main)
|
6
|
-
[![CircleCI](https://dl.circleci.com/status-badge/img/gh/DataDog/datadog-ci-rb/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/DataDog/datadog-ci-rb/tree/main)
|
7
5
|
|
8
6
|
Datadog's Ruby Library for instrumenting your tests.
|
9
7
|
Learn more on our [official website](https://docs.datadoghq.com/tests/) and check out our [documentation for this library](https://docs.datadoghq.com/tests/setup/ruby/?tab=cloudciprovideragentless).
|
@@ -11,12 +9,12 @@ Learn more on our [official website](https://docs.datadoghq.com/tests/) and chec
|
|
11
9
|
## Features
|
12
10
|
|
13
11
|
- [Test Visibility](https://docs.datadoghq.com/tests/) - collect metrics and results for your tests
|
14
|
-
- [
|
15
|
-
- [
|
16
|
-
- [
|
12
|
+
- [Test impact analysis](https://docs.datadoghq.com/tests/test_impact_analysis/) - save time by selectively running only tests affected by code changes
|
13
|
+
- [Flaky test management](https://docs.datadoghq.com/tests/flaky_test_management/) - track, alert, search your flaky tests in Datadog UI
|
14
|
+
- [Auto test retries](https://docs.datadoghq.com/tests/flaky_test_management/auto_test_retries/?tab=ruby) - retrying failing tests up to N times to avoid failing your build due to flaky tests
|
15
|
+
- [Early flake detection](https://docs.datadoghq.com/tests/flaky_test_management/early_flake_detection/?tab=ruby) - Datadog’s test flakiness solution that identifies flakes early by running newly added tests multiple times
|
17
16
|
- [Search and manage CI tests](https://docs.datadoghq.com/tests/search/)
|
18
17
|
- [Enhance developer workflows](https://docs.datadoghq.com/tests/developer_workflows)
|
19
|
-
- [Flaky test management](https://docs.datadoghq.com/tests/guides/flaky_test_management/)
|
20
18
|
- [Add custom measures to your tests](https://docs.datadoghq.com/tests/guides/add_custom_measures/?tab=ruby)
|
21
19
|
- [Browser tests integration with Datadog RUM](https://docs.datadoghq.com/tests/browser_tests)
|
22
20
|
|
@@ -37,7 +35,7 @@ If you used [test visibility for Ruby](https://docs.datadoghq.com/tests/setup/ru
|
|
37
35
|
## Setup
|
38
36
|
|
39
37
|
- [Test visibility setup](https://docs.datadoghq.com/tests/setup/ruby/?tab=cloudciprovideragentless)
|
40
|
-
- [
|
38
|
+
- [Test impact analysis setup](https://docs.datadoghq.com/tests/test_impact_analysis/setup/ruby/?tab=cloudciprovideragentless) (test visibility setup is required before setting up test impact analysis)
|
41
39
|
|
42
40
|
## Contributing
|
43
41
|
|
data/exe/ddcirb
CHANGED
data/lib/datadog/ci/cli/cli.rb
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
require "datadog"
|
2
2
|
require "datadog/ci"
|
3
3
|
|
4
|
+
require_relative "command/exec"
|
4
5
|
require_relative "command/skippable_tests_percentage"
|
5
6
|
require_relative "command/skippable_tests_percentage_estimate"
|
6
7
|
|
7
8
|
module Datadog
|
8
9
|
module CI
|
9
10
|
module CLI
|
10
|
-
def self.exec(action)
|
11
|
+
def self.exec(action, args = [])
|
11
12
|
case action
|
13
|
+
when "exec"
|
14
|
+
Command::Exec.new(args).exec
|
12
15
|
when "skipped-tests", "skippable-tests"
|
13
16
|
Command::SkippableTestsPercentage.new.exec
|
14
17
|
when "skipped-tests-estimate", "skippable-tests-estimate"
|
@@ -17,6 +20,7 @@ module Datadog
|
|
17
20
|
puts("Usage: bundle exec ddcirb [command] [options]. Available commands:")
|
18
21
|
puts(" skippable-tests - calculates the exact percentage of skipped tests and prints it to stdout or file")
|
19
22
|
puts(" skippable-tests-estimate - estimates the percentage of skipped tests and prints it to stdout or file")
|
23
|
+
puts(" exec YOUR_TEST_COMMAND - automatically instruments your test command with Datadog and executes it")
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
require_relative "../../test_optimisation/skippable_percentage/estimator"
|
3
|
+
|
4
|
+
module Datadog
|
5
|
+
module CI
|
6
|
+
module CLI
|
7
|
+
module Command
|
8
|
+
class Exec < Base
|
9
|
+
def initialize(args)
|
10
|
+
super()
|
11
|
+
|
12
|
+
@args = args
|
13
|
+
end
|
14
|
+
|
15
|
+
def exec
|
16
|
+
rubyopts = [
|
17
|
+
"-rdatadog/ci/auto_instrument"
|
18
|
+
]
|
19
|
+
|
20
|
+
existing_rubyopt = ENV["RUBYOPT"]
|
21
|
+
ENV["RUBYOPT"] = existing_rubyopt ? "#{existing_rubyopt} #{rubyopts.join(" ")}" : rubyopts.join(" ")
|
22
|
+
|
23
|
+
Kernel.exec(*@args)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "../contrib/instrumentation"
|
3
4
|
require_relative "../ext/settings"
|
4
5
|
require_relative "../utils/bundle"
|
5
6
|
|
@@ -8,8 +9,6 @@ module Datadog
|
|
8
9
|
module Configuration
|
9
10
|
# Adds CI behavior to ddtrace settings
|
10
11
|
module Settings
|
11
|
-
InvalidIntegrationError = Class.new(StandardError)
|
12
|
-
|
13
12
|
def self.extended(base)
|
14
13
|
base = base.singleton_class unless base.is_a?(Class)
|
15
14
|
add_settings!(base)
|
@@ -126,23 +125,11 @@ module Datadog
|
|
126
125
|
define_method(:instrument) do |integration_name, options = {}, &block|
|
127
126
|
return unless enabled
|
128
127
|
|
129
|
-
|
130
|
-
integration.configure(options, &block)
|
131
|
-
|
132
|
-
return unless integration.enabled
|
133
|
-
|
134
|
-
patch_results = integration.patch
|
135
|
-
next if patch_results == true
|
136
|
-
|
137
|
-
error_message = <<-ERROR
|
138
|
-
Available?: #{patch_results[:available]}, Loaded?: #{patch_results[:loaded]},
|
139
|
-
Compatible?: #{patch_results[:compatible]}, Patchable?: #{patch_results[:patchable]}"
|
140
|
-
ERROR
|
141
|
-
Datadog.logger.warn("Unable to patch #{integration_name} (#{error_message})")
|
128
|
+
Contrib::Instrumentation.instrument(integration_name, options, &block)
|
142
129
|
end
|
143
130
|
|
144
131
|
define_method(:[]) do |integration_name|
|
145
|
-
fetch_integration(integration_name).configuration
|
132
|
+
Contrib::Instrumentation.fetch_integration(integration_name).configuration
|
146
133
|
end
|
147
134
|
|
148
135
|
option :trace_flush
|
@@ -151,11 +138,6 @@ module Datadog
|
|
151
138
|
o.type :hash
|
152
139
|
o.default({})
|
153
140
|
end
|
154
|
-
|
155
|
-
define_method(:fetch_integration) do |name|
|
156
|
-
Datadog::CI::Contrib::Integration.registry[name] ||
|
157
|
-
raise(InvalidIntegrationError, "'#{name}' is not a valid integration.")
|
158
|
-
end
|
159
141
|
end
|
160
142
|
end
|
161
143
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../integration"
|
4
|
+
require_relative "patcher"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module CI
|
8
|
+
module Contrib
|
9
|
+
module Ciqueue
|
10
|
+
# ci-queue test runner instrumentation
|
11
|
+
# https://github.com/Shopify/ci-queue
|
12
|
+
class Integration < Contrib::Integration
|
13
|
+
MINIMUM_VERSION = Gem::Version.new("0.9.0")
|
14
|
+
|
15
|
+
def version
|
16
|
+
Gem.loaded_specs["ci-queue"]&.version
|
17
|
+
end
|
18
|
+
|
19
|
+
def loaded?
|
20
|
+
!defined?(::RSpec::Queue::Runner).nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def compatible?
|
24
|
+
super && version >= MINIMUM_VERSION
|
25
|
+
end
|
26
|
+
|
27
|
+
def patcher
|
28
|
+
Patcher
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../patcher"
|
4
|
+
require_relative "../rspec/runner"
|
5
|
+
|
6
|
+
module Datadog
|
7
|
+
module CI
|
8
|
+
module Contrib
|
9
|
+
module Ciqueue
|
10
|
+
# Patcher enables patching of 'rspec' module.
|
11
|
+
module Patcher
|
12
|
+
include Datadog::CI::Contrib::Patcher
|
13
|
+
|
14
|
+
module_function
|
15
|
+
|
16
|
+
def patch
|
17
|
+
::RSpec::Queue::Runner.include(Contrib::RSpec::Runner)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require_relative "../../ext/test"
|
4
4
|
require_relative "../../git/local_repository"
|
5
5
|
require_relative "../../utils/test_run"
|
6
|
+
require_relative "../instrumentation"
|
6
7
|
require_relative "ext"
|
7
8
|
|
8
9
|
module Datadog
|
@@ -38,9 +39,9 @@ module Datadog
|
|
38
39
|
test_visibility_component.start_test_session(
|
39
40
|
tags: {
|
40
41
|
CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
|
41
|
-
CI::Ext::Test::TAG_FRAMEWORK_VERSION =>
|
42
|
+
CI::Ext::Test::TAG_FRAMEWORK_VERSION => datadog_integration.version.to_s
|
42
43
|
},
|
43
|
-
service:
|
44
|
+
service: datadog_configuration[:service_name]
|
44
45
|
)
|
45
46
|
test_visibility_component.start_test_module(Ext::FRAMEWORK)
|
46
47
|
end
|
@@ -61,7 +62,7 @@ module Datadog
|
|
61
62
|
# @type var tags: Hash[String, String]
|
62
63
|
tags = {
|
63
64
|
CI::Ext::Test::TAG_FRAMEWORK => Ext::FRAMEWORK,
|
64
|
-
CI::Ext::Test::TAG_FRAMEWORK_VERSION =>
|
65
|
+
CI::Ext::Test::TAG_FRAMEWORK_VERSION => datadog_integration.version.to_s,
|
65
66
|
CI::Ext::Test::TAG_SOURCE_FILE => Git::LocalRepository.relative_to_root(event.test_case.location.file),
|
66
67
|
CI::Ext::Test::TAG_SOURCE_START => event.test_case.location.line.to_s
|
67
68
|
}
|
@@ -81,7 +82,7 @@ module Datadog
|
|
81
82
|
event.test_case.name,
|
82
83
|
test_suite_name,
|
83
84
|
tags: tags,
|
84
|
-
service:
|
85
|
+
service: datadog_configuration[:service_name]
|
85
86
|
)
|
86
87
|
if event.test_case.match_tags?("@#{CI::Ext::Test::ITR_UNSKIPPABLE_OPTION}")
|
87
88
|
test_span&.itr_unskippable!
|
@@ -199,7 +200,11 @@ module Datadog
|
|
199
200
|
end
|
200
201
|
end
|
201
202
|
|
202
|
-
def
|
203
|
+
def datadog_integration
|
204
|
+
CI::Contrib::Instrumentation.fetch_integration(:cucumber)
|
205
|
+
end
|
206
|
+
|
207
|
+
def datadog_configuration
|
203
208
|
Datadog.configuration.ci[:cucumber]
|
204
209
|
end
|
205
210
|
|
@@ -9,30 +9,21 @@ module Datadog
|
|
9
9
|
module Contrib
|
10
10
|
module Cucumber
|
11
11
|
# Description of Cucumber integration
|
12
|
-
class Integration
|
13
|
-
include Datadog::CI::Contrib::Integration
|
14
|
-
|
12
|
+
class Integration < Contrib::Integration
|
15
13
|
MINIMUM_VERSION = Gem::Version.new("3.0.0")
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
def self.version
|
15
|
+
def version
|
20
16
|
Gem.loaded_specs["cucumber"]&.version
|
21
17
|
end
|
22
18
|
|
23
|
-
def
|
24
|
-
!defined?(::Cucumber).nil? && !defined?(::Cucumber::Runtime).nil?
|
19
|
+
def loaded?
|
20
|
+
!defined?(::Cucumber).nil? && !defined?(::Cucumber::Runtime).nil? && !defined?(::Cucumber::Configuration).nil?
|
25
21
|
end
|
26
22
|
|
27
|
-
def
|
23
|
+
def compatible?
|
28
24
|
super && version >= MINIMUM_VERSION
|
29
25
|
end
|
30
26
|
|
31
|
-
# test environments should not auto instrument test libraries
|
32
|
-
def auto_instrument?
|
33
|
-
false
|
34
|
-
end
|
35
|
-
|
36
27
|
def new_configuration
|
37
28
|
Configuration::Settings.new
|
38
29
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative "../patcher"
|
4
4
|
|
5
5
|
require_relative "instrumentation"
|
6
6
|
|
@@ -10,14 +10,10 @@ module Datadog
|
|
10
10
|
module Cucumber
|
11
11
|
# Patches 'cucumber' gem.
|
12
12
|
module Patcher
|
13
|
-
include Datadog::
|
13
|
+
include Datadog::CI::Contrib::Patcher
|
14
14
|
|
15
15
|
module_function
|
16
16
|
|
17
|
-
def target_version
|
18
|
-
Integration.version
|
19
|
-
end
|
20
|
-
|
21
17
|
def patch
|
22
18
|
::Cucumber::Runtime.include(Instrumentation)
|
23
19
|
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "datadog/core/utils/only_once"
|
4
|
+
|
5
|
+
module Datadog
|
6
|
+
module CI
|
7
|
+
module Contrib
|
8
|
+
module Instrumentation
|
9
|
+
class InvalidIntegrationError < StandardError; end
|
10
|
+
|
11
|
+
@registry = {}
|
12
|
+
@auto_instrumented = false
|
13
|
+
|
14
|
+
def self.registry
|
15
|
+
@registry
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.register_integration(integration_class)
|
19
|
+
@registry[integration_name(integration_class)] = integration_class.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.auto_instrumented?
|
23
|
+
@auto_instrumented
|
24
|
+
end
|
25
|
+
|
26
|
+
# Auto instrumentation of all integrations.
|
27
|
+
#
|
28
|
+
# Registers a :script_compiled tracepoint to watch for new Ruby files being loaded.
|
29
|
+
# On every file load it checks if any of the integrations are patchable now.
|
30
|
+
# Only the integrations that are available in the environment are checked.
|
31
|
+
def self.auto_instrument
|
32
|
+
Datadog.logger.debug("Auto instrumenting all integrations...")
|
33
|
+
@auto_instrumented = true
|
34
|
+
|
35
|
+
auto_instrumented_integrations = fetch_auto_instrumented_integrations
|
36
|
+
if auto_instrumented_integrations.empty?
|
37
|
+
Datadog.logger.warn(
|
38
|
+
"Auto instrumentation was requested, but no available integrations were found. " \
|
39
|
+
"Tests will be run without Datadog instrumentation."
|
40
|
+
)
|
41
|
+
return
|
42
|
+
end
|
43
|
+
|
44
|
+
# note that `Kernel.require` might be called from a different thread, so
|
45
|
+
# there is a possibility of concurrent execution of this tracepoint
|
46
|
+
mutex = Mutex.new
|
47
|
+
script_compiled_tracepoint = TracePoint.new(:script_compiled) do |tp|
|
48
|
+
all_patched = true
|
49
|
+
|
50
|
+
mutex.synchronize do
|
51
|
+
auto_instrumented_integrations.each do |integration|
|
52
|
+
next if integration.patched?
|
53
|
+
|
54
|
+
all_patched = false
|
55
|
+
next unless integration.loaded?
|
56
|
+
|
57
|
+
auto_configure_datadog
|
58
|
+
|
59
|
+
Datadog.logger.debug("#{integration.class} is loaded")
|
60
|
+
patch_integration(integration)
|
61
|
+
end
|
62
|
+
|
63
|
+
if all_patched
|
64
|
+
Datadog.logger.debug("All expected integrations are patched, disabling the script_compiled tracepoint")
|
65
|
+
|
66
|
+
tp.disable
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
script_compiled_tracepoint.enable
|
71
|
+
end
|
72
|
+
|
73
|
+
# Manual instrumentation of a specific integration.
|
74
|
+
#
|
75
|
+
# This method is called when user has `c.ci.instrument :integration_name` in their code.
|
76
|
+
def self.instrument(integration_name, options = {}, &block)
|
77
|
+
integration = fetch_integration(integration_name)
|
78
|
+
# when manually instrumented, it might be configured via code
|
79
|
+
integration.configure(options, &block)
|
80
|
+
|
81
|
+
return unless integration.enabled
|
82
|
+
|
83
|
+
patch_integration(integration, with_dependencies: true)
|
84
|
+
end
|
85
|
+
|
86
|
+
# This method instruments all additional test libraries (ex: selenium-webdriver) that need to be instrumented
|
87
|
+
# later in the test suite run.
|
88
|
+
#
|
89
|
+
# It is intended to be called when test session starts to add additional capabilities to test visibility.
|
90
|
+
#
|
91
|
+
# This method does not automatically instrument test frameworks (ex: RSpec, Cucumber, etc), it requires
|
92
|
+
# test framework to be already instrumented.
|
93
|
+
def self.instrument_on_session_start
|
94
|
+
Datadog.logger.debug("Instrumenting all late instrumented integrations...")
|
95
|
+
|
96
|
+
@registry.each do |name, integration|
|
97
|
+
next unless integration.late_instrument?
|
98
|
+
next unless integration.enabled
|
99
|
+
|
100
|
+
Datadog.logger.debug "#{name} is allowed to be late instrumented"
|
101
|
+
|
102
|
+
patch_integration(integration)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.fetch_integration(name)
|
107
|
+
@registry[name] ||
|
108
|
+
raise(InvalidIntegrationError, "'#{name}' is not a valid integration.")
|
109
|
+
end
|
110
|
+
|
111
|
+
# take the parent module name and downcase it
|
112
|
+
# for example for Datadog::CI::Contrib::RSpec::Integration it will be :rspec
|
113
|
+
def self.integration_name(subclass)
|
114
|
+
result = subclass.name&.split("::")&.[](-2)&.downcase&.to_sym
|
115
|
+
raise "Integration name could not be derived for #{subclass}" if result.nil?
|
116
|
+
result
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.patch_integration(integration, with_dependencies: false)
|
120
|
+
patch_results = integration.patch
|
121
|
+
|
122
|
+
if patch_results[:ok]
|
123
|
+
Datadog.logger.debug("#{integration.class} is patched")
|
124
|
+
|
125
|
+
return unless with_dependencies
|
126
|
+
|
127
|
+
# try to patch dependant integrations (for example knapsack that depends on rspec)
|
128
|
+
dependants = integration.dependants
|
129
|
+
.map { |name| fetch_integration(name) }
|
130
|
+
.filter { |integration| integration.patchable? }
|
131
|
+
|
132
|
+
Datadog.logger.debug("Found dependent integrations for #{integration.class}: #{dependants}")
|
133
|
+
|
134
|
+
dependants.each do |dependent_integration|
|
135
|
+
patch_integration(dependent_integration, with_dependencies: true)
|
136
|
+
end
|
137
|
+
|
138
|
+
else
|
139
|
+
Datadog.logger.debug("Attention: #{integration.class} is not patched (#{patch_results})")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.fetch_auto_instrumented_integrations
|
144
|
+
@registry.filter_map do |name, integration|
|
145
|
+
# ignore integrations that are not in the Gemfile or have incompatible versions
|
146
|
+
next unless integration.compatible?
|
147
|
+
|
148
|
+
# late instrumented integrations will be patched when the test session starts
|
149
|
+
next if integration.late_instrument?
|
150
|
+
|
151
|
+
Datadog.logger.debug("#{name} should be auto instrumented")
|
152
|
+
integration
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.auto_configure_datadog
|
157
|
+
configure_once.run do
|
158
|
+
Datadog.logger.debug("Applying Datadog configuration in CI mode...")
|
159
|
+
Datadog.configure do |c|
|
160
|
+
c.ci.enabled = true
|
161
|
+
c.tracing.enabled = true
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# This is not thread safe, it is synchronized by the caller in the tracepoint
|
167
|
+
def self.configure_once
|
168
|
+
@configure_once ||= Datadog::Core::Utils::OnlyOnce.new
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|