datadog-ci 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -1
  3. data/lib/datadog/ci/configuration/components.rb +46 -25
  4. data/lib/datadog/ci/ext/environment/providers/appveyor.rb +4 -0
  5. data/lib/datadog/ci/ext/environment/providers/aws_code_pipeline.rb +39 -0
  6. data/lib/datadog/ci/ext/environment/providers/azure.rb +4 -0
  7. data/lib/datadog/ci/ext/environment/providers/base.rb +4 -0
  8. data/lib/datadog/ci/ext/environment/providers/bitbucket.rb +4 -0
  9. data/lib/datadog/ci/ext/environment/providers/bitrise.rb +4 -0
  10. data/lib/datadog/ci/ext/environment/providers/buddy.rb +4 -0
  11. data/lib/datadog/ci/ext/environment/providers/buildkite.rb +4 -0
  12. data/lib/datadog/ci/ext/environment/providers/circleci.rb +4 -0
  13. data/lib/datadog/ci/ext/environment/providers/codefresh.rb +4 -0
  14. data/lib/datadog/ci/ext/environment/providers/github_actions.rb +4 -0
  15. data/lib/datadog/ci/ext/environment/providers/gitlab.rb +4 -0
  16. data/lib/datadog/ci/ext/environment/providers/jenkins.rb +4 -0
  17. data/lib/datadog/ci/ext/environment/providers/teamcity.rb +4 -0
  18. data/lib/datadog/ci/ext/environment/providers/travis.rb +4 -0
  19. data/lib/datadog/ci/ext/environment/providers.rb +16 -14
  20. data/lib/datadog/ci/ext/transport.rb +5 -0
  21. data/lib/datadog/ci/test_visibility/transport.rb +11 -29
  22. data/lib/datadog/ci/transport/api/base.rb +36 -0
  23. data/lib/datadog/ci/transport/api/builder.rb +46 -0
  24. data/lib/datadog/ci/transport/api/ci_test_cycle.rb +30 -0
  25. data/lib/datadog/ci/transport/api/evp_proxy.rb +44 -0
  26. data/lib/datadog/ci/transport/gzip.rb +4 -2
  27. data/lib/datadog/ci/transport/http.rb +25 -101
  28. data/lib/datadog/ci/version.rb +1 -1
  29. data/sig/datadog/ci/configuration/components.rbs +3 -1
  30. data/sig/datadog/ci/ext/environment/providers/aws_code_pipeline.rbs +19 -0
  31. data/sig/datadog/ci/ext/environment/providers/base.rbs +2 -0
  32. data/sig/datadog/ci/ext/environment/providers.rbs +1 -1
  33. data/sig/datadog/ci/ext/transport.rbs +8 -0
  34. data/sig/datadog/ci/test_visibility/transport.rbs +7 -11
  35. data/sig/datadog/ci/transport/api/base.rbs +21 -0
  36. data/sig/datadog/ci/transport/api/builder.rbs +12 -0
  37. data/sig/datadog/ci/transport/api/ci_test_cycle.rbs +21 -0
  38. data/sig/datadog/ci/transport/api/evp_proxy.rbs +19 -0
  39. data/sig/datadog/ci/transport/http.rbs +12 -37
  40. metadata +13 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: edf471864cc0dc97624e2666deede58c547f5513a972a4e041c1204a0b665a36
4
- data.tar.gz: a1cbf16a8c4891173dc02ceef831a94be2b2a50936bf551494c814c94a94594c
3
+ metadata.gz: ce3b4502404f6faa6b05421763ced6582071c9ad025937219b59ba8c63c39175
4
+ data.tar.gz: 7a341aa75161299cb04a29f745e172ef5ca4fec3a24f536ec96e08119de11a97
5
5
  SHA512:
6
- metadata.gz: 9c1559ae996b1f7ee7fc5ac0ec131f4e227fb227c7fa62af30f3e6739e040d5947a1e1ca900b3abe94d21262608164dd0ea82ffbcd7fa1e5a157ab400bd22554
7
- data.tar.gz: c58b74157088a4c3e8dbafad7cbf443ebbb503cc831ae2106190bfadc26cfd67f1c80be6d7b500350736b3b3ee8056d1de4aec4693a7500cef1156dd490d3cf7
6
+ metadata.gz: 6058fbf497f43040a588018a2104055a303849d5616d063412dae4dab1e5247098e9ecd1b0b718776a51bc090f137d2bcf19cc78d252c7968c9cd6e4723ad902
7
+ data.tar.gz: 3c8d8eb9a34266a690a0dd5103d344b80df5175c703a414b1bc8255dc3c2732d723960e786765f2686fdcaaff5f009b675942c5e39dbd4a6fc9e58a38653051e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2023-10-25
4
+
5
+ ### Added
6
+
7
+ * Add AWS CodePipeline support for automatic CI tags extraction ([#54][])
8
+ * Support test visibility protocol via Datadog Agent with EVP proxy ([#51][])
9
+
10
+ ### Changed
11
+
12
+ * Migrate to Net::HTTP adapter from Core module of ddtrace gem ([#49][])
13
+
3
14
  ## [0.2.0] - 2023-10-05
4
15
 
5
16
  ### Added
@@ -36,7 +47,8 @@
36
47
 
37
48
  * Ruby versions < 2.7 no longer supported ([#8][])
38
49
 
39
- [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v0.2.0...main
50
+ [Unreleased]: https://github.com/DataDog/datadog-ci-rb/compare/v0.3.0...main
51
+ [0.3.0]: https://github.com/DataDog/datadog-ci-rb/compare/v0.2.0...v0.3.0
40
52
  [0.2.0]: https://github.com/DataDog/datadog-ci-rb/compare/v0.1.1...v0.2.0
41
53
  [0.1.1]: https://github.com/DataDog/datadog-ci-rb/compare/v0.1.0...v0.1.1
42
54
 
@@ -51,3 +63,6 @@
51
63
  [#31]: https://github.com/DataDog/datadog-ci-rb/issues/31
52
64
  [#33]: https://github.com/DataDog/datadog-ci-rb/issues/33
53
65
  [#40]: https://github.com/DataDog/datadog-ci-rb/issues/40
66
+ [#49]: https://github.com/DataDog/datadog-ci-rb/issues/49
67
+ [#51]: https://github.com/DataDog/datadog-ci-rb/issues/51
68
+ [#54]: https://github.com/DataDog/datadog-ci-rb/issues/54
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "datadog/core/configuration/agent_settings_resolver"
4
+ require "datadog/core/remote/negotiation"
5
+
6
+ require_relative "../ext/transport"
3
7
  require_relative "../test_visibility/flush"
4
8
  require_relative "../test_visibility/transport"
9
+ require_relative "../transport/api/builder"
5
10
 
6
11
  module Datadog
7
12
  module CI
@@ -17,25 +22,13 @@ module Datadog
17
22
  end
18
23
 
19
24
  def activate_ci!(settings)
20
- agentless_transport = nil
25
+ test_visibility_transport = nil
26
+ agent_settings = Datadog::Core::Configuration::AgentSettingsResolver.call(settings)
21
27
 
22
28
  if settings.ci.agentless_mode_enabled
23
- if settings.api_key.nil?
24
- # agentless mode is requested but no API key is provided -
25
- # we cannot continue and log an error
26
- # Tests are running without CI visibility enabled
27
-
28
- Datadog.logger.error(
29
- "DATADOG CONFIGURATION - CI VISIBILITY - ATTENTION - " \
30
- "Agentless mode was enabled but DD_API_KEY is not set: CI visibility is disabled. " \
31
- "Please make sure to set valid api key in DD_API_KEY environment variable"
32
- )
33
-
34
- settings.ci.enabled = false
35
- return
36
- else
37
- agentless_transport = build_agentless_transport(settings)
38
- end
29
+ test_visibility_transport = build_agentless_transport(settings)
30
+ elsif can_use_evp_proxy?(settings, agent_settings)
31
+ test_visibility_transport = build_evp_proxy_transport(settings, agent_settings)
39
32
  end
40
33
 
41
34
  # Deactivate telemetry
@@ -51,8 +44,8 @@ module Datadog
51
44
  settings.tracing.test_mode.trace_flush = settings.ci.trace_flush || CI::TestVisibility::Flush::Finished.new
52
45
 
53
46
  writer_options = settings.ci.writer_options
54
- if agentless_transport
55
- writer_options[:transport] = agentless_transport
47
+ if test_visibility_transport
48
+ writer_options[:transport] = test_visibility_transport
56
49
  writer_options[:shutdown_timeout] = 60
57
50
 
58
51
  settings.tracing.test_mode.async = true
@@ -61,15 +54,43 @@ module Datadog
61
54
  settings.tracing.test_mode.writer_options = writer_options
62
55
  end
63
56
 
57
+ def can_use_evp_proxy?(settings, agent_settings)
58
+ Datadog::Core::Remote::Negotiation.new(settings, agent_settings).endpoint?(
59
+ Ext::Transport::EVP_PROXY_PATH_PREFIX
60
+ )
61
+ end
62
+
64
63
  def build_agentless_transport(settings)
65
- dd_site = settings.site || "datadoghq.com"
66
- agentless_url = settings.ci.agentless_url ||
67
- "https://#{Ext::Transport::TEST_VISIBILITY_INTAKE_HOST_PREFIX}.#{dd_site}:443"
64
+ if settings.api_key.nil?
65
+ # agentless mode is requested but no API key is provided -
66
+ # we cannot continue and log an error
67
+ # Tests are running without CI visibility enabled
68
+
69
+ Datadog.logger.error(
70
+ "DATADOG CONFIGURATION - CI VISIBILITY - ATTENTION - " \
71
+ "Agentless mode was enabled but DD_API_KEY is not set: CI visibility is disabled. " \
72
+ "Please make sure to set valid api key in DD_API_KEY environment variable"
73
+ )
74
+
75
+ settings.ci.enabled = false
76
+
77
+ nil
78
+ else
79
+ Datadog.logger.debug("CI visibility configured to use agentless transport")
80
+
81
+ Datadog::CI::TestVisibility::Transport.new(
82
+ api: Transport::Api::Builder.build_ci_test_cycle_api(settings),
83
+ dd_env: settings.env
84
+ )
85
+ end
86
+ end
87
+
88
+ def build_evp_proxy_transport(settings, agent_settings)
89
+ Datadog.logger.debug("CI visibility configured to use agent transport via EVP proxy")
68
90
 
69
91
  Datadog::CI::TestVisibility::Transport.new(
70
- api_key: settings.api_key,
71
- url: agentless_url,
72
- env: settings.env
92
+ api: Transport::Api::Builder.build_evp_proxy_api(agent_settings),
93
+ dd_env: settings.env
73
94
  )
74
95
  end
75
96
  end
@@ -10,6 +10,10 @@ module Datadog
10
10
  # Appveyor: https://www.appveyor.com/
11
11
  # Environment variables docs: https://www.appveyor.com/docs/environment-variables/
12
12
  class Appveyor < Base
13
+ def self.handles?(env)
14
+ env.key?("APPVEYOR")
15
+ end
16
+
13
17
  def provider_name
14
18
  "appveyor"
15
19
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Ext
8
+ module Environment
9
+ module Providers
10
+ # AWS CodePipeline: https://aws.amazon.com/codepipeline/
11
+ # Environment variables docs: https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-variables.html
12
+ # AWS CodeBuild: https://aws.amazon.com/codebuild/
13
+ # Environment variable docs: https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
14
+ class AwsCodePipeline < Base
15
+ def self.handles?(env)
16
+ !env["CODEBUILD_INITIATOR"].nil? && env["CODEBUILD_INITIATOR"].start_with?("codepipeline")
17
+ end
18
+
19
+ def provider_name
20
+ "awscodepipeline"
21
+ end
22
+
23
+ def pipeline_id
24
+ env["DD_PIPELINE_EXECUTION_ID"]
25
+ end
26
+
27
+ def ci_env_vars
28
+ {
29
+ "CODEBUILD_BUILD_ARN" => env["CODEBUILD_BUILD_ARN"],
30
+ "DD_PIPELINE_EXECUTION_ID" => env["DD_PIPELINE_EXECUTION_ID"],
31
+ "DD_ACTION_EXECUTION_ID" => env["DD_ACTION_EXECUTION_ID"]
32
+ }.to_json
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -12,6 +12,10 @@ module Datadog
12
12
  # Azure Pipelines: https://azure.microsoft.com/en-us/products/devops/pipelines
13
13
  # Environment variables docs: https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml
14
14
  class Azure < Base
15
+ def self.handles?(env)
16
+ env.key?("TF_BUILD")
17
+ end
18
+
15
19
  def provider_name
16
20
  "azurepipelines"
17
21
  end
@@ -8,6 +8,10 @@ module Datadog
8
8
  class Base
9
9
  attr_reader :env
10
10
 
11
+ def self.handles?(_env)
12
+ false
13
+ end
14
+
11
15
  def initialize(env)
12
16
  @env = env
13
17
  end
@@ -10,6 +10,10 @@ module Datadog
10
10
  # Bitbucket Pipelines: https://bitbucket.org/product/features/pipelines
11
11
  # Environment variables docs: https://support.atlassian.com/bitbucket-cloud/docs/variables-and-secrets/
12
12
  class Bitbucket < Base
13
+ def self.handles?(env)
14
+ env.key?("BITBUCKET_COMMIT")
15
+ end
16
+
13
17
  # overridden methods
14
18
  def provider_name
15
19
  "bitbucket"
@@ -10,6 +10,10 @@ module Datadog
10
10
  # Bitrise: https://bitrise.io/
11
11
  # Environment variables docs: https://devcenter.bitrise.io/en/references/available-environment-variables.html
12
12
  class Bitrise < Base
13
+ def self.handles?(env)
14
+ env.key?("BITRISE_BUILD_SLUG")
15
+ end
16
+
13
17
  def provider_name
14
18
  "bitrise"
15
19
  end
@@ -10,6 +10,10 @@ module Datadog
10
10
  # Buddy: https://buddy.works/
11
11
  # Environment variables docs: https://buddy.works/docs/pipelines/environment-variables
12
12
  class Buddy < Base
13
+ def self.handles?(env)
14
+ env.key?("BUDDY")
15
+ end
16
+
13
17
  def provider_name
14
18
  "buddy"
15
19
  end
@@ -12,6 +12,10 @@ module Datadog
12
12
  # Buildkite: https://buildkite.com/
13
13
  # Environment variables docs: https://buildkite.com/docs/pipelines/environment-variables
14
14
  class Buildkite < Base
15
+ def self.handles?(env)
16
+ env.key?("BUILDKITE")
17
+ end
18
+
15
19
  def provider_name
16
20
  "buildkite"
17
21
  end
@@ -12,6 +12,10 @@ module Datadog
12
12
  # Circle CI: https://circleci.com/
13
13
  # Environment variables docs: https://circleci.com/docs/variables/#built-in-environment-variables
14
14
  class Circleci < Base
15
+ def self.handles?(env)
16
+ env.key?("CIRCLECI")
17
+ end
18
+
15
19
  def provider_name
16
20
  "circleci"
17
21
  end
@@ -12,6 +12,10 @@ module Datadog
12
12
  # Codefresh: https://codefresh.io/
13
13
  # Environment variables docs: https://codefresh.io/docs/docs/pipelines/variables/#export-variables-to-all-steps-with-cf_export
14
14
  class Codefresh < Base
15
+ def self.handles?(env)
16
+ env.key?("CF_BUILD_ID")
17
+ end
18
+
15
19
  def provider_name
16
20
  "codefresh"
17
21
  end
@@ -12,6 +12,10 @@ module Datadog
12
12
  # Github Actions: https://github.com/features/actions
13
13
  # Environment variables docs: https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
14
14
  class GithubActions < Base
15
+ def self.handles?(env)
16
+ env.key?("GITHUB_SHA")
17
+ end
18
+
15
19
  def provider_name
16
20
  "github"
17
21
  end
@@ -10,6 +10,10 @@ module Datadog
10
10
  # Gitlab CI: https://docs.gitlab.com/ee/ci/
11
11
  # Environment variables docs: https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
12
12
  class Gitlab < Base
13
+ def self.handles?(env)
14
+ env.key?("GITLAB_CI")
15
+ end
16
+
13
17
  def provider_name
14
18
  "gitlab"
15
19
  end
@@ -13,6 +13,10 @@ module Datadog
13
13
  # Jenkins: https://www.jenkins.io/
14
14
  # Environment variables docs: https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
15
15
  class Jenkins < Base
16
+ def self.handles?(env)
17
+ env.key?("JENKINS_URL")
18
+ end
19
+
16
20
  def provider_name
17
21
  "jenkins"
18
22
  end
@@ -10,6 +10,10 @@ module Datadog
10
10
  # Teamcity: https://www.jetbrains.com/teamcity/
11
11
  # Environment variables docs: https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html
12
12
  class Teamcity < Base
13
+ def self.handles?(env)
14
+ env.key?("TEAMCITY_VERSION")
15
+ end
16
+
13
17
  def provider_name
14
18
  "teamcity"
15
19
  end
@@ -10,6 +10,10 @@ module Datadog
10
10
  # Travis CI: https://www.travis-ci.com/
11
11
  # Environment variables docs: https://docs.travis-ci.com/user/environment-variables#default-environment-variables
12
12
  class Travis < Base
13
+ def self.handles?(env)
14
+ env.key?("TRAVIS")
15
+ end
16
+
13
17
  def provider_name
14
18
  "travisci"
15
19
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "providers/base"
4
4
  require_relative "providers/appveyor"
5
+ require_relative "providers/aws_code_pipeline"
5
6
  require_relative "providers/azure"
6
7
  require_relative "providers/bitbucket"
7
8
  require_relative "providers/bitrise"
@@ -24,23 +25,24 @@ module Datadog
24
25
  module Environment
25
26
  module Providers
26
27
  PROVIDERS = [
27
- ["APPVEYOR", Providers::Appveyor],
28
- ["TF_BUILD", Providers::Azure],
29
- ["BITBUCKET_COMMIT", Providers::Bitbucket],
30
- ["BITRISE_BUILD_SLUG", Providers::Bitrise],
31
- ["BUDDY", Providers::Buddy],
32
- ["BUILDKITE", Providers::Buildkite],
33
- ["CIRCLECI", Providers::Circleci],
34
- ["CF_BUILD_ID", Providers::Codefresh],
35
- ["GITHUB_SHA", Providers::GithubActions],
36
- ["GITLAB_CI", Providers::Gitlab],
37
- ["JENKINS_URL", Providers::Jenkins],
38
- ["TEAMCITY_VERSION", Providers::Teamcity],
39
- ["TRAVIS", Providers::Travis]
28
+ Providers::Appveyor,
29
+ Providers::AwsCodePipeline,
30
+ Providers::Azure,
31
+ Providers::Bitbucket,
32
+ Providers::Bitrise,
33
+ Providers::Buddy,
34
+ Providers::Buildkite,
35
+ Providers::Circleci,
36
+ Providers::Codefresh,
37
+ Providers::GithubActions,
38
+ Providers::Gitlab,
39
+ Providers::Jenkins,
40
+ Providers::Teamcity,
41
+ Providers::Travis
40
42
  ]
41
43
 
42
44
  def self.for_environment(env)
43
- _, provider_klass = PROVIDERS.find { |provider_env_var, _| env.key?(provider_env_var) }
45
+ provider_klass = PROVIDERS.find { |klass| klass.handles?(env) }
44
46
  provider_klass = Providers::Base if provider_klass.nil?
45
47
 
46
48
  provider_klass.new(env)
@@ -4,10 +4,15 @@ module Datadog
4
4
  module CI
5
5
  module Ext
6
6
  module Transport
7
+ DEFAULT_DD_SITE = "datadoghq.com"
8
+
7
9
  HEADER_DD_API_KEY = "DD-API-KEY"
8
10
  HEADER_CONTENT_TYPE = "Content-Type"
9
11
  HEADER_CONTENT_ENCODING = "Content-Encoding"
12
+ HEADER_EVP_SUBDOMAIN = "X-Datadog-EVP-Subdomain"
13
+ HEADER_CONTAINER_ID = "Datadog-Container-ID"
10
14
 
15
+ EVP_PROXY_PATH_PREFIX = "/evp_proxy/v2/"
11
16
  TEST_VISIBILITY_INTAKE_HOST_PREFIX = "citestcycle-intake"
12
17
  TEST_VISIBILITY_INTAKE_PATH = "/api/v2/citestcycle"
13
18
 
@@ -9,7 +9,6 @@ require "datadog/core/chunker"
9
9
 
10
10
  require_relative "serializers/factories/test_level"
11
11
  require_relative "../ext/transport"
12
- require_relative "../transport/http"
13
12
 
14
13
  module Datadog
15
14
  module CI
@@ -20,33 +19,20 @@ module Datadog
20
19
  DEFAULT_MAX_PAYLOAD_SIZE = 5 * 1024 * 1024
21
20
 
22
21
  attr_reader :serializers_factory,
23
- :api_key,
22
+ :api,
24
23
  :max_payload_size,
25
- :http,
26
- :env
24
+ :dd_env
27
25
 
28
26
  def initialize(
29
- api_key:,
30
- url:,
31
- env: nil,
27
+ api:,
28
+ dd_env: nil,
32
29
  serializers_factory: Datadog::CI::TestVisibility::Serializers::Factories::TestLevel,
33
30
  max_payload_size: DEFAULT_MAX_PAYLOAD_SIZE
34
31
  )
35
32
  @serializers_factory = serializers_factory
36
- @api_key = api_key
37
33
  @max_payload_size = max_payload_size
38
- @env = env
39
-
40
- uri = URI.parse(url)
41
-
42
- raise "Invalid agentless mode URL: #{url}" if uri.host.nil?
43
-
44
- @http = Datadog::CI::Transport::HTTP.new(
45
- host: uri.host,
46
- port: uri.port,
47
- ssl: uri.scheme == "https" || uri.port == 443,
48
- compress: true
49
- )
34
+ @dd_env = dd_env
35
+ @api = api
50
36
  end
51
37
 
52
38
  def send_traces(traces)
@@ -82,13 +68,9 @@ module Datadog
82
68
  private
83
69
 
84
70
  def send_payload(encoded_payload)
85
- http.request(
71
+ api.request(
86
72
  path: Datadog::CI::Ext::Transport::TEST_VISIBILITY_INTAKE_PATH,
87
- payload: encoded_payload,
88
- headers: {
89
- Ext::Transport::HEADER_DD_API_KEY => api_key,
90
- Ext::Transport::HEADER_CONTENT_TYPE => Ext::Transport::CONTENT_TYPE_MESSAGEPACK
91
- }
73
+ payload: encoded_payload
92
74
  )
93
75
  end
94
76
 
@@ -141,12 +123,12 @@ module Datadog
141
123
  packer.write_map_header(1)
142
124
 
143
125
  packer.write("*")
144
- metadata_fields_count = env ? 4 : 3
126
+ metadata_fields_count = dd_env ? 4 : 3
145
127
  packer.write_map_header(metadata_fields_count)
146
128
 
147
- if env
129
+ if dd_env
148
130
  packer.write("env")
149
- packer.write(env)
131
+ packer.write(dd_env)
150
132
  end
151
133
 
152
134
  packer.write("runtime-id")
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../ext/transport"
4
+
5
+ module Datadog
6
+ module CI
7
+ module Transport
8
+ module Api
9
+ class Base
10
+ attr_reader :http
11
+
12
+ def initialize(http:)
13
+ @http = http
14
+ end
15
+
16
+ def request(path:, payload:, verb: "post")
17
+ http.request(
18
+ path: path,
19
+ payload: payload,
20
+ verb: verb,
21
+ headers: headers
22
+ )
23
+ end
24
+
25
+ private
26
+
27
+ def headers
28
+ {
29
+ Ext::Transport::HEADER_CONTENT_TYPE => Ext::Transport::CONTENT_TYPE_MESSAGEPACK
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "ci_test_cycle"
4
+ require_relative "evp_proxy"
5
+ require_relative "../http"
6
+ require_relative "../../ext/transport"
7
+
8
+ module Datadog
9
+ module CI
10
+ module Transport
11
+ module Api
12
+ module Builder
13
+ def self.build_ci_test_cycle_api(settings)
14
+ dd_site = settings.site || Ext::Transport::DEFAULT_DD_SITE
15
+ url = settings.ci.agentless_url ||
16
+ "https://#{Ext::Transport::TEST_VISIBILITY_INTAKE_HOST_PREFIX}.#{dd_site}:443"
17
+
18
+ uri = URI.parse(url)
19
+ raise "Invalid agentless mode URL: #{url}" if uri.host.nil?
20
+
21
+ http = Datadog::CI::Transport::HTTP.new(
22
+ host: uri.host,
23
+ port: uri.port,
24
+ ssl: uri.scheme == "https" || uri.port == 443,
25
+ compress: true
26
+ )
27
+
28
+ CiTestCycle.new(api_key: settings.api_key, http: http)
29
+ end
30
+
31
+ def self.build_evp_proxy_api(agent_settings)
32
+ http = Datadog::CI::Transport::HTTP.new(
33
+ host: agent_settings.hostname,
34
+ port: agent_settings.port,
35
+ ssl: agent_settings.ssl,
36
+ timeout: agent_settings.timeout_seconds,
37
+ compress: false
38
+ )
39
+
40
+ EvpProxy.new(http: http)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../../ext/transport"
5
+
6
+ module Datadog
7
+ module CI
8
+ module Transport
9
+ module Api
10
+ class CiTestCycle < Base
11
+ attr_reader :api_key
12
+
13
+ def initialize(api_key:, http:)
14
+ @api_key = api_key
15
+
16
+ super(http: http)
17
+ end
18
+
19
+ private
20
+
21
+ def headers
22
+ headers = super
23
+ headers[Ext::Transport::HEADER_DD_API_KEY] = api_key
24
+ headers
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "datadog/core/environment/container"
4
+
5
+ require_relative "base"
6
+ require_relative "../../ext/transport"
7
+
8
+ module Datadog
9
+ module CI
10
+ module Transport
11
+ module Api
12
+ class EvpProxy < Base
13
+ def request(path:, payload:, verb: "post")
14
+ path = "#{Ext::Transport::EVP_PROXY_PATH_PREFIX}#{path.sub(/^\//, "")}"
15
+
16
+ super(
17
+ path: path,
18
+ payload: payload,
19
+ verb: verb
20
+ )
21
+ end
22
+
23
+ private
24
+
25
+ def container_id
26
+ return @container_id if defined?(@container_id)
27
+
28
+ @container_id = Datadog::Core::Environment::Container.container_id
29
+ end
30
+
31
+ def headers
32
+ headers = super
33
+ headers[Ext::Transport::HEADER_EVP_SUBDOMAIN] = Ext::Transport::TEST_VISIBILITY_INTAKE_HOST_PREFIX
34
+
35
+ c_id = container_id
36
+ headers[Ext::Transport::HEADER_CONTAINER_ID] = c_id unless c_id.nil?
37
+
38
+ headers
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -10,9 +10,11 @@ module Datadog
10
10
  module_function
11
11
 
12
12
  def compress(input)
13
- gzip_writer = Zlib::GzipWriter.new(StringIO.new)
13
+ sio = StringIO.new
14
+ gzip_writer = Zlib::GzipWriter.new(sio, Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY)
14
15
  gzip_writer << input
15
- gzip_writer.close.string
16
+ gzip_writer.close
17
+ sio.string
16
18
  end
17
19
  end
18
20
  end
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "net/http"
3
+ require "delegate"
4
+ require "datadog/core/transport/http/adapters/net"
5
+ require "datadog/core/transport/http/env"
6
+ require "datadog/core/transport/request"
4
7
 
5
8
  require_relative "gzip"
6
9
  require_relative "../ext/transport"
@@ -26,126 +29,47 @@ module Datadog
26
29
  @compress = compress.nil? ? false : compress
27
30
  end
28
31
 
29
- def request(path:, payload:, headers:, method: "post")
30
- raise "Unknown method #{method}" unless respond_to?(method, true)
31
-
32
+ def request(path:, payload:, headers:, verb: "post")
32
33
  if compress
33
34
  headers[Ext::Transport::HEADER_CONTENT_ENCODING] = Ext::Transport::CONTENT_ENCODING_GZIP
34
35
  payload = Gzip.compress(payload)
35
36
  end
36
37
 
37
38
  Datadog.logger.debug do
38
- "Sending #{method} request: host=#{host}; port=#{port}; ssl_enabled=#{ssl}; " \
39
+ "Sending #{verb} request: host=#{host}; port=#{port}; ssl_enabled=#{ssl}; " \
39
40
  "compression_enabled=#{compress}; path=#{path}; payload_size=#{payload.size}"
40
41
  end
41
42
 
42
- send(method, path: path, payload: payload, headers: headers)
43
+ ResponseDecorator.new(
44
+ adapter.call(
45
+ build_env(path: path, payload: payload, headers: headers, verb: verb)
46
+ )
47
+ )
43
48
  end
44
49
 
45
50
  private
46
51
 
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)
52
+ def build_env(path:, payload:, headers:, verb:)
53
+ env = Datadog::Core::Transport::HTTP::Env.new(
54
+ Datadog::Core::Transport::Request.new
55
+ )
56
+ env.body = payload
57
+ env.path = path
58
+ env.headers = headers
59
+ env.verb = verb
60
+ env
54
61
  end
55
62
 
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)
63
+ def adapter
64
+ @adapter ||= Datadog::Core::Transport::HTTP::Adapters::Net.new(host, port, timeout: timeout, ssl: ssl)
69
65
  end
70
66
 
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
-
67
+ # this is needed because Datadog::Tracing::Writer is not fully compatiple with Datadog::Core::Transport
68
+ # TODO: remove before 1.0 when CI implements its own worker
69
+ class ResponseDecorator < ::SimpleDelegator
111
70
  def trace_count
112
71
  0
113
72
  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
73
  end
150
74
  end
151
75
  end
@@ -4,7 +4,7 @@ module Datadog
4
4
  module CI
5
5
  module VERSION
6
6
  MAJOR = "0"
7
- MINOR = "2"
7
+ MINOR = "3"
8
8
  PATCH = "0"
9
9
  PRE = nil
10
10
  BUILD = nil
@@ -6,7 +6,9 @@ module Datadog
6
6
 
7
7
  def activate_ci!: (untyped settings) -> untyped
8
8
 
9
- def build_agentless_transport: (untyped settings) -> Datadog::CI::TestVisibility::Transport
9
+ def build_agentless_transport: (untyped settings) -> Datadog::CI::TestVisibility::Transport?
10
+ def build_evp_proxy_transport: (untyped settings, untyped agent_settings) -> Datadog::CI::TestVisibility::Transport
11
+ def can_use_evp_proxy?: (untyped settings, untyped agent_settings) -> bool
10
12
  end
11
13
  end
12
14
  end
@@ -0,0 +1,19 @@
1
+ module Datadog
2
+ module CI
3
+ module Ext
4
+ module Environment
5
+ module Providers
6
+ class AwsCodePipeline < Base
7
+ def self.handles?: (Hash[String, String?] env) -> bool
8
+
9
+ def provider_name: () -> "awscodepipeline"
10
+
11
+ def pipeline_id: () -> String?
12
+
13
+ def ci_env_vars: () -> String?
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -8,6 +8,8 @@ module Datadog
8
8
  @branch: String?
9
9
  @tag: String?
10
10
 
11
+ def self.handles?: (Hash[String, String?] env) -> bool
12
+
11
13
  def initialize: (Hash[String, String?] env) -> void
12
14
 
13
15
  def job_name: () -> nil
@@ -3,7 +3,7 @@ module Datadog
3
3
  module Ext
4
4
  module Environment
5
5
  module Providers
6
- PROVIDERS: ::Array[[String, untyped]]
6
+ PROVIDERS: ::Array[untyped]
7
7
 
8
8
  def self.for_environment: (Hash[String, String?] env) -> Providers::Base
9
9
  end
@@ -2,12 +2,20 @@ module Datadog
2
2
  module CI
3
3
  module Ext
4
4
  module Transport
5
+ DEFAULT_DD_SITE: "datadoghq.com"
6
+
5
7
  HEADER_DD_API_KEY: "DD-API-KEY"
6
8
 
7
9
  HEADER_CONTENT_TYPE: "Content-Type"
8
10
 
9
11
  HEADER_CONTENT_ENCODING: "Content-Encoding"
10
12
 
13
+ HEADER_EVP_SUBDOMAIN: "X-Datadog-EVP-Subdomain"
14
+
15
+ HEADER_CONTAINER_ID: "Datadog-Container-ID"
16
+
17
+ EVP_PROXY_PATH_PREFIX: "/evp_proxy/v2/"
18
+
11
19
  TEST_VISIBILITY_INTAKE_HOST_PREFIX: "citestcycle-intake"
12
20
 
13
21
  TEST_VISIBILITY_INTAKE_PATH: "/api/v2/citestcycle"
@@ -5,30 +5,26 @@ module Datadog
5
5
  DEFAULT_MAX_PAYLOAD_SIZE: Integer
6
6
 
7
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
8
+ attr_reader dd_env: String?
9
+ attr_reader api: Datadog::CI::Transport::Api::Base
11
10
  attr_reader max_payload_size: Integer
12
11
 
13
- @api_key: String
14
- @env: String?
15
- @http: Datadog::CI::Transport::HTTP
12
+ @dd_env: String?
16
13
  @serializers_factory: singleton(Datadog::CI::TestVisibility::Serializers::Factories::TestLevel)
17
14
  @max_payload_size: Integer
18
15
 
19
16
  def initialize: (
20
- api_key: String,
21
- url: ::String,
22
- ?env: ::String?,
17
+ api: Datadog::CI::Transport::Api::Base,
18
+ ?dd_env: ::String?,
23
19
  ?serializers_factory: singleton(Datadog::CI::TestVisibility::Serializers::Factories::TestLevel),
24
20
  ?max_payload_size: Integer
25
21
  ) -> void
26
22
 
27
- def send_traces: (Array[Datadog::Tracing::TraceSegment] traces) -> ::Array[Datadog::CI::Transport::HTTP::Response]
23
+ def send_traces: (Array[Datadog::Tracing::TraceSegment] traces) -> ::Array[Datadog::CI::Transport::HTTP::ResponseDecorator]
28
24
 
29
25
  private
30
26
 
31
- def send_payload: (String encoded_payload) -> Datadog::CI::Transport::HTTP::Response
27
+ def send_payload: (String encoded_payload) -> Datadog::CI::Transport::HTTP::ResponseDecorator
32
28
  def pack_events: (Array[String] encoded_events) -> String
33
29
  def encode_traces: (Array[Datadog::Tracing::TraceSegment] traces) -> ::Array[String]
34
30
  def encode_span: (Datadog::Tracing::TraceSegment trace, Datadog::Tracing::Span span) -> String?
@@ -0,0 +1,21 @@
1
+ module Datadog
2
+ module CI
3
+ module Transport
4
+ module Api
5
+ class Base
6
+ attr_reader http: Datadog::CI::Transport::HTTP
7
+
8
+ @http: Datadog::CI::Transport::HTTP
9
+
10
+ def initialize: (http: Datadog::CI::Transport::HTTP) -> void
11
+
12
+ def request: (path: String, payload: String, ?verb: ::String) -> untyped
13
+
14
+ private
15
+
16
+ def headers: () -> Hash[String, String]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ module Datadog
2
+ module CI
3
+ module Transport
4
+ module Api
5
+ module Builder
6
+ def self.build_ci_test_cycle_api: (untyped settings) -> Datadog::CI::Transport::Api::CiTestCycle
7
+ def self.build_evp_proxy_api: (untyped agent_settings) -> Datadog::CI::Transport::Api::EvpProxy
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module Datadog
2
+ module CI
3
+ module Transport
4
+ module Api
5
+ class CiTestCycle < Base
6
+ attr_reader api_key: String
7
+
8
+ @api_key: String
9
+
10
+ def initialize: (api_key: String, http: Datadog::CI::Transport::HTTP) -> void
11
+
12
+ def request: (path: String, payload: String, ?verb: ::String) -> Datadog::CI::Transport::HTTP::ResponseDecorator
13
+
14
+ private
15
+
16
+ def headers: () -> Hash[String, String]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module Datadog
2
+ module CI
3
+ module Transport
4
+ module Api
5
+ class EvpProxy < Base
6
+ @container_id: String?
7
+
8
+ def request: (path: String, payload: String, ?verb: ::String) -> Datadog::CI::Transport::HTTP::ResponseDecorator
9
+
10
+ private
11
+
12
+ def container_id: () -> String?
13
+
14
+ def headers: () -> Hash[String, String]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,7 +1,12 @@
1
+ class SimpleDelegator
2
+ end
3
+
1
4
  module Datadog
2
5
  module CI
3
6
  module Transport
4
7
  class HTTP
8
+ @adapter: Datadog::Core::Transport::HTTP::Adapters::Net
9
+
5
10
  attr_reader host: String
6
11
  attr_reader port: Integer?
7
12
  attr_reader ssl: bool
@@ -12,50 +17,20 @@ module Datadog
12
17
 
13
18
  def initialize: (host: String, ?port: Integer?, ?ssl: bool, ?timeout: Integer, ?compress: bool) -> void
14
19
 
15
- def request: (?method: String, payload: String, headers: Hash[String, String], path: String) -> Response
20
+ def request: (?verb: String, payload: String, headers: Hash[String, String], path: String) -> ResponseDecorator
16
21
 
17
22
  private
18
23
 
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
24
+ def adapter: () -> Datadog::Core::Transport::HTTP::Adapters::Net
33
25
 
34
- def unsupported?: () -> bool
26
+ def build_env: (payload: String, headers: Hash[String, String], path: String, verb: String) -> Datadog::Core::Transport::HTTP::Env
35
27
 
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
28
+ class ResponseDecorator < ::SimpleDelegator
29
+ def initialize: (untyped anything) -> void
30
+ def trace_count: () -> Integer
57
31
  end
58
32
  end
59
33
  end
60
34
  end
61
35
  end
36
+
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: 0.2.0
4
+ version: 0.3.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: 2023-10-05 00:00:00.000000000 Z
11
+ date: 2023-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -67,6 +67,7 @@ files:
67
67
  - lib/datadog/ci/ext/environment/extractor.rb
68
68
  - lib/datadog/ci/ext/environment/providers.rb
69
69
  - lib/datadog/ci/ext/environment/providers/appveyor.rb
70
+ - lib/datadog/ci/ext/environment/providers/aws_code_pipeline.rb
70
71
  - lib/datadog/ci/ext/environment/providers/azure.rb
71
72
  - lib/datadog/ci/ext/environment/providers/base.rb
72
73
  - lib/datadog/ci/ext/environment/providers/bitbucket.rb
@@ -94,6 +95,10 @@ files:
94
95
  - lib/datadog/ci/test_visibility/serializers/span.rb
95
96
  - lib/datadog/ci/test_visibility/serializers/test_v1.rb
96
97
  - lib/datadog/ci/test_visibility/transport.rb
98
+ - lib/datadog/ci/transport/api/base.rb
99
+ - lib/datadog/ci/transport/api/builder.rb
100
+ - lib/datadog/ci/transport/api/ci_test_cycle.rb
101
+ - lib/datadog/ci/transport/api/evp_proxy.rb
97
102
  - lib/datadog/ci/transport/gzip.rb
98
103
  - lib/datadog/ci/transport/http.rb
99
104
  - lib/datadog/ci/utils/git.rb
@@ -124,6 +129,7 @@ files:
124
129
  - sig/datadog/ci/ext/environment/extractor.rbs
125
130
  - sig/datadog/ci/ext/environment/providers.rbs
126
131
  - sig/datadog/ci/ext/environment/providers/appveyor.rbs
132
+ - sig/datadog/ci/ext/environment/providers/aws_code_pipeline.rbs
127
133
  - sig/datadog/ci/ext/environment/providers/azure.rbs
128
134
  - sig/datadog/ci/ext/environment/providers/base.rbs
129
135
  - sig/datadog/ci/ext/environment/providers/bitbucket.rbs
@@ -151,6 +157,10 @@ files:
151
157
  - sig/datadog/ci/test_visibility/serializers/span.rbs
152
158
  - sig/datadog/ci/test_visibility/serializers/test_v1.rbs
153
159
  - sig/datadog/ci/test_visibility/transport.rbs
160
+ - sig/datadog/ci/transport/api/base.rbs
161
+ - sig/datadog/ci/transport/api/builder.rbs
162
+ - sig/datadog/ci/transport/api/ci_test_cycle.rbs
163
+ - sig/datadog/ci/transport/api/evp_proxy.rbs
154
164
  - sig/datadog/ci/transport/gzip.rbs
155
165
  - sig/datadog/ci/transport/http.rbs
156
166
  - sig/datadog/ci/utils/git.rbs
@@ -181,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
191
  - !ruby/object:Gem::Version
182
192
  version: 2.0.0
183
193
  requirements: []
184
- rubygems_version: 3.4.18
194
+ rubygems_version: 3.4.21
185
195
  signing_key:
186
196
  specification_version: 4
187
197
  summary: Datadog CI visibility for your ruby application