datadog-ci 0.2.0 → 0.3.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 (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