datadog-ci 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -1
  3. data/LICENSE-3rdparty.csv +1 -0
  4. data/README.md +64 -0
  5. data/lib/datadog/ci/configuration/components.rb +51 -5
  6. data/lib/datadog/ci/configuration/settings.rb +36 -8
  7. data/lib/datadog/ci/contrib/cucumber/configuration/settings.rb +2 -3
  8. data/lib/datadog/ci/contrib/cucumber/formatter.rb +8 -10
  9. data/lib/datadog/ci/contrib/cucumber/integration.rb +3 -5
  10. data/lib/datadog/ci/contrib/integration.rb +149 -0
  11. data/lib/datadog/ci/contrib/minitest/configuration/settings.rb +2 -3
  12. data/lib/datadog/ci/contrib/minitest/hooks.rb +8 -4
  13. data/lib/datadog/ci/contrib/minitest/integration.rb +3 -5
  14. data/lib/datadog/ci/contrib/rspec/configuration/settings.rb +2 -3
  15. data/lib/datadog/ci/contrib/rspec/example.rb +5 -8
  16. data/lib/datadog/ci/contrib/rspec/integration.rb +3 -5
  17. data/lib/datadog/ci/contrib/settings.rb +33 -0
  18. data/lib/datadog/ci/ext/environment/providers/local_git.rb +7 -0
  19. data/lib/datadog/ci/ext/settings.rb +2 -0
  20. data/lib/datadog/ci/ext/transport.rb +19 -0
  21. data/lib/datadog/ci/{test.rb → recorder.rb} +6 -5
  22. data/lib/datadog/ci/test_visibility/flush.rb +40 -0
  23. data/lib/datadog/ci/test_visibility/serializers/base.rb +161 -0
  24. data/lib/datadog/ci/test_visibility/serializers/factories/test_level.rb +30 -0
  25. data/lib/datadog/ci/test_visibility/serializers/span.rb +51 -0
  26. data/lib/datadog/ci/test_visibility/serializers/test_v1.rb +60 -0
  27. data/lib/datadog/ci/test_visibility/transport.rb +169 -0
  28. data/lib/datadog/ci/transport/gzip.rb +20 -0
  29. data/lib/datadog/ci/transport/http.rb +153 -0
  30. data/lib/datadog/ci/version.rb +2 -2
  31. data/sig/datadog/ci/configuration/components.rbs +2 -0
  32. data/sig/datadog/ci/configuration/settings.rbs +2 -0
  33. data/sig/datadog/ci/contrib/cucumber/configuration/settings.rbs +1 -1
  34. data/sig/datadog/ci/contrib/cucumber/integration.rbs +2 -1
  35. data/sig/datadog/ci/contrib/integration.rbs +44 -0
  36. data/sig/datadog/ci/contrib/minitest/configuration/settings.rbs +1 -1
  37. data/sig/datadog/ci/contrib/minitest/integration.rbs +4 -3
  38. data/sig/datadog/ci/contrib/rspec/configuration/settings.rbs +1 -1
  39. data/sig/datadog/ci/contrib/rspec/integration.rbs +3 -2
  40. data/sig/datadog/ci/contrib/settings.rbs +25 -0
  41. data/sig/datadog/ci/ext/settings.rbs +2 -0
  42. data/sig/datadog/ci/ext/transport.rbs +21 -0
  43. data/sig/datadog/ci/{test.rbs → recorder.rbs} +1 -1
  44. data/sig/datadog/ci/test_visibility/flush.rbs +17 -0
  45. data/sig/datadog/ci/test_visibility/serializers/base.rbs +73 -0
  46. data/sig/datadog/ci/test_visibility/serializers/factories/test_level.rbs +13 -0
  47. data/sig/datadog/ci/test_visibility/serializers/span.rbs +18 -0
  48. data/sig/datadog/ci/test_visibility/serializers/test_v1.rbs +23 -0
  49. data/sig/datadog/ci/test_visibility/transport.rbs +39 -0
  50. data/sig/datadog/ci/transport/gzip.rbs +9 -0
  51. data/sig/datadog/ci/transport/http.rbs +61 -0
  52. metadata +41 -7
  53. data/lib/datadog/ci/flush.rb +0 -38
  54. data/sig/datadog/ci/flush.rbs +0 -15
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+
5
+ require_relative "gzip"
6
+ require_relative "../ext/transport"
7
+
8
+ module Datadog
9
+ module CI
10
+ module Transport
11
+ class HTTP
12
+ attr_reader \
13
+ :host,
14
+ :port,
15
+ :ssl,
16
+ :timeout,
17
+ :compress
18
+
19
+ DEFAULT_TIMEOUT = 30
20
+
21
+ def initialize(host:, timeout: DEFAULT_TIMEOUT, port: nil, ssl: true, compress: false)
22
+ @host = host
23
+ @port = port
24
+ @timeout = timeout
25
+ @ssl = ssl.nil? ? true : ssl
26
+ @compress = compress.nil? ? false : compress
27
+ end
28
+
29
+ def request(path:, payload:, headers:, method: "post")
30
+ raise "Unknown method #{method}" unless respond_to?(method, true)
31
+
32
+ if compress
33
+ headers[Ext::Transport::HEADER_CONTENT_ENCODING] = Ext::Transport::CONTENT_ENCODING_GZIP
34
+ payload = Gzip.compress(payload)
35
+ end
36
+
37
+ Datadog.logger.debug do
38
+ "Sending #{method} request: host=#{host}; port=#{port}; ssl_enabled=#{ssl}; " \
39
+ "compression_enabled=#{compress}; path=#{path}; payload_size=#{payload.size}"
40
+ end
41
+
42
+ send(method, path: path, payload: payload, headers: headers)
43
+ end
44
+
45
+ private
46
+
47
+ def open(&block)
48
+ req = ::Net::HTTP.new(@host, @port)
49
+
50
+ req.use_ssl = @ssl
51
+ req.open_timeout = req.read_timeout = @timeout
52
+
53
+ req.start(&block)
54
+ end
55
+
56
+ def post(path:, headers:, payload:)
57
+ post = ::Net::HTTP::Post.new(path, headers)
58
+ post.body = payload
59
+
60
+ http_response = open do |http|
61
+ http.request(post)
62
+ end
63
+
64
+ Response.new(http_response)
65
+ rescue => e
66
+ Datadog.logger.debug("Unable to send events: #{e}")
67
+
68
+ InternalErrorResponse.new(e)
69
+ end
70
+
71
+ # Data structure for an HTTP Response
72
+ class Response
73
+ attr_reader :http_response
74
+
75
+ def initialize(http_response)
76
+ @http_response = http_response
77
+ end
78
+
79
+ def payload
80
+ http_response.body
81
+ end
82
+
83
+ def code
84
+ http_response.code.to_i
85
+ end
86
+
87
+ def ok?
88
+ code.between?(200, 299)
89
+ end
90
+
91
+ def unsupported?
92
+ code == 415
93
+ end
94
+
95
+ def not_found?
96
+ code == 404
97
+ end
98
+
99
+ def client_error?
100
+ code.between?(400, 499)
101
+ end
102
+
103
+ def server_error?
104
+ code.between?(500, 599)
105
+ end
106
+
107
+ def internal_error?
108
+ false
109
+ end
110
+
111
+ def trace_count
112
+ 0
113
+ end
114
+
115
+ def inspect
116
+ "#{self.class} ok?:#{ok?} unsupported?:#{unsupported?}, " \
117
+ "not_found?:#{not_found?}, client_error?:#{client_error?}, " \
118
+ "server_error?:#{server_error?}, internal_error?:#{internal_error?}, " \
119
+ "payload:#{payload}"
120
+ end
121
+ end
122
+
123
+ class InternalErrorResponse < Response
124
+ class DummyNetHTTPResponse
125
+ def body
126
+ ""
127
+ end
128
+
129
+ def code
130
+ "-1"
131
+ end
132
+ end
133
+
134
+ attr_reader :error
135
+
136
+ def initialize(error)
137
+ super(DummyNetHTTPResponse.new)
138
+
139
+ @error = error
140
+ end
141
+
142
+ def internal_error?
143
+ true
144
+ end
145
+
146
+ def inspect
147
+ "#{super}, error_class:#{error.class}, error:#{error}"
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -4,8 +4,8 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = "0"
7
- MINOR = "1"
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
@@ -5,6 +5,8 @@ module Datadog
5
5
  def initialize: (untyped settings) -> void
6
6
 
7
7
  def activate_ci!: (untyped settings) -> untyped
8
+
9
+ def build_agentless_transport: (untyped settings) -> Datadog::CI::TestVisibility::Transport
8
10
  end
9
11
  end
10
12
  end
@@ -3,6 +3,8 @@ module Datadog
3
3
  module Configuration
4
4
  module Settings
5
5
  extend Datadog::Core::Configuration::Options::ClassMethods
6
+ include Datadog::Core::Configuration::Options::InstanceMethods
7
+
6
8
  extend Datadog::Core::Configuration::Base::ClassMethods
7
9
 
8
10
  def self.extended: (untyped base) -> untyped
@@ -3,7 +3,7 @@ module Datadog
3
3
  module Contrib
4
4
  module Cucumber
5
5
  module Configuration
6
- class Settings < Datadog::Tracing::Contrib::Configuration::Settings
6
+ class Settings < Datadog::CI::Contrib::Settings
7
7
  end
8
8
  end
9
9
  end
@@ -3,7 +3,8 @@ module Datadog
3
3
  module Contrib
4
4
  module Cucumber
5
5
  class Integration
6
- extend Datadog::Tracing::Contrib::Integration
6
+ extend Datadog::CI::Contrib::Integration::ClassMethods
7
+ include Datadog::CI::Contrib::Integration::InstanceMethods
7
8
 
8
9
  MINIMUM_VERSION: Gem::Version
9
10
 
@@ -0,0 +1,44 @@
1
+ module Datadog
2
+ module CI
3
+ module Contrib
4
+ module Integration
5
+ self.@registry: Hash[Symbol, untyped]
6
+
7
+ def self.included: (Module base) -> void
8
+
9
+ def self.register: (untyped integration, Symbol name) -> void
10
+
11
+ def self.registry: () -> Hash[Symbol, Struct[untyped]]
12
+
13
+ module ClassMethods
14
+ def register_as: (Symbol name) -> void
15
+
16
+ def version: () -> Gem::Version?
17
+
18
+ def available?: () -> bool
19
+
20
+ def loaded?: () -> bool
21
+
22
+ def compatible?: () -> bool
23
+
24
+ def patchable?: () -> bool
25
+ end
26
+
27
+ module InstanceMethods
28
+ extend ClassMethods
29
+ @configuration: Datadog::CI::Contrib::Settings?
30
+
31
+ def configuration: () -> Datadog::CI::Contrib::Settings
32
+
33
+ def configure: (?::Hash[Symbol, untyped] options) ?{ (Datadog::CI::Contrib::Settings) -> Datadog::CI::Contrib::Settings } -> Datadog::CI::Contrib::Settings
34
+
35
+ def reset_configuration!: () -> void
36
+
37
+ def patcher: () -> Datadog::Tracing::Contrib::Patcher?
38
+
39
+ def new_configuration: () -> Datadog::CI::Contrib::Settings
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -3,7 +3,7 @@ module Datadog
3
3
  module Contrib
4
4
  module Minitest
5
5
  module Configuration
6
- class Settings < Datadog::Tracing::Contrib::Configuration::Settings
6
+ class Settings < Datadog::CI::Contrib::Settings
7
7
  end
8
8
  end
9
9
  end
@@ -3,13 +3,14 @@ module Datadog
3
3
  module Contrib
4
4
  module Minitest
5
5
  class Integration
6
- extend Datadog::Tracing::Contrib::Integration
6
+ extend Datadog::CI::Contrib::Integration::ClassMethods
7
+ include Datadog::CI::Contrib::Integration::InstanceMethods
7
8
 
8
- MINIMUM_VERSION: untyped
9
+ MINIMUM_VERSION: Gem::Version
9
10
 
10
11
  def self.version: () -> untyped
11
12
 
12
- def self.loaded?: () -> untyped
13
+ def self.loaded?: () -> bool
13
14
 
14
15
  def compatible?: () -> bool
15
16
 
@@ -3,7 +3,7 @@ module Datadog
3
3
  module Contrib
4
4
  module RSpec
5
5
  module Configuration
6
- class Settings < Datadog::Tracing::Contrib::Configuration::Settings
6
+ class Settings < Datadog::CI::Contrib::Settings
7
7
  end
8
8
  end
9
9
  end
@@ -3,9 +3,10 @@ module Datadog
3
3
  module Contrib
4
4
  module RSpec
5
5
  class Integration
6
- extend Datadog::Tracing::Contrib::Integration
6
+ extend Datadog::CI::Contrib::Integration::ClassMethods
7
+ include Datadog::CI::Contrib::Integration::InstanceMethods
7
8
 
8
- MINIMUM_VERSION: untyped
9
+ MINIMUM_VERSION: Gem::Version
9
10
 
10
11
  def self.version: () -> untyped
11
12
 
@@ -0,0 +1,25 @@
1
+ module Datadog
2
+ module CI
3
+ module Contrib
4
+ class Settings
5
+ include Core::Configuration::Base
6
+ extend Datadog::Core::Configuration::Options::ClassMethods
7
+ include Datadog::Core::Configuration::Options::InstanceMethods
8
+
9
+ extend Datadog::Core::Configuration::Base::ClassMethods
10
+
11
+ def configure: (?::Hash[Symbol, untyped] options) ?{ (Datadog::CI::Contrib::Settings) -> Datadog::CI::Contrib::Settings } -> Datadog::CI::Contrib::Settings?
12
+
13
+ def []: (Symbol name) -> Datadog::CI::Contrib::Settings
14
+
15
+ def []=: (untyped name, untyped value) -> untyped
16
+
17
+ # default configuration options
18
+ #
19
+ def enabled: () -> bool
20
+ def service_name: () -> String
21
+ def operation_name: () -> String
22
+ end
23
+ end
24
+ end
25
+ end
@@ -3,6 +3,8 @@ module Datadog
3
3
  module Ext
4
4
  module Settings
5
5
  ENV_MODE_ENABLED: String
6
+ ENV_AGENTLESS_MODE_ENABLED: String
7
+ ENV_AGENTLESS_URL: String
6
8
  end
7
9
  end
8
10
  end
@@ -0,0 +1,21 @@
1
+ module Datadog
2
+ module CI
3
+ module Ext
4
+ module Transport
5
+ HEADER_DD_API_KEY: "DD-API-KEY"
6
+
7
+ HEADER_CONTENT_TYPE: "Content-Type"
8
+
9
+ HEADER_CONTENT_ENCODING: "Content-Encoding"
10
+
11
+ TEST_VISIBILITY_INTAKE_HOST_PREFIX: "citestcycle-intake"
12
+
13
+ TEST_VISIBILITY_INTAKE_PATH: "/api/v2/citestcycle"
14
+
15
+ CONTENT_TYPE_MESSAGEPACK: "application/msgpack"
16
+
17
+ CONTENT_ENCODING_GZIP: "gzip"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,6 @@
1
1
  module Datadog
2
2
  module CI
3
- module Test
3
+ module Recorder
4
4
  self.@environment_tags: Hash[String, String]
5
5
 
6
6
  def self.trace: (untyped span_name, ?::Hash[untyped, untyped] options) ?{ (untyped, untyped) -> untyped } -> untyped
@@ -0,0 +1,17 @@
1
+ module Datadog
2
+ module CI
3
+ module TestVisibility
4
+ module Flush
5
+ module Tagging
6
+ def get_trace: (Datadog::Tracing::TraceOperation trace_op) -> untyped
7
+ end
8
+ class Finished < Tracing::Flush::Finished
9
+ prepend Tagging
10
+ end
11
+ class Partial < Tracing::Flush::Partial
12
+ prepend Tagging
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,73 @@
1
+ module Datadog
2
+ module CI
3
+ module TestVisibility
4
+ module Serializers
5
+ class Base
6
+ MINIMUM_TIMESTAMP_NANO: 946684800000000000
7
+ MINIMUM_DURATION_NANO: 0
8
+ MAXIMUM_DURATION_NANO: 9223372036854775807
9
+
10
+ @content_fields_count: Integer
11
+ @start: Integer
12
+ @duration: Integer
13
+
14
+ attr_reader trace: Datadog::Tracing::TraceSegment
15
+ attr_reader span: Datadog::Tracing::Span
16
+
17
+ def initialize: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span) -> void
18
+
19
+ def to_msgpack: (?untyped? packer) -> untyped
20
+
21
+ def valid?: () -> bool
22
+ def content_fields: () -> ::Array[String | Hash[String, String]]
23
+ def content_map_size: () -> Integer
24
+
25
+ def runtime_id: () -> String
26
+
27
+ def trace_id: () -> String
28
+
29
+ def span_id: () -> String
30
+
31
+ def parent_id: () -> String
32
+
33
+ def type: () -> nil
34
+
35
+ def version: () -> 1
36
+
37
+ def span_type: () -> String
38
+
39
+ def name: () -> String
40
+
41
+ def resource: () -> String
42
+
43
+ def service: () -> String
44
+
45
+ def start: () -> Integer
46
+
47
+ def duration: () -> Integer
48
+
49
+ def meta: () -> Hash[String, untyped]
50
+
51
+ def metrics: () -> Hash[String, untyped]
52
+
53
+ def error: () -> Integer
54
+
55
+ def self.calculate_content_map_size: (Array[String | Hash[String, String]] fields_list) -> Integer
56
+
57
+ private
58
+
59
+ def valid_start_time?: () -> bool
60
+ def valid_duration?: () -> bool
61
+ def required_fields_present?: () -> bool
62
+ def required_fields: () -> Array[String]
63
+
64
+ def write_field: (untyped packer, String field_name, ?String? method) -> untyped
65
+ def time_nano: (Time time) -> Integer
66
+ def duration_nano: (Float duration) -> Integer
67
+
68
+ def content_fields_count: () -> Integer
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,13 @@
1
+ module Datadog
2
+ module CI
3
+ module TestVisibility
4
+ module Serializers
5
+ module Factories
6
+ module TestLevel
7
+ def self?.serializer: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span) -> Datadog::CI::TestVisibility::Serializers::Base
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module Datadog
2
+ module CI
3
+ module TestVisibility
4
+ module Serializers
5
+ class Span < Base
6
+ CONTENT_FIELDS: Array[String | Hash[String, String]]
7
+ CONTENT_MAP_SIZE: Integer
8
+ REQUIRED_FIELDS: Array[String]
9
+
10
+ def required_fields: () -> Array[String]
11
+ def content_fields: () -> Array[String | Hash[String, String]]
12
+ def content_map_size: () -> Integer
13
+ def type: () -> "span"
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ module Datadog
2
+ module CI
3
+ module TestVisibility
4
+ module Serializers
5
+ class TestV1 < Base
6
+ CONTENT_FIELDS: Array[String | Hash[String, String]]
7
+ CONTENT_MAP_SIZE: Integer
8
+ REQUIRED_FIELDS: Array[String]
9
+
10
+ def required_fields: () -> Array[String]
11
+ def content_fields: () -> Array[String | Hash[String, String]]
12
+ def content_map_size: () -> Integer
13
+
14
+ def type: () -> "test"
15
+
16
+ def name: () -> ::String
17
+
18
+ def resource: () -> ::String
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ module Datadog
2
+ module CI
3
+ module TestVisibility
4
+ class Transport
5
+ DEFAULT_MAX_PAYLOAD_SIZE: Integer
6
+
7
+ attr_reader serializers_factory: singleton(Datadog::CI::TestVisibility::Serializers::Factories::TestLevel)
8
+ attr_reader api_key: String
9
+ attr_reader env: String?
10
+ attr_reader http: Datadog::CI::Transport::HTTP
11
+ attr_reader max_payload_size: Integer
12
+
13
+ @api_key: String
14
+ @env: String?
15
+ @http: Datadog::CI::Transport::HTTP
16
+ @serializers_factory: singleton(Datadog::CI::TestVisibility::Serializers::Factories::TestLevel)
17
+ @max_payload_size: Integer
18
+
19
+ def initialize: (
20
+ api_key: String,
21
+ url: ::String,
22
+ ?env: ::String?,
23
+ ?serializers_factory: singleton(Datadog::CI::TestVisibility::Serializers::Factories::TestLevel),
24
+ ?max_payload_size: Integer
25
+ ) -> void
26
+
27
+ def send_traces: (Array[Datadog::Tracing::TraceSegment] traces) -> ::Array[Datadog::CI::Transport::HTTP::Response]
28
+
29
+ private
30
+
31
+ def send_payload: (String encoded_payload) -> Datadog::CI::Transport::HTTP::Response
32
+ def pack_events: (Array[String] encoded_events) -> String
33
+ def encode_traces: (Array[Datadog::Tracing::TraceSegment] traces) -> ::Array[String]
34
+ def encode_span: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span) -> String?
35
+ def encoder: () -> singleton(Datadog::Core::Encoding::MsgpackEncoder)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ module Datadog
2
+ module CI
3
+ module Transport
4
+ module Gzip
5
+ def self?.compress: (String input) -> String
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,61 @@
1
+ module Datadog
2
+ module CI
3
+ module Transport
4
+ class HTTP
5
+ attr_reader host: String
6
+ attr_reader port: Integer?
7
+ attr_reader ssl: bool
8
+ attr_reader timeout: Integer
9
+ attr_reader compress: bool
10
+
11
+ DEFAULT_TIMEOUT: 30
12
+
13
+ def initialize: (host: String, ?port: Integer?, ?ssl: bool, ?timeout: Integer, ?compress: bool) -> void
14
+
15
+ def request: (?method: String, payload: String, headers: Hash[String, String], path: String) -> Response
16
+
17
+ private
18
+
19
+ def open: () { (::Net::HTTP) -> Net::HTTPResponse } -> Net::HTTPResponse
20
+
21
+ def post: (payload: String, headers: Hash[String, String], path: String) -> Response
22
+
23
+ class Response
24
+ attr_reader http_response: (Net::HTTPResponse | InternalErrorResponse::DummyNetHTTPResponse)
25
+
26
+ def initialize: ((Net::HTTPResponse | InternalErrorResponse::DummyNetHTTPResponse) http_response) -> void
27
+
28
+ def payload: () -> String
29
+
30
+ def code: () -> Integer
31
+
32
+ def ok?: () -> bool
33
+
34
+ def unsupported?: () -> bool
35
+
36
+ def not_found?: () -> bool
37
+
38
+ def client_error?: () -> bool
39
+
40
+ def server_error?: () -> bool
41
+
42
+ def internal_error?: () -> bool
43
+
44
+ def inspect: () -> ::String
45
+ end
46
+
47
+ class InternalErrorResponse < Response
48
+ class DummyNetHTTPResponse
49
+ def body: () -> ""
50
+ def code: () -> "-1"
51
+ end
52
+
53
+ attr_reader error: StandardError
54
+ @error: StandardError
55
+
56
+ def initialize: (StandardError error) -> void
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end