datadog-ci 1.34.0 → 1.36.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -2
- data/lib/datadog/ci/code_coverage/component.rb +26 -2
- data/lib/datadog/ci/configuration/components.rb +2 -1
- data/lib/datadog/ci/configuration/settings.rb +5 -0
- data/lib/datadog/ci/contrib/minitest/helpers.rb +21 -6
- data/lib/datadog/ci/contrib/rspec/anonymous_example_name.rb +515 -0
- data/lib/datadog/ci/contrib/rspec/example.rb +23 -5
- data/lib/datadog/ci/contrib/simplecov/result_extractor.rb +9 -1
- data/lib/datadog/ci/ext/environment/extractor.rb +1 -0
- data/lib/datadog/ci/ext/environment/providers/base.rb +3 -0
- data/lib/datadog/ci/ext/environment/providers/buildkite.rb +4 -0
- data/lib/datadog/ci/ext/environment.rb +1 -0
- data/lib/datadog/ci/ext/settings.rb +1 -0
- data/lib/datadog/ci/ext/telemetry.rb +3 -0
- data/lib/datadog/ci/test.rb +67 -0
- data/lib/datadog/ci/test_discovery/component.rb +4 -0
- data/lib/datadog/ci/test_impact_analysis/component.rb +36 -8
- data/lib/datadog/ci/test_impact_analysis/coverage/event.rb +24 -15
- data/lib/datadog/ci/test_impact_analysis/coverage/files.rb +66 -0
- data/lib/datadog/ci/test_suite.rb +67 -0
- data/lib/datadog/ci/test_tracing/component.rb +8 -0
- data/lib/datadog/ci/test_tracing/deprecated_total_coverage_metric.rb +11 -1
- data/lib/datadog/ci/test_tracing/known_tests.rb +20 -0
- data/lib/datadog/ci/utils/test_name.rb +112 -0
- data/lib/datadog/ci/version.rb +1 -1
- metadata +4 -1
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
|
+
require "datadog/core/utils/time"
|
|
6
|
+
|
|
5
7
|
require_relative "../ext/telemetry"
|
|
6
8
|
require_relative "../ext/transport"
|
|
7
9
|
require_relative "../transport/telemetry"
|
|
@@ -14,6 +16,8 @@ module Datadog
|
|
|
14
16
|
# fetches and stores a list of known tests from the backend
|
|
15
17
|
class KnownTests
|
|
16
18
|
class Response
|
|
19
|
+
attr_reader :http_response
|
|
20
|
+
|
|
17
21
|
def self.from_http_response(http_response)
|
|
18
22
|
new(http_response, nil)
|
|
19
23
|
end
|
|
@@ -94,9 +98,12 @@ module Datadog
|
|
|
94
98
|
return Set.new unless api
|
|
95
99
|
|
|
96
100
|
result = Set.new
|
|
101
|
+
total_request_ms = 0.0
|
|
97
102
|
page_state = nil
|
|
98
103
|
page_number = 1
|
|
99
104
|
|
|
105
|
+
fetch_start_time = Core::Utils::Time.get_time(:float_millisecond)
|
|
106
|
+
|
|
100
107
|
loop do
|
|
101
108
|
Datadog.logger.debug { "Fetching known tests page ##{page_number}#{" with cursor" if page_state}" }
|
|
102
109
|
|
|
@@ -114,6 +121,10 @@ module Datadog
|
|
|
114
121
|
return Set.new
|
|
115
122
|
end
|
|
116
123
|
|
|
124
|
+
# @type var response: Datadog::CI::TestTracing::KnownTests::Response
|
|
125
|
+
http_response = response.http_response
|
|
126
|
+
total_request_ms += http_response.duration_ms if http_response
|
|
127
|
+
|
|
117
128
|
page_tests = response.tests
|
|
118
129
|
result.merge(page_tests)
|
|
119
130
|
Datadog.logger.debug { "Received #{page_tests.size} known tests from page ##{page_number} (total so far: #{result.size})" }
|
|
@@ -127,7 +138,16 @@ module Datadog
|
|
|
127
138
|
page_number += 1
|
|
128
139
|
end
|
|
129
140
|
|
|
141
|
+
fetch_duration_ms = Core::Utils::Time.get_time(:float_millisecond) - fetch_start_time
|
|
142
|
+
# @type var fetch_duration_ms: Float
|
|
143
|
+
|
|
130
144
|
Datadog.logger.debug { "Finished fetching known tests: #{result.size} tests total from #{page_number} page(s)" }
|
|
145
|
+
|
|
146
|
+
# Emit pagination aggregate metrics
|
|
147
|
+
Utils::Telemetry.distribution(Ext::Telemetry::METRIC_KNOWN_TESTS_PAGES_FETCHED, page_number.to_f)
|
|
148
|
+
Utils::Telemetry.distribution(Ext::Telemetry::METRIC_KNOWN_TESTS_TOTAL_FETCH_MS, fetch_duration_ms)
|
|
149
|
+
Utils::Telemetry.distribution(Ext::Telemetry::METRIC_KNOWN_TESTS_TOTAL_REQUEST_MS, total_request_ms)
|
|
150
|
+
|
|
131
151
|
result
|
|
132
152
|
end
|
|
133
153
|
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Datadog
|
|
4
|
+
module CI
|
|
5
|
+
module Utils
|
|
6
|
+
module TestName
|
|
7
|
+
MONTH = "(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"
|
|
8
|
+
WEEKDAY = "(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun)"
|
|
9
|
+
CONSTANT_NAME = "[A-Z]\\w*(?:::[A-Z]\\w*)*"
|
|
10
|
+
|
|
11
|
+
DATE_INSPECT_PATTERN = /#<Date(?::[^>\n]*)?>/.freeze
|
|
12
|
+
TIME_INSPECT_PATTERN = /#<(?:DateTime|Time)(?::[^>\n]*)?>/.freeze
|
|
13
|
+
CLASS_INSPECT_PATTERN = /#<Class:(#{CONSTANT_NAME}|0x[0-9a-fA-F]+)(?:\s[^>\n]*)?>/.freeze
|
|
14
|
+
NAMED_OBJECT_INSPECT_PATTERN = /#<(#{CONSTANT_NAME})(?::[^>\n]*)?>/.freeze
|
|
15
|
+
OBJECT_INSPECT_PATTERN = /#<[^>\n]+>/.freeze
|
|
16
|
+
ACTIVE_RECORD_CLASS_INSPECT_PATTERN = /
|
|
17
|
+
\b(#{CONSTANT_NAME})
|
|
18
|
+
(?:
|
|
19
|
+
\s\(call\s'\1\.connection'\sto\ establish\ a\ connection\)
|
|
20
|
+
|
|
|
21
|
+
\(
|
|
22
|
+
(?:\.\.\.\s*)?[a-z_][a-z0-9_]*:\s[^,)\n]*
|
|
23
|
+
(?:
|
|
24
|
+
,\s(?:\.\.\.\s*)?[a-z_][a-z0-9_]*:\s[^,)\n]*
|
|
25
|
+
)*
|
|
26
|
+
\)
|
|
27
|
+
)
|
|
28
|
+
/x.freeze
|
|
29
|
+
|
|
30
|
+
TIME_PATTERN = /
|
|
31
|
+
\b
|
|
32
|
+
(?:
|
|
33
|
+
\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}(?:\.\d+)?
|
|
34
|
+
(?:\s?(?:Z|UTC|[A-Z]{2,5}|[+-]\d{2}:?\d{2}))?
|
|
35
|
+
|
|
|
36
|
+
#{WEEKDAY},?\s+\d{1,2}\s+#{MONTH}\s+\d{4}\s+\d{2}:\d{2}:\d{2}(?:\.\d+)?
|
|
37
|
+
(?:\s+(?:UTC|[A-Z]{2,5}|[+-]\d{2}:?\d{2}))?
|
|
38
|
+
)
|
|
39
|
+
\b
|
|
40
|
+
/x.freeze
|
|
41
|
+
DATE_PATTERN = /
|
|
42
|
+
\b
|
|
43
|
+
(?:
|
|
44
|
+
\d{4}-\d{2}-\d{2}
|
|
45
|
+
|
|
|
46
|
+
#{WEEKDAY},?\s+\d{1,2}\s+#{MONTH}\s+\d{4}
|
|
47
|
+
)
|
|
48
|
+
\b
|
|
49
|
+
/x.freeze
|
|
50
|
+
RANGE_PATTERN = /
|
|
51
|
+
(^|[^\w.])
|
|
52
|
+
(?:-?\d+(?:\.\d+)?|DATE|TIME|:[a-zA-Z_]\w*|"[^"]*"|'[^']*')
|
|
53
|
+
\s*\.{2,3}\s*
|
|
54
|
+
(?:-?\d+(?:\.\d+)?|DATE|TIME|:[a-zA-Z_]\w*|"[^"]*"|'[^']*')
|
|
55
|
+
(?=$|[^\w.])
|
|
56
|
+
/x.freeze
|
|
57
|
+
|
|
58
|
+
def self.normalize(name)
|
|
59
|
+
return name unless name.is_a?(String)
|
|
60
|
+
return name if name.empty?
|
|
61
|
+
|
|
62
|
+
normalized = name.gsub(DATE_INSPECT_PATTERN, "DATE")
|
|
63
|
+
normalized.gsub!(TIME_INSPECT_PATTERN, "TIME")
|
|
64
|
+
normalized.gsub!(CLASS_INSPECT_PATTERN) do
|
|
65
|
+
class_name = Regexp.last_match(1).to_s
|
|
66
|
+
class_name.start_with?("0x") ? "CLASS" : "CLASS:#{class_name}"
|
|
67
|
+
end
|
|
68
|
+
normalized.gsub!(NAMED_OBJECT_INSPECT_PATTERN) { "OBJECT:#{Regexp.last_match(1)}" }
|
|
69
|
+
normalized.gsub!(OBJECT_INSPECT_PATTERN, "OBJECT")
|
|
70
|
+
normalized.gsub!(ACTIVE_RECORD_CLASS_INSPECT_PATTERN) { Regexp.last_match(1).to_s }
|
|
71
|
+
normalized.gsub!(ARRAY_PATTERN) { |value| array_literal?(value) ? "ARRAY" : value }
|
|
72
|
+
normalized.gsub!(HASH_PATTERN) { |value| hash_literal?(value) ? "HASH" : value }
|
|
73
|
+
normalized.gsub!(TIME_PATTERN, "TIME")
|
|
74
|
+
normalized.gsub!(DATE_PATTERN, "DATE")
|
|
75
|
+
normalized.gsub!(RANGE_PATTERN) { "#{Regexp.last_match(1)}RANGE" }
|
|
76
|
+
|
|
77
|
+
normalized
|
|
78
|
+
rescue => e
|
|
79
|
+
warn_normalization_error(e)
|
|
80
|
+
name
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
ARRAY_PATTERN = /\[[^\[\]\n]{0,300}\]/.freeze
|
|
84
|
+
HASH_PATTERN = /\{[^{}\n]{0,300}\}/.freeze
|
|
85
|
+
|
|
86
|
+
def self.array_literal?(value)
|
|
87
|
+
content = value[1, value.length - 2].to_s.strip
|
|
88
|
+
return true if content.empty?
|
|
89
|
+
|
|
90
|
+
content.include?(",") || content.match?(/\A(?:"|'|:|-?\d|true\b|false\b|nil\b|#<|\[|\{)/)
|
|
91
|
+
end
|
|
92
|
+
private_class_method :array_literal?
|
|
93
|
+
|
|
94
|
+
def self.hash_literal?(value)
|
|
95
|
+
content = value[1, value.length - 2].to_s.strip
|
|
96
|
+
return true if content.empty?
|
|
97
|
+
|
|
98
|
+
content.include?("=>") ||
|
|
99
|
+
content.match?(/(?:\A|,)\s*(?:"[^"]+"|'[^']+'|:[a-zA-Z_]\w*|[a-zA-Z_]\w*)\s*:/)
|
|
100
|
+
end
|
|
101
|
+
private_class_method :hash_literal?
|
|
102
|
+
|
|
103
|
+
def self.warn_normalization_error(error)
|
|
104
|
+
Datadog.logger.warn { "Unable to normalize test name: #{error.class}: #{error.message}" }
|
|
105
|
+
|
|
106
|
+
nil
|
|
107
|
+
end
|
|
108
|
+
private_class_method :warn_normalization_error
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
data/lib/datadog/ci/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: datadog-ci
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.36.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Datadog, Inc.
|
|
@@ -151,6 +151,7 @@ files:
|
|
|
151
151
|
- lib/datadog/ci/contrib/parallel_tests/integration.rb
|
|
152
152
|
- lib/datadog/ci/contrib/parallel_tests/patcher.rb
|
|
153
153
|
- lib/datadog/ci/contrib/patcher.rb
|
|
154
|
+
- lib/datadog/ci/contrib/rspec/anonymous_example_name.rb
|
|
154
155
|
- lib/datadog/ci/contrib/rspec/configuration/settings.rb
|
|
155
156
|
- lib/datadog/ci/contrib/rspec/documentation_formatter.rb
|
|
156
157
|
- lib/datadog/ci/contrib/rspec/example.rb
|
|
@@ -247,6 +248,7 @@ files:
|
|
|
247
248
|
- lib/datadog/ci/test_impact_analysis/component.rb
|
|
248
249
|
- lib/datadog/ci/test_impact_analysis/coverage/ddcov.rb
|
|
249
250
|
- lib/datadog/ci/test_impact_analysis/coverage/event.rb
|
|
251
|
+
- lib/datadog/ci/test_impact_analysis/coverage/files.rb
|
|
250
252
|
- lib/datadog/ci/test_impact_analysis/coverage/transport.rb
|
|
251
253
|
- lib/datadog/ci/test_impact_analysis/null_component.rb
|
|
252
254
|
- lib/datadog/ci/test_impact_analysis/skippable.rb
|
|
@@ -322,6 +324,7 @@ files:
|
|
|
322
324
|
- lib/datadog/ci/utils/runtime_tags_overrides.rb
|
|
323
325
|
- lib/datadog/ci/utils/stateful.rb
|
|
324
326
|
- lib/datadog/ci/utils/telemetry.rb
|
|
327
|
+
- lib/datadog/ci/utils/test_name.rb
|
|
325
328
|
- lib/datadog/ci/utils/test_run.rb
|
|
326
329
|
- lib/datadog/ci/version.rb
|
|
327
330
|
- lib/datadog/ci/worker.rb
|