datadog-ci 1.0.1 → 1.2.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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -2
  3. data/ext/datadog_cov/datadog_cov.c +259 -67
  4. data/lib/datadog/ci/configuration/components.rb +121 -79
  5. data/lib/datadog/ci/configuration/settings.rb +6 -0
  6. data/lib/datadog/ci/contrib/rspec/example.rb +1 -1
  7. data/lib/datadog/ci/contrib/rspec/patcher.rb +3 -3
  8. data/lib/datadog/ci/ext/settings.rb +1 -0
  9. data/lib/datadog/ci/span.rb +3 -3
  10. data/lib/datadog/ci/test.rb +1 -1
  11. data/lib/datadog/ci/test_module.rb +1 -1
  12. data/lib/datadog/ci/{itr/runner.rb → test_optimisation/component.rb} +13 -10
  13. data/lib/datadog/ci/{itr → test_optimisation}/coverage/ddcov.rb +1 -1
  14. data/lib/datadog/ci/{itr → test_optimisation}/coverage/event.rb +1 -1
  15. data/lib/datadog/ci/{itr → test_optimisation}/coverage/transport.rb +1 -1
  16. data/lib/datadog/ci/{itr → test_optimisation}/coverage/writer.rb +1 -1
  17. data/lib/datadog/ci/{itr → test_optimisation}/skippable.rb +1 -1
  18. data/lib/datadog/ci/test_session.rb +1 -1
  19. data/lib/datadog/ci/test_suite.rb +1 -1
  20. data/lib/datadog/ci/test_visibility/{recorder.rb → component.rb} +10 -10
  21. data/lib/datadog/ci/test_visibility/{null_recorder.rb → null_component.rb} +6 -4
  22. data/lib/datadog/ci/test_visibility/transport.rb +1 -1
  23. data/lib/datadog/ci/transport/adapters/net.rb +138 -0
  24. data/lib/datadog/ci/transport/api/agentless.rb +2 -2
  25. data/lib/datadog/ci/transport/api/evp_proxy.rb +1 -1
  26. data/lib/datadog/ci/transport/http.rb +7 -57
  27. data/lib/datadog/ci/version.rb +2 -2
  28. data/lib/datadog/ci.rb +15 -15
  29. metadata +12 -11
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/core/transport/response"
4
+ require "datadog/core/transport/ext"
5
+
6
+ require_relative "../gzip"
7
+ require_relative "../../ext/transport"
8
+
9
+ module Datadog
10
+ module CI
11
+ module Transport
12
+ module Adapters
13
+ # Adapter for Net::HTTP
14
+ class Net
15
+ attr_reader \
16
+ :hostname,
17
+ :port,
18
+ :timeout,
19
+ :ssl
20
+
21
+ def initialize(hostname:, port:, ssl:, timeout_seconds:)
22
+ @hostname = hostname
23
+ @port = port
24
+ @timeout = timeout_seconds
25
+ @ssl = ssl
26
+ end
27
+
28
+ def open(&block)
29
+ req = net_http_client.new(hostname, port)
30
+
31
+ req.use_ssl = ssl
32
+ req.open_timeout = req.read_timeout = timeout
33
+
34
+ req.start(&block)
35
+ end
36
+
37
+ def call(path:, payload:, headers:, verb:)
38
+ headers ||= {}
39
+ # skip tracing for internal DD requests
40
+ headers[Core::Transport::Ext::HTTP::HEADER_DD_INTERNAL_UNTRACED_REQUEST] = "1"
41
+
42
+ if respond_to?(verb)
43
+ send(verb, path: path, payload: payload, headers: headers)
44
+ else
45
+ raise "Unknown HTTP method [#{verb}]"
46
+ end
47
+ end
48
+
49
+ def post(path:, payload:, headers:)
50
+ post = ::Net::HTTP::Post.new(path, headers)
51
+ post.body = payload
52
+
53
+ # Connect and send the request
54
+ http_response = open do |http|
55
+ http.request(post)
56
+ end
57
+
58
+ # Build and return response
59
+ Response.new(http_response)
60
+ end
61
+
62
+ class Response
63
+ include Datadog::Core::Transport::Response
64
+
65
+ attr_reader :http_response
66
+
67
+ def initialize(http_response)
68
+ @http_response = http_response
69
+ end
70
+
71
+ def payload
72
+ return @decompressed_payload if defined?(@decompressed_payload)
73
+ return http_response.body unless gzipped_content?
74
+ return http_response.body unless gzipped_body?(http_response.body)
75
+
76
+ Datadog.logger.debug("Decompressing gzipped response payload")
77
+ @decompressed_payload = Gzip.decompress(http_response.body)
78
+ end
79
+
80
+ def header(name)
81
+ http_response[name]
82
+ end
83
+
84
+ def code
85
+ http_response.code.to_i
86
+ end
87
+
88
+ def ok?
89
+ code.between?(200, 299)
90
+ end
91
+
92
+ def unsupported?
93
+ code == 415
94
+ end
95
+
96
+ def not_found?
97
+ code == 404
98
+ end
99
+
100
+ def client_error?
101
+ code.between?(400, 499)
102
+ end
103
+
104
+ def server_error?
105
+ code.between?(500, 599)
106
+ end
107
+
108
+ def gzipped_content?
109
+ header(Ext::Transport::HEADER_CONTENT_ENCODING) == Ext::Transport::CONTENT_ENCODING_GZIP
110
+ end
111
+
112
+ def gzipped_body?(body)
113
+ return false if body.nil? || body.empty?
114
+
115
+ # no-dd-sa
116
+ first_bytes = body[0, 2]
117
+ return false if first_bytes.nil? || first_bytes.empty?
118
+
119
+ first_bytes.b == Ext::Transport::GZIP_MAGIC_NUMBER
120
+ end
121
+
122
+ def inspect
123
+ "#{super}, http_response:#{http_response}"
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ def net_http_client
130
+ return ::Net::HTTP unless defined?(WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP)
131
+
132
+ WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -37,7 +37,7 @@ module Datadog
37
37
  end
38
38
 
39
39
  def citestcov_request(path:, payload:, headers: {}, verb: "post")
40
- super(path: path, payload: payload, headers: headers, verb: verb)
40
+ super
41
41
 
42
42
  perform_request(@citestcov_http, path: path, payload: @citestcov_payload, headers: headers, verb: verb)
43
43
  end
@@ -60,7 +60,7 @@ module Datadog
60
60
 
61
61
  Datadog::CI::Transport::HTTP.new(
62
62
  host: uri.host,
63
- port: uri.port,
63
+ port: uri.port || 80,
64
64
  ssl: uri.scheme == "https" || uri.port == 443,
65
65
  compress: compress
66
66
  )
@@ -39,7 +39,7 @@ module Datadog
39
39
  end
40
40
 
41
41
  def citestcov_request(path:, payload:, headers: {}, verb: "post")
42
- super(path: path, payload: payload, headers: headers, verb: verb)
42
+ super
43
43
 
44
44
  headers[Ext::Transport::HEADER_EVP_SUBDOMAIN] = Ext::Transport::TEST_COVERAGE_INTAKE_HOST_PREFIX
45
45
 
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "delegate"
4
- require "datadog/core/transport/http/adapters/net"
5
- require "datadog/core/transport/http/env"
6
- require "datadog/core/transport/request"
7
4
  require "socket"
8
5
 
9
6
  require_relative "gzip"
7
+ require_relative "adapters/net"
10
8
  require_relative "../ext/transport"
11
9
 
12
10
  module Datadog
@@ -24,7 +22,7 @@ module Datadog
24
22
  MAX_RETRIES = 3
25
23
  INITIAL_BACKOFF = 1
26
24
 
27
- def initialize(host:, timeout: DEFAULT_TIMEOUT, port: nil, ssl: true, compress: false)
25
+ def initialize(host:, port:, timeout: DEFAULT_TIMEOUT, ssl: true, compress: false)
28
26
  @host = host
29
27
  @port = port
30
28
  @timeout = timeout
@@ -70,7 +68,7 @@ module Datadog
70
68
 
71
69
  def perform_http_call(path:, payload:, headers:, verb:, retries: MAX_RETRIES, backoff: INITIAL_BACKOFF)
72
70
  adapter.call(
73
- build_env(path: path, payload: payload, headers: headers, verb: verb)
71
+ path: path, payload: payload, headers: headers, verb: verb
74
72
  )
75
73
  rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, SocketError, Net::HTTPBadResponse => e
76
74
  Datadog.logger.debug("Failed to send request with #{e} (#{e.message})")
@@ -87,65 +85,17 @@ module Datadog
87
85
  end
88
86
  end
89
87
 
90
- def build_env(path:, payload:, headers:, verb:)
91
- env = Datadog::Core::Transport::HTTP::Env.new(
92
- Datadog::Core::Transport::Request.new
93
- )
94
- env.body = payload
95
- env.path = path
96
- env.headers = headers
97
- env.verb = verb
98
- env
99
- end
100
-
101
88
  def adapter
102
- settings = AdapterSettings.new(hostname: host, port: port, ssl: ssl, timeout_seconds: timeout)
103
- @adapter ||= Datadog::Core::Transport::HTTP::Adapters::Net.new(settings)
89
+ @adapter ||= Datadog::CI::Transport::Adapters::Net.new(
90
+ hostname: host, port: port, ssl: ssl, timeout_seconds: timeout
91
+ )
104
92
  end
105
93
 
106
- # adds compatibility with Datadog::Tracing transport and
107
- # provides ungzipping capabilities
94
+ # adds compatibility with Datadog::Tracing transport
108
95
  class ResponseDecorator < ::SimpleDelegator
109
- def payload
110
- return @decompressed_payload if defined?(@decompressed_payload)
111
-
112
- if gzipped?(__getobj__.payload)
113
- Datadog.logger.debug("Decompressing gzipped response payload")
114
- @decompressed_payload = Gzip.decompress(__getobj__.payload)
115
- else
116
- __getobj__.payload
117
- end
118
- end
119
-
120
96
  def trace_count
121
97
  0
122
98
  end
123
-
124
- def gzipped?(payload)
125
- return false if payload.nil? || payload.empty?
126
-
127
- # no-dd-sa
128
- first_bytes = payload[0, 2]
129
- return false if first_bytes.nil? || first_bytes.empty?
130
-
131
- first_bytes.b == Datadog::CI::Ext::Transport::GZIP_MAGIC_NUMBER
132
- end
133
- end
134
-
135
- class AdapterSettings
136
- attr_reader :hostname, :port, :ssl, :timeout_seconds
137
-
138
- def initialize(hostname:, port: nil, ssl: true, timeout_seconds: nil)
139
- @hostname = hostname
140
- @port = port
141
- @ssl = ssl
142
- @timeout_seconds = timeout_seconds
143
- end
144
-
145
- def ==(other)
146
- hostname == other.hostname && port == other.port && ssl == other.ssl &&
147
- timeout_seconds == other.timeout_seconds
148
- end
149
99
  end
150
100
  end
151
101
  end
@@ -4,8 +4,8 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = 1
7
- MINOR = 0
8
- PATCH = 1
7
+ MINOR = 2
8
+ PATCH = 0
9
9
  PRE = nil
10
10
  BUILD = nil
11
11
  # PRE and BUILD above are modified for dev gems during gem build GHA workflow
data/lib/datadog/ci.rb CHANGED
@@ -39,7 +39,7 @@ module Datadog
39
39
  # @return [Datadog::CI::TestSession] the active, running {Datadog::CI::TestSession}.
40
40
  # @return [nil] if test suite level visibility is disabled or CI mode is disabled.
41
41
  def start_test_session(service: Utils::Configuration.fetch_service_name("test"), tags: {})
42
- recorder.start_test_session(service: service, tags: tags)
42
+ test_visibility.start_test_session(service: service, tags: tags)
43
43
  end
44
44
 
45
45
  # The active, unfinished test session.
@@ -61,7 +61,7 @@ module Datadog
61
61
  # @return [Datadog::CI::TestSession] the active test session
62
62
  # @return [nil] if no test session is active
63
63
  def active_test_session
64
- recorder.active_test_session
64
+ test_visibility.active_test_session
65
65
  end
66
66
 
67
67
  # Starts a {Datadog::CI::TestModule ci_test_module} that represents a single test module (for most Ruby test frameworks
@@ -93,7 +93,7 @@ module Datadog
93
93
  # @return [Datadog::CI::TestModule] the active, running {Datadog::CI::TestModule}.
94
94
  # @return [nil] if test suite level visibility is disabled or CI mode is disabled.
95
95
  def start_test_module(test_module_name, service: nil, tags: {})
96
- recorder.start_test_module(test_module_name, service: service, tags: tags)
96
+ test_visibility.start_test_module(test_module_name, service: service, tags: tags)
97
97
  end
98
98
 
99
99
  # The active, unfinished test module.
@@ -116,7 +116,7 @@ module Datadog
116
116
  # @return [Datadog::CI::TestModule] the active test module
117
117
  # @return [nil] if no test module is active
118
118
  def active_test_module
119
- recorder.active_test_module
119
+ test_visibility.active_test_module
120
120
  end
121
121
 
122
122
  # Starts a {Datadog::CI::TestSuite ci_test_suite} that represents a single test suite.
@@ -145,7 +145,7 @@ module Datadog
145
145
  # @return [Datadog::CI::TestSuite] the active, running {Datadog::CI::TestSuite}.
146
146
  # @return [nil] if test suite level visibility is disabled or CI mode is disabled.
147
147
  def start_test_suite(test_suite_name, service: nil, tags: {})
148
- recorder.start_test_suite(test_suite_name, service: service, tags: tags)
148
+ test_visibility.start_test_suite(test_suite_name, service: service, tags: tags)
149
149
  end
150
150
 
151
151
  # The active, unfinished test suite.
@@ -168,7 +168,7 @@ module Datadog
168
168
  # @return [Datadog::CI::TestSuite] the active test suite
169
169
  # @return [nil] if no test suite with given name is active
170
170
  def active_test_suite(test_suite_name)
171
- recorder.active_test_suite(test_suite_name)
171
+ test_visibility.active_test_suite(test_suite_name)
172
172
  end
173
173
 
174
174
  # Return a {Datadog::CI::Test ci_test} that will trace a test called `test_name`.
@@ -222,7 +222,7 @@ module Datadog
222
222
  # @yieldparam [Datadog::CI::Test] ci_test the newly created and active [Datadog::CI::Test]
223
223
  # @yieldparam [nil] if CI mode is disabled
224
224
  def trace_test(test_name, test_suite_name, service: nil, tags: {}, &block)
225
- recorder.trace_test(test_name, test_suite_name, service: service, tags: tags, &block)
225
+ test_visibility.trace_test(test_name, test_suite_name, service: service, tags: tags, &block)
226
226
  end
227
227
 
228
228
  # Same as {.trace_test} but it does not accept a block.
@@ -248,7 +248,7 @@ module Datadog
248
248
  # @return [Datadog::CI::Test] the active, unfinished {Datadog::CI::Test}.
249
249
  # @return [nil] if CI mode is disabled.
250
250
  def start_test(test_name, test_suite_name, service: nil, tags: {})
251
- recorder.trace_test(test_name, test_suite_name, service: service, tags: tags)
251
+ test_visibility.trace_test(test_name, test_suite_name, service: service, tags: tags)
252
252
  end
253
253
 
254
254
  # Trace any custom span inside a test. For example, you could trace:
@@ -300,7 +300,7 @@ module Datadog
300
300
  )
301
301
  end
302
302
 
303
- recorder.trace(span_name, type: type, tags: tags, &block)
303
+ test_visibility.trace(span_name, type: type, tags: tags, &block)
304
304
  end
305
305
 
306
306
  # The active, unfinished custom (i.e. not test/suite/module/session) span.
@@ -326,7 +326,7 @@ module Datadog
326
326
  # @return [Datadog::CI::Span] the active span
327
327
  # @return [nil] if no span is active, or if the active span is not a custom span
328
328
  def active_span
329
- span = recorder.active_span
329
+ span = test_visibility.active_span
330
330
  span if span && !Ext::AppTypes::CI_SPAN_TYPES.include?(span.type)
331
331
  end
332
332
 
@@ -352,7 +352,7 @@ module Datadog
352
352
  # @return [Datadog::CI::Test] the active test
353
353
  # @return [nil] if no test is active
354
354
  def active_test
355
- recorder.active_test
355
+ test_visibility.active_test
356
356
  end
357
357
 
358
358
  private
@@ -361,12 +361,12 @@ module Datadog
361
361
  Datadog.send(:components)
362
362
  end
363
363
 
364
- def recorder
365
- components.ci_recorder
364
+ def test_visibility
365
+ components.test_visibility
366
366
  end
367
367
 
368
- def itr_runner
369
- components.itr
368
+ def test_optimisation
369
+ components.test_optimisation
370
370
  end
371
371
  end
372
372
  end
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.0.1
4
+ version: 1.2.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-06-11 00:00:00.000000000 Z
11
+ date: 2024-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: datadog
@@ -134,22 +134,22 @@ files:
134
134
  - lib/datadog/ci/git/tree_uploader.rb
135
135
  - lib/datadog/ci/git/upload_packfile.rb
136
136
  - lib/datadog/ci/git/user.rb
137
- - lib/datadog/ci/itr/coverage/ddcov.rb
138
- - lib/datadog/ci/itr/coverage/event.rb
139
- - lib/datadog/ci/itr/coverage/transport.rb
140
- - lib/datadog/ci/itr/coverage/writer.rb
141
- - lib/datadog/ci/itr/runner.rb
142
- - lib/datadog/ci/itr/skippable.rb
143
137
  - lib/datadog/ci/span.rb
144
138
  - lib/datadog/ci/test.rb
145
139
  - lib/datadog/ci/test_module.rb
140
+ - lib/datadog/ci/test_optimisation/component.rb
141
+ - lib/datadog/ci/test_optimisation/coverage/ddcov.rb
142
+ - lib/datadog/ci/test_optimisation/coverage/event.rb
143
+ - lib/datadog/ci/test_optimisation/coverage/transport.rb
144
+ - lib/datadog/ci/test_optimisation/coverage/writer.rb
145
+ - lib/datadog/ci/test_optimisation/skippable.rb
146
146
  - lib/datadog/ci/test_session.rb
147
147
  - lib/datadog/ci/test_suite.rb
148
+ - lib/datadog/ci/test_visibility/component.rb
148
149
  - lib/datadog/ci/test_visibility/context/global.rb
149
150
  - lib/datadog/ci/test_visibility/context/local.rb
150
151
  - lib/datadog/ci/test_visibility/flush.rb
151
- - lib/datadog/ci/test_visibility/null_recorder.rb
152
- - lib/datadog/ci/test_visibility/recorder.rb
152
+ - lib/datadog/ci/test_visibility/null_component.rb
153
153
  - lib/datadog/ci/test_visibility/serializers/base.rb
154
154
  - lib/datadog/ci/test_visibility/serializers/factories/test_level.rb
155
155
  - lib/datadog/ci/test_visibility/serializers/factories/test_suite_level.rb
@@ -160,6 +160,7 @@ files:
160
160
  - lib/datadog/ci/test_visibility/serializers/test_v1.rb
161
161
  - lib/datadog/ci/test_visibility/serializers/test_v2.rb
162
162
  - lib/datadog/ci/test_visibility/transport.rb
163
+ - lib/datadog/ci/transport/adapters/net.rb
163
164
  - lib/datadog/ci/transport/api/agentless.rb
164
165
  - lib/datadog/ci/transport/api/base.rb
165
166
  - lib/datadog/ci/transport/api/builder.rb
@@ -201,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
201
202
  - !ruby/object:Gem::Version
202
203
  version: 2.0.0
203
204
  requirements: []
204
- rubygems_version: 3.5.9
205
+ rubygems_version: 3.5.11
205
206
  signing_key:
206
207
  specification_version: 4
207
208
  summary: Datadog CI visibility for your ruby application