ddtrace 0.38.0 → 0.43.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 (194) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +56 -0
  3. data/.github/workflows/add-milestone-to-pull-requests.yml +42 -0
  4. data/.github/workflows/create-next-milestone.yml +20 -0
  5. data/.gitlab-ci.yml +1 -0
  6. data/.simplecov +38 -0
  7. data/Appraisals +293 -105
  8. data/CHANGELOG.md +192 -1
  9. data/CONTRIBUTING.md +2 -2
  10. data/Rakefile +554 -480
  11. data/ddtrace.gemspec +3 -0
  12. data/docs/DevelopmentGuide.md +28 -2
  13. data/docs/GettingStarted.md +207 -82
  14. data/lib/ddtrace.rb +4 -0
  15. data/lib/ddtrace/buffer.rb +259 -52
  16. data/lib/ddtrace/configuration.rb +55 -5
  17. data/lib/ddtrace/configuration/components.rb +4 -7
  18. data/lib/ddtrace/configuration/options.rb +3 -1
  19. data/lib/ddtrace/configuration/settings.rb +18 -6
  20. data/lib/ddtrace/context.rb +18 -0
  21. data/lib/ddtrace/context_provider.rb +17 -5
  22. data/lib/ddtrace/contrib/action_cable/configuration/settings.rb +7 -2
  23. data/lib/ddtrace/contrib/action_cable/ext.rb +5 -2
  24. data/lib/ddtrace/contrib/action_pack/configuration/settings.rb +7 -2
  25. data/lib/ddtrace/contrib/action_pack/ext.rb +5 -2
  26. data/lib/ddtrace/contrib/action_view/configuration/settings.rb +7 -2
  27. data/lib/ddtrace/contrib/action_view/ext.rb +5 -2
  28. data/lib/ddtrace/contrib/active_model_serializers/configuration/settings.rb +7 -2
  29. data/lib/ddtrace/contrib/active_model_serializers/ext.rb +5 -2
  30. data/lib/ddtrace/contrib/active_record/configuration/settings.rb +7 -2
  31. data/lib/ddtrace/contrib/active_record/events/sql.rb +4 -0
  32. data/lib/ddtrace/contrib/active_record/ext.rb +5 -2
  33. data/lib/ddtrace/contrib/active_support/cache/instrumentation.rb +104 -3
  34. data/lib/ddtrace/contrib/active_support/cache/patcher.rb +21 -0
  35. data/lib/ddtrace/contrib/active_support/configuration/settings.rb +7 -2
  36. data/lib/ddtrace/contrib/active_support/ext.rb +8 -2
  37. data/lib/ddtrace/contrib/active_support/notifications/event.rb +10 -0
  38. data/lib/ddtrace/contrib/active_support/notifications/subscription.rb +2 -2
  39. data/lib/ddtrace/contrib/aws/configuration/settings.rb +7 -2
  40. data/lib/ddtrace/contrib/aws/ext.rb +5 -2
  41. data/lib/ddtrace/contrib/aws/instrumentation.rb +6 -1
  42. data/lib/ddtrace/contrib/aws/patcher.rb +0 -1
  43. data/lib/ddtrace/contrib/concurrent_ruby/configuration/settings.rb +5 -0
  44. data/lib/ddtrace/contrib/concurrent_ruby/ext.rb +1 -0
  45. data/lib/ddtrace/contrib/configurable.rb +2 -0
  46. data/lib/ddtrace/contrib/configuration/resolvers/pattern_resolver.rb +4 -5
  47. data/lib/ddtrace/contrib/configuration/settings.rb +1 -0
  48. data/lib/ddtrace/contrib/cucumber/configuration/settings.rb +38 -0
  49. data/lib/ddtrace/contrib/cucumber/ext.rb +19 -0
  50. data/lib/ddtrace/contrib/cucumber/formatter.rb +104 -0
  51. data/lib/ddtrace/contrib/cucumber/instrumentation.rb +24 -0
  52. data/lib/ddtrace/contrib/cucumber/integration.rb +40 -0
  53. data/lib/ddtrace/contrib/cucumber/patcher.rb +23 -0
  54. data/lib/ddtrace/contrib/dalli/configuration/settings.rb +7 -2
  55. data/lib/ddtrace/contrib/dalli/ext.rb +5 -2
  56. data/lib/ddtrace/contrib/dalli/instrumentation.rb +4 -0
  57. data/lib/ddtrace/contrib/delayed_job/configuration/settings.rb +9 -2
  58. data/lib/ddtrace/contrib/delayed_job/ext.rb +7 -2
  59. data/lib/ddtrace/contrib/delayed_job/plugin.rb +39 -15
  60. data/lib/ddtrace/contrib/elasticsearch/configuration/settings.rb +7 -2
  61. data/lib/ddtrace/contrib/elasticsearch/ext.rb +5 -2
  62. data/lib/ddtrace/contrib/elasticsearch/patcher.rb +4 -0
  63. data/lib/ddtrace/contrib/ethon/configuration/settings.rb +7 -2
  64. data/lib/ddtrace/contrib/ethon/easy_patch.rb +4 -2
  65. data/lib/ddtrace/contrib/ethon/ext.rb +5 -2
  66. data/lib/ddtrace/contrib/ethon/multi_patch.rb +4 -0
  67. data/lib/ddtrace/contrib/excon/configuration/settings.rb +7 -2
  68. data/lib/ddtrace/contrib/excon/ext.rb +5 -2
  69. data/lib/ddtrace/contrib/excon/middleware.rb +11 -1
  70. data/lib/ddtrace/contrib/extensions.rb +1 -1
  71. data/lib/ddtrace/contrib/faraday/configuration/settings.rb +7 -2
  72. data/lib/ddtrace/contrib/faraday/ext.rb +5 -2
  73. data/lib/ddtrace/contrib/faraday/middleware.rb +4 -0
  74. data/lib/ddtrace/contrib/faraday/patcher.rb +13 -4
  75. data/lib/ddtrace/contrib/grape/configuration/settings.rb +14 -3
  76. data/lib/ddtrace/contrib/grape/endpoint.rb +24 -7
  77. data/lib/ddtrace/contrib/grape/ext.rb +5 -2
  78. data/lib/ddtrace/contrib/graphql/configuration/settings.rb +7 -2
  79. data/lib/ddtrace/contrib/graphql/ext.rb +5 -2
  80. data/lib/ddtrace/contrib/grpc/configuration/settings.rb +7 -2
  81. data/lib/ddtrace/contrib/grpc/datadog_interceptor/client.rb +5 -1
  82. data/lib/ddtrace/contrib/grpc/datadog_interceptor/server.rb +4 -0
  83. data/lib/ddtrace/contrib/grpc/ext.rb +5 -2
  84. data/lib/ddtrace/contrib/http/configuration/settings.rb +7 -2
  85. data/lib/ddtrace/contrib/http/ext.rb +5 -2
  86. data/lib/ddtrace/contrib/http/instrumentation.rb +6 -2
  87. data/lib/ddtrace/contrib/httprb/configuration/settings.rb +7 -2
  88. data/lib/ddtrace/contrib/httprb/ext.rb +5 -2
  89. data/lib/ddtrace/contrib/httprb/instrumentation.rb +8 -8
  90. data/lib/ddtrace/contrib/kafka/configuration/settings.rb +7 -2
  91. data/lib/ddtrace/contrib/kafka/event.rb +1 -1
  92. data/lib/ddtrace/contrib/kafka/ext.rb +5 -2
  93. data/lib/ddtrace/contrib/mongodb/configuration/settings.rb +7 -2
  94. data/lib/ddtrace/contrib/mongodb/ext.rb +5 -2
  95. data/lib/ddtrace/contrib/mongodb/subscribers.rb +4 -0
  96. data/lib/ddtrace/contrib/mysql2/configuration/settings.rb +7 -2
  97. data/lib/ddtrace/contrib/mysql2/ext.rb +5 -2
  98. data/lib/ddtrace/contrib/mysql2/instrumentation.rb +4 -0
  99. data/lib/ddtrace/contrib/presto/configuration/settings.rb +7 -2
  100. data/lib/ddtrace/contrib/presto/ext.rb +5 -2
  101. data/lib/ddtrace/contrib/presto/instrumentation.rb +3 -0
  102. data/lib/ddtrace/contrib/que/configuration/settings.rb +43 -0
  103. data/lib/ddtrace/contrib/que/ext.rb +30 -0
  104. data/lib/ddtrace/contrib/que/integration.rb +42 -0
  105. data/lib/ddtrace/contrib/que/patcher.rb +24 -0
  106. data/lib/ddtrace/contrib/que/tracer.rb +57 -0
  107. data/lib/ddtrace/contrib/racecar/configuration/settings.rb +7 -2
  108. data/lib/ddtrace/contrib/racecar/event.rb +4 -0
  109. data/lib/ddtrace/contrib/racecar/events.rb +2 -0
  110. data/lib/ddtrace/contrib/racecar/events/consume.rb +27 -0
  111. data/lib/ddtrace/contrib/racecar/ext.rb +6 -2
  112. data/lib/ddtrace/contrib/rack/configuration/settings.rb +7 -2
  113. data/lib/ddtrace/contrib/rack/ext.rb +5 -2
  114. data/lib/ddtrace/contrib/rack/middlewares.rb +2 -0
  115. data/lib/ddtrace/contrib/rails/configuration/settings.rb +12 -2
  116. data/lib/ddtrace/contrib/rails/ext.rb +6 -2
  117. data/lib/ddtrace/contrib/rails/log_injection.rb +81 -0
  118. data/lib/ddtrace/contrib/rails/middlewares.rb +7 -2
  119. data/lib/ddtrace/contrib/rails/patcher.rb +29 -0
  120. data/lib/ddtrace/contrib/rake/configuration/settings.rb +7 -3
  121. data/lib/ddtrace/contrib/rake/ext.rb +5 -2
  122. data/lib/ddtrace/contrib/redis/configuration/settings.rb +7 -2
  123. data/lib/ddtrace/contrib/redis/ext.rb +5 -2
  124. data/lib/ddtrace/contrib/redis/tags.rb +4 -0
  125. data/lib/ddtrace/contrib/resque/configuration/settings.rb +8 -2
  126. data/lib/ddtrace/contrib/resque/ext.rb +5 -2
  127. data/lib/ddtrace/contrib/resque/integration.rb +1 -1
  128. data/lib/ddtrace/contrib/resque/resque_job.rb +1 -1
  129. data/lib/ddtrace/contrib/rest_client/configuration/settings.rb +7 -2
  130. data/lib/ddtrace/contrib/rest_client/ext.rb +5 -2
  131. data/lib/ddtrace/contrib/rest_client/request_patch.rb +4 -0
  132. data/lib/ddtrace/contrib/rspec/configuration/settings.rb +38 -0
  133. data/lib/ddtrace/contrib/rspec/example.rb +61 -0
  134. data/lib/ddtrace/contrib/rspec/example_group.rb +61 -0
  135. data/lib/ddtrace/contrib/rspec/ext.rb +19 -0
  136. data/lib/ddtrace/contrib/rspec/integration.rb +41 -0
  137. data/lib/ddtrace/contrib/rspec/patcher.rb +25 -0
  138. data/lib/ddtrace/contrib/sequel/configuration/settings.rb +7 -2
  139. data/lib/ddtrace/contrib/sequel/database.rb +3 -1
  140. data/lib/ddtrace/contrib/sequel/dataset.rb +3 -2
  141. data/lib/ddtrace/contrib/sequel/ext.rb +6 -2
  142. data/lib/ddtrace/contrib/sequel/utils.rb +35 -6
  143. data/lib/ddtrace/contrib/shoryuken/configuration/settings.rb +8 -2
  144. data/lib/ddtrace/contrib/shoryuken/ext.rb +5 -2
  145. data/lib/ddtrace/contrib/shoryuken/tracer.rb +4 -1
  146. data/lib/ddtrace/contrib/sidekiq/configuration/settings.rb +8 -2
  147. data/lib/ddtrace/contrib/sidekiq/ext.rb +5 -2
  148. data/lib/ddtrace/contrib/sidekiq/server_tracer.rb +4 -1
  149. data/lib/ddtrace/contrib/sinatra/configuration/settings.rb +7 -2
  150. data/lib/ddtrace/contrib/sinatra/env.rb +5 -4
  151. data/lib/ddtrace/contrib/sinatra/ext.rb +5 -2
  152. data/lib/ddtrace/contrib/sinatra/tracer.rb +21 -42
  153. data/lib/ddtrace/contrib/sinatra/tracer_middleware.rb +50 -23
  154. data/lib/ddtrace/contrib/sneakers/configuration/settings.rb +33 -0
  155. data/lib/ddtrace/contrib/sneakers/ext.rb +22 -0
  156. data/lib/ddtrace/contrib/sneakers/integration.rb +41 -0
  157. data/lib/ddtrace/contrib/sneakers/patcher.rb +24 -0
  158. data/lib/ddtrace/contrib/sneakers/tracer.rb +55 -0
  159. data/lib/ddtrace/contrib/status_code_matcher.rb +67 -0
  160. data/lib/ddtrace/contrib/sucker_punch/configuration/settings.rb +7 -2
  161. data/lib/ddtrace/contrib/sucker_punch/ext.rb +5 -2
  162. data/lib/ddtrace/diagnostics/environment_logger.rb +1 -1
  163. data/lib/ddtrace/environment.rb +14 -4
  164. data/lib/ddtrace/ext/app_types.rb +1 -0
  165. data/lib/ddtrace/ext/ci.rb +265 -0
  166. data/lib/ddtrace/ext/diagnostics.rb +2 -1
  167. data/lib/ddtrace/ext/distributed.rb +8 -2
  168. data/lib/ddtrace/ext/git.rb +12 -0
  169. data/lib/ddtrace/ext/integration.rb +8 -0
  170. data/lib/ddtrace/ext/runtime.rb +2 -0
  171. data/lib/ddtrace/ext/test.rb +24 -0
  172. data/lib/ddtrace/ext/transport.rb +1 -0
  173. data/lib/ddtrace/logger.rb +1 -1
  174. data/lib/ddtrace/opentracer/distributed_headers.rb +1 -1
  175. data/lib/ddtrace/propagation/grpc_propagator.rb +18 -6
  176. data/lib/ddtrace/runtime/identity.rb +4 -5
  177. data/lib/ddtrace/runtime/metrics.rb +24 -6
  178. data/lib/ddtrace/sampler.rb +2 -2
  179. data/lib/ddtrace/sampling/rate_limiter.rb +65 -16
  180. data/lib/ddtrace/span.rb +152 -27
  181. data/lib/ddtrace/tracer.rb +25 -13
  182. data/lib/ddtrace/transport/http.rb +15 -0
  183. data/lib/ddtrace/transport/http/adapters/net.rb +8 -2
  184. data/lib/ddtrace/transport/http/adapters/test.rb +2 -0
  185. data/lib/ddtrace/transport/http/statistics.rb +14 -1
  186. data/lib/ddtrace/transport/traces.rb +7 -2
  187. data/lib/ddtrace/utils.rb +16 -13
  188. data/lib/ddtrace/utils/forking.rb +52 -0
  189. data/lib/ddtrace/version.rb +1 -1
  190. data/lib/ddtrace/workers/async.rb +2 -2
  191. data/lib/ddtrace/workers/loop.rb +1 -1
  192. data/lib/ddtrace/workers/polling.rb +1 -1
  193. data/lib/ddtrace/writer.rb +19 -1
  194. metadata +53 -6
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ddtrace/contrib/analytics'
4
+
5
+ module Datadog
6
+ module Contrib
7
+ module Sneakers
8
+ # Tracer is a Sneakers server-side middleware which traces executed jobs
9
+ class Tracer
10
+ def initialize(app, *args)
11
+ @app = app
12
+ @args = args
13
+ end
14
+
15
+ def call(deserialized_msg, delivery_info, metadata, handler)
16
+ trace_options = {
17
+ service: configuration[:service_name],
18
+ span_type: Datadog::Ext::AppTypes::WORKER,
19
+ on_error: configuration[:error_handler]
20
+ }
21
+
22
+ tracer.trace(Ext::SPAN_JOB, trace_options) do |request_span|
23
+ # Set analytics sample rate
24
+ if Datadog::Contrib::Analytics.enabled?(configuration[:analytics_enabled])
25
+ Datadog::Contrib::Analytics.set_sample_rate(request_span, configuration[:analytics_sample_rate])
26
+ end
27
+
28
+ # Measure service stats
29
+ Contrib::Analytics.set_measured(request_span)
30
+
31
+ request_span.resource = @app.to_proc.binding.eval('self.class').to_s
32
+ request_span.set_tag(Ext::TAG_JOB_ROUTING_KEY, delivery_info.routing_key)
33
+ request_span.set_tag(Ext::TAG_JOB_QUEUE, delivery_info.consumer.queue.name)
34
+
35
+ if configuration[:tag_body]
36
+ request_span.set_tag(Ext::TAG_JOB_BODY, deserialized_msg)
37
+ end
38
+
39
+ @app.call(deserialized_msg, delivery_info, metadata, handler)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def tracer
46
+ configuration[:tracer]
47
+ end
48
+
49
+ def configuration
50
+ Datadog.configuration[:sneakers]
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,67 @@
1
+ require 'set'
2
+ require 'ddtrace/ext/http'
3
+
4
+ module Datadog
5
+ module Contrib
6
+ # Contains methods helpful for tracing/annotating HTTP request libraries
7
+ class StatusCodeMatcher
8
+ REGEX_PARSER = /^\d{3}(?:-\d{3})?(?:,\d{3}(?:-\d{3})?)*$/
9
+
10
+ def initialize(range)
11
+ @error_response_range = range
12
+ set_range
13
+ end
14
+
15
+ def include?(exception_status)
16
+ set_range.include?(exception_status)
17
+ end
18
+
19
+ def to_s
20
+ @error_response_range.to_s
21
+ end
22
+
23
+ private
24
+
25
+ def set_range
26
+ @datadog_set ||= begin
27
+ set = Set.new
28
+ handle_statuses.each do |statuses|
29
+ status = statuses.to_s.split('-')
30
+ if status.length == 1
31
+ set.add(Integer(status[0]))
32
+ elsif status.length == 2
33
+ min, max = status.minmax
34
+ Array(min..max).each do |i|
35
+ set.add(Integer(i))
36
+ end
37
+ end
38
+ end
39
+ set
40
+ end
41
+ @datadog_set
42
+ end
43
+
44
+ def error_responses
45
+ return @error_response_range if @error_response_range.is_a?(String) && !@error_response_range.nil?
46
+ @error_response_range.join(',') if @error_response_range.is_a?(Array) && !@error_response_range.empty?
47
+ end
48
+
49
+ def handle_statuses
50
+ if error_responses
51
+ filter_error_responses = error_responses.gsub(/\s+/, '').split(',').select do |code|
52
+ if !code.to_s.match(REGEX_PARSER)
53
+ Datadog.logger.debug("Invalid config provided: #{code}. Must be formatted like '400-403,405,410-499'.")
54
+ next
55
+ else
56
+ true
57
+ end
58
+ end
59
+ filter_error_responses.empty? ? Datadog::Ext::HTTP::ERROR_RANGE.to_a : filter_error_responses
60
+ else
61
+ Datadog.logger.debug('No valid config was provided for :error_statuses - falling back to default.')
62
+ Datadog::Ext::HTTP::ERROR_RANGE.to_a
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -7,13 +7,18 @@ module Datadog
7
7
  module Configuration
8
8
  # Custom settings for the SuckerPunch integration
9
9
  class Settings < Contrib::Configuration::Settings
10
+ option :enabled do |o|
11
+ o.default { env_to_bool(Ext::ENV_ENABLED, true) }
12
+ o.lazy
13
+ end
14
+
10
15
  option :analytics_enabled do |o|
11
- o.default { env_to_bool(Ext::ENV_ANALYTICS_ENABLED, false) }
16
+ o.default { env_to_bool([Ext::ENV_ANALYTICS_ENABLED, Ext::ENV_ANALYTICS_ENABLED_OLD], false) }
12
17
  o.lazy
13
18
  end
14
19
 
15
20
  option :analytics_sample_rate do |o|
16
- o.default { env_to_float(Ext::ENV_ANALYTICS_SAMPLE_RATE, 1.0) }
21
+ o.default { env_to_float([Ext::ENV_ANALYTICS_SAMPLE_RATE, Ext::ENV_ANALYTICS_SAMPLE_RATE_OLD], 1.0) }
17
22
  o.lazy
18
23
  end
19
24
 
@@ -4,8 +4,11 @@ module Datadog
4
4
  # SuckerPunch integration constants
5
5
  module Ext
6
6
  APP = 'sucker_punch'.freeze
7
- ENV_ANALYTICS_ENABLED = 'DD_SUCKER_PUNCH_ANALYTICS_ENABLED'.freeze
8
- ENV_ANALYTICS_SAMPLE_RATE = 'DD_SUCKER_PUNCH_ANALYTICS_SAMPLE_RATE'.freeze
7
+ ENV_ENABLED = 'DD_TRACE_SUCKER_PUNCH_ENABLED'.freeze
8
+ ENV_ANALYTICS_ENABLED = 'DD_TRACE_SUCKER_PUNCH_ANALYTICS_ENABLED'.freeze
9
+ ENV_ANALYTICS_ENABLED_OLD = 'DD_SUCKER_PUNCH_ANALYTICS_ENABLED'.freeze
10
+ ENV_ANALYTICS_SAMPLE_RATE = 'DD_TRACE_SUCKER_PUNCH_ANALYTICS_SAMPLE_RATE'.freeze
11
+ ENV_ANALYTICS_SAMPLE_RATE_OLD = 'DD_SUCKER_PUNCH_ANALYTICS_SAMPLE_RATE'.freeze
9
12
  SERVICE_NAME = 'sucker_punch'.freeze
10
13
  SPAN_PERFORM = 'sucker_punch.perform'.freeze
11
14
  SPAN_PERFORM_ASYNC = 'sucker_punch.perform_async'.freeze
@@ -28,7 +28,7 @@ module Datadog
28
28
  private
29
29
 
30
30
  def log_environment!(line)
31
- Datadog.logger.warn("DATADOG TRACER CONFIGURATION - #{line}")
31
+ Datadog.logger.info("DATADOG TRACER CONFIGURATION - #{line}")
32
32
  end
33
33
 
34
34
  def log_error!(type, error)
@@ -6,24 +6,34 @@ module Datadog
6
6
  # Defines helper methods for environment
7
7
  module Helpers
8
8
  def env_to_bool(var, default = nil)
9
- ENV.key?(var) ? ENV[var].to_s.strip.downcase == 'true' : default
9
+ var = decode_array(var)
10
+ var && ENV.key?(var) ? ENV[var].to_s.strip.downcase == 'true' : default
10
11
  end
11
12
 
12
13
  def env_to_int(var, default = nil)
13
- ENV.key?(var) ? ENV[var].to_i : default
14
+ var = decode_array(var)
15
+ var && ENV.key?(var) ? ENV[var].to_i : default
14
16
  end
15
17
 
16
18
  def env_to_float(var, default = nil)
17
- ENV.key?(var) ? ENV[var].to_f : default
19
+ var = decode_array(var)
20
+ var && ENV.key?(var) ? ENV[var].to_f : default
18
21
  end
19
22
 
20
23
  def env_to_list(var, default = [])
21
- if ENV.key?(var)
24
+ var = decode_array(var)
25
+ if var && ENV.key?(var)
22
26
  ENV[var].split(',').map(&:strip)
23
27
  else
24
28
  default
25
29
  end
26
30
  end
31
+
32
+ private
33
+
34
+ def decode_array(var)
35
+ var.is_a?(Array) ? var.find { |env_var| ENV.key?(env_var) } : var
36
+ end
27
37
  end
28
38
 
29
39
  extend Helpers
@@ -6,6 +6,7 @@ module Datadog
6
6
  CACHE = 'cache'.freeze
7
7
  WORKER = 'worker'.freeze
8
8
  CUSTOM = 'custom'.freeze
9
+ TEST = 'test'.freeze
9
10
  end
10
11
  end
11
12
  end
@@ -0,0 +1,265 @@
1
+ require 'ddtrace/ext/git'
2
+
3
+ module Datadog
4
+ module Ext
5
+ # Defines constants for CI tags
6
+ # rubocop:disable Metrics/ModuleLength:
7
+ module CI
8
+ TAG_JOB_URL = 'ci.job.url'.freeze
9
+ TAG_PIPELINE_ID = 'ci.pipeline.id'.freeze
10
+ TAG_PIPELINE_NAME = 'ci.pipeline.name'.freeze
11
+ TAG_PIPELINE_NUMBER = 'ci.pipeline.number'.freeze
12
+ TAG_PIPELINE_URL = 'ci.pipeline.url'.freeze
13
+ TAG_PROVIDER_NAME = 'ci.provider.name'.freeze
14
+ TAG_WORKSPACE_PATH = 'ci.workspace_path'.freeze
15
+
16
+ PROVIDERS = [
17
+ ['APPVEYOR'.freeze, :extract_appveyor],
18
+ ['TF_BUILD'.freeze, :extract_azure_pipelines],
19
+ ['BITBUCKET_COMMIT'.freeze, :extract_bitbucket],
20
+ ['BUILDKITE'.freeze, :extract_buildkite],
21
+ ['CIRCLECI'.freeze, :extract_circle_ci],
22
+ ['GITHUB_SHA'.freeze, :extract_github_actions],
23
+ ['GITLAB_CI'.freeze, :extract_gitlab],
24
+ ['JENKINS_URL'.freeze, :extract_jenkins],
25
+ ['TEAMCITY_VERSION'.freeze, :extract_teamcity],
26
+ ['TRAVIS'.freeze, :extract_travis]
27
+ ].freeze
28
+
29
+ module_function
30
+
31
+ def tags(env)
32
+ provider = PROVIDERS.find { |c| env.key? c[0] }
33
+ return {} if provider.nil?
34
+
35
+ tags = send(provider[1], env)
36
+
37
+ tags[Git::TAG_TAG] = normalize_ref(tags[Git::TAG_TAG])
38
+ tags.delete(Git::TAG_BRANCH) unless tags[Git::TAG_TAG].nil?
39
+ tags[Git::TAG_BRANCH] = normalize_ref(tags[Git::TAG_BRANCH])
40
+ tags[Git::TAG_DEPRECATED_COMMIT_SHA] = tags[Git::TAG_COMMIT_SHA]
41
+ tags[Git::TAG_REPOSITORY_URL] = filter_sensitive_info(tags[Git::TAG_REPOSITORY_URL])
42
+
43
+ # Expand ~
44
+ workspace_path = tags[TAG_WORKSPACE_PATH]
45
+ if !workspace_path.nil? && (workspace_path == '~' || workspace_path.start_with?('~/'))
46
+ tags[TAG_WORKSPACE_PATH] = File.expand_path(workspace_path)
47
+ end
48
+ tags.reject { |_, v| v.nil? }
49
+ end
50
+
51
+ def normalize_ref(name)
52
+ refs = %r{^refs/(heads/)?}
53
+ origin = %r{^origin/}
54
+ tags = %r{^tags/}
55
+ name.gsub(refs, '').gsub(origin, '').gsub(tags, '') unless name.nil?
56
+ end
57
+
58
+ def filter_sensitive_info(url)
59
+ url.gsub(%r{(https?://)[^/]*@}, '\1') unless url.nil?
60
+ end
61
+
62
+ # CI providers
63
+
64
+ def extract_appveyor(env)
65
+ url = "https://ci.appveyor.com/project/#{env['APPVEYOR_REPO_NAME']}/builds/#{env['APPVEYOR_BUILD_ID']}"
66
+ {
67
+ TAG_PROVIDER_NAME => 'appveyor',
68
+ Git::TAG_REPOSITORY_URL => "https://github.com/#{env['APPVEYOR_REPO_NAME']}.git",
69
+ Git::TAG_COMMIT_SHA => env['APPVEYOR_REPO_COMMIT'],
70
+ TAG_WORKSPACE_PATH => env['APPVEYOR_BUILD_FOLDER'],
71
+ TAG_PIPELINE_ID => env['APPVEYOR_BUILD_ID'],
72
+ TAG_PIPELINE_NAME => env['APPVEYOR_REPO_NAME'],
73
+ TAG_PIPELINE_NUMBER => env['APPVEYOR_BUILD_NUMBER'],
74
+ TAG_PIPELINE_URL => url,
75
+ TAG_JOB_URL => url,
76
+ Git::TAG_BRANCH => (env['APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH'] || env['APPVEYOR_REPO_BRANCH']),
77
+ Git::TAG_TAG => env['APPVEYOR_REPO_TAG_NAME']
78
+ }
79
+ end
80
+
81
+ def extract_azure_pipelines(env)
82
+ if env['SYSTEM_TEAMFOUNDATIONSERVERURI'] && env['SYSTEM_TEAMPROJECT'] && env['BUILD_BUILDID']
83
+ base_url = "#{env['SYSTEM_TEAMFOUNDATIONSERVERURI']}#{env['SYSTEM_TEAMPROJECT']}" \
84
+ "/_build/results?buildId=#{env['BUILD_BUILDID']}"
85
+ pipeline_url = base_url + '&_a=summary'
86
+ job_url = base_url + "&view=logs&j=#{env['SYSTEM_JOBID']}&t=#{env['SYSTEM_TASKINSTANCEID']}"
87
+ else
88
+ pipeline_url = job_url = nil
89
+ end
90
+ branch_or_tag = (
91
+ env['SYSTEM_PULLREQUEST_SOURCEBRANCH'] || env['BUILD_SOURCEBRANCH'] || env['BUILD_SOURCEBRANCHNAME']
92
+ )
93
+ if branch_or_tag.include? 'tags/'
94
+ branch = nil
95
+ tag = branch_or_tag
96
+ else
97
+ branch = branch_or_tag
98
+ tag = nil
99
+ end
100
+ {
101
+ TAG_PROVIDER_NAME => 'azurepipelines',
102
+ TAG_WORKSPACE_PATH => env['BUILD_SOURCESDIRECTORY'],
103
+ TAG_PIPELINE_ID => env['BUILD_BUILDID'],
104
+ TAG_PIPELINE_NAME => env['BUILD_DEFINITIONNAME'],
105
+ TAG_PIPELINE_NUMBER => env['BUILD_BUILDID'],
106
+ TAG_PIPELINE_URL => pipeline_url,
107
+ TAG_JOB_URL => job_url,
108
+ Git::TAG_REPOSITORY_URL => (env['SYSTEM_PULLREQUEST_SOURCEREPOSITORYURI'] || env['BUILD_REPOSITORY_URI']),
109
+ Git::TAG_COMMIT_SHA => (env['SYSTEM_PULLREQUEST_SOURCECOMMITID'] || env['BUILD_SOURCEVERSION']),
110
+ Git::TAG_BRANCH => branch,
111
+ Git::TAG_TAG => tag
112
+ }
113
+ end
114
+
115
+ def extract_bitbucket(env)
116
+ url = "https://bitbucket.org/#{env['BITBUCKET_REPO_FULL_NAME']}/addon/pipelines/home#" \
117
+ "!/results/#{env['BITBUCKET_BUILD_NUMBER']}"
118
+ {
119
+ Git::TAG_BRANCH => env['BITBUCKET_BRANCH'],
120
+ Git::TAG_COMMIT_SHA => env['BITBUCKET_COMMIT'],
121
+ Git::TAG_REPOSITORY_URL => env['BITBUCKET_GIT_SSH_ORIGIN'],
122
+ Git::TAG_TAG => env['BITBUCKET_TAG'],
123
+ TAG_JOB_URL => url,
124
+ TAG_PIPELINE_ID => env['BITBUCKET_PIPELINE_UUID'] ? env['BITBUCKET_PIPELINE_UUID'].tr('{}', '') : None,
125
+ TAG_PIPELINE_NAME => env['BITBUCKET_REPO_FULL_NAME'],
126
+ TAG_PIPELINE_NUMBER => env['BITBUCKET_BUILD_NUMBER'],
127
+ TAG_PIPELINE_URL => url,
128
+ TAG_PROVIDER_NAME => 'bitbucket',
129
+ TAG_WORKSPACE_PATH => env['BITBUCKET_CLONE_DIR']
130
+ }
131
+ end
132
+
133
+ def extract_buildkite(env)
134
+ {
135
+ Git::TAG_BRANCH => env['BUILDKITE_BRANCH'],
136
+ Git::TAG_COMMIT_SHA => env['BUILDKITE_COMMIT'],
137
+ Git::TAG_REPOSITORY_URL => env['BUILDKITE_REPO'],
138
+ Git::TAG_TAG => env['BUILDKITE_TAG'],
139
+ TAG_PIPELINE_ID => env['BUILDKITE_BUILD_ID'],
140
+ TAG_PIPELINE_NAME => env['BUILDKITE_PIPELINE_SLUG'],
141
+ TAG_PIPELINE_NUMBER => env['BUILDKITE_BUILD_NUMBER'],
142
+ TAG_PIPELINE_URL => env['BUILDKITE_BUILD_URL'],
143
+ TAG_JOB_URL => "#{env['BUILDKITE_BUILD_URL']}##{env['BUILDKITE_JOB_ID']}",
144
+ TAG_PROVIDER_NAME => 'buildkite',
145
+ TAG_WORKSPACE_PATH => env['BUILDKITE_BUILD_CHECKOUT_PATH']
146
+ }
147
+ end
148
+
149
+ def extract_circle_ci(env)
150
+ {
151
+ Git::TAG_BRANCH => env['CIRCLE_BRANCH'],
152
+ Git::TAG_COMMIT_SHA => env['CIRCLE_SHA1'],
153
+ Git::TAG_REPOSITORY_URL => env['CIRCLE_REPOSITORY_URL'],
154
+ Git::TAG_TAG => env['CIRCLE_TAG'],
155
+ TAG_PIPELINE_ID => env['CIRCLE_WORKFLOW_ID'],
156
+ TAG_PIPELINE_NAME => env['CIRCLE_PROJECT_REPONAME'],
157
+ TAG_PIPELINE_NUMBER => env['CIRCLE_BUILD_NUM'],
158
+ TAG_PIPELINE_URL => env['CIRCLE_BUILD_URL'],
159
+ TAG_JOB_URL => env['CIRCLE_BUILD_URL'],
160
+ TAG_PROVIDER_NAME => 'circleci',
161
+ TAG_WORKSPACE_PATH => env['CIRCLE_WORKING_DIRECTORY']
162
+ }
163
+ end
164
+
165
+ def extract_github_actions(env)
166
+ branch_or_tag = (env['GITHUB_HEAD_REF'] || env['GITHUB_REF'])
167
+ if branch_or_tag.include? 'tags/'
168
+ branch = nil
169
+ tag = branch_or_tag
170
+ else
171
+ branch = branch_or_tag
172
+ tag = nil
173
+ end
174
+ {
175
+ Git::TAG_BRANCH => branch,
176
+ Git::TAG_COMMIT_SHA => env['GITHUB_SHA'],
177
+ Git::TAG_REPOSITORY_URL => "https://github.com/#{env['GITHUB_REPOSITORY']}.git",
178
+ Git::TAG_TAG => tag,
179
+ TAG_JOB_URL => "https://github.com/#{env['GITHUB_REPOSITORY']}/commit/#{env['GITHUB_SHA']}/checks",
180
+ TAG_PIPELINE_ID => env['GITHUB_RUN_ID'],
181
+ TAG_PIPELINE_NAME => env['GITHUB_WORKFLOW'],
182
+ TAG_PIPELINE_NUMBER => env['GITHUB_RUN_NUMBER'],
183
+ TAG_PIPELINE_URL => "https://github.com/#{env['GITHUB_REPOSITORY']}/commit/#{env['GITHUB_SHA']}/checks",
184
+ TAG_PROVIDER_NAME => 'github',
185
+ TAG_WORKSPACE_PATH => env['GITHUB_WORKSPACE']
186
+ }
187
+ end
188
+
189
+ def extract_gitlab(env)
190
+ url = env['CI_PIPELINE_URL']
191
+ url = url.gsub(%r{/-/pipelines/}, '/pipelines/') unless url.nil?
192
+ {
193
+ Git::TAG_BRANCH => env['CI_COMMIT_BRANCH'],
194
+ Git::TAG_COMMIT_SHA => env['CI_COMMIT_SHA'],
195
+ Git::TAG_REPOSITORY_URL => env['CI_REPOSITORY_URL'],
196
+ Git::TAG_TAG => env['CI_COMMIT_TAG'],
197
+ TAG_JOB_URL => env['CI_JOB_URL'],
198
+ TAG_PIPELINE_ID => env['CI_PIPELINE_ID'],
199
+ TAG_PIPELINE_NAME => env['CI_PROJECT_PATH'],
200
+ TAG_PIPELINE_NUMBER => env['CI_PIPELINE_IID'],
201
+ TAG_PIPELINE_URL => url,
202
+ TAG_PROVIDER_NAME => 'gitlab',
203
+ TAG_WORKSPACE_PATH => env['CI_PROJECT_DIR']
204
+ }
205
+ end
206
+
207
+ def extract_jenkins(env)
208
+ branch_or_tag = env['GIT_BRANCH']
209
+ if branch_or_tag.include? 'tags/'
210
+ branch = nil
211
+ tag = branch_or_tag
212
+ else
213
+ branch = branch_or_tag
214
+ tag = nil
215
+ end
216
+ name = env['JOB_NAME']
217
+ name = name.gsub("/#{normalize_ref(branch)}", '') unless name.nil? || branch.nil?
218
+ name = name.split('/').reject { |v| v.nil? || v.include?('=') }.join('/') unless name.nil?
219
+ {
220
+ Git::TAG_BRANCH => branch,
221
+ Git::TAG_COMMIT_SHA => env['GIT_COMMIT'],
222
+ Git::TAG_REPOSITORY_URL => env['GIT_URL'],
223
+ Git::TAG_TAG => tag,
224
+ TAG_JOB_URL => env['JOB_URL'],
225
+ TAG_PIPELINE_ID => env['BUILD_TAG'],
226
+ TAG_PIPELINE_NAME => name,
227
+ TAG_PIPELINE_NUMBER => env['BUILD_NUMBER'],
228
+ TAG_PIPELINE_URL => env['BUILD_URL'],
229
+ TAG_PROVIDER_NAME => 'jenkins',
230
+ TAG_WORKSPACE_PATH => env['WORKSPACE']
231
+ }
232
+ end
233
+
234
+ def extract_teamcity(env)
235
+ {
236
+ TAG_PROVIDER_NAME => 'teamcity',
237
+ Git::TAG_REPOSITORY_URL => env['BUILD_VCS_URL'],
238
+ Git::TAG_COMMIT_SHA => env['BUILD_VCS_NUMBER'],
239
+ TAG_WORKSPACE_PATH => env['BUILD_CHECKOUTDIR'],
240
+ TAG_PIPELINE_ID => env['BUILD_ID'],
241
+ TAG_PIPELINE_NUMBER => env['BUILD_NUMBER'],
242
+ TAG_PIPELINE_URL => (
243
+ env['SERVER_URL'] && env['BUILD_ID'] ? "#{env['SERVER_URL']}/viewLog.html?buildId=#{env['SERVER_URL']}" : nil
244
+ )
245
+ }
246
+ end
247
+
248
+ def extract_travis(env)
249
+ {
250
+ Git::TAG_BRANCH => (env['TRAVIS_PULL_REQUEST_BRANCH'] || env['TRAVIS_BRANCH']),
251
+ Git::TAG_COMMIT_SHA => env['TRAVIS_COMMIT'],
252
+ Git::TAG_REPOSITORY_URL => "https://github.com/#{env['TRAVIS_REPO_SLUG']}.git",
253
+ Git::TAG_TAG => env['TRAVIS_TAG'],
254
+ TAG_JOB_URL => env['TRAVIS_JOB_WEB_URL'],
255
+ TAG_PIPELINE_ID => env['TRAVIS_BUILD_ID'],
256
+ TAG_PIPELINE_NAME => env['TRAVIS_REPO_SLUG'],
257
+ TAG_PIPELINE_NUMBER => env['TRAVIS_BUILD_NUMBER'],
258
+ TAG_PIPELINE_URL => env['TRAVIS_BUILD_WEB_URL'],
259
+ TAG_PROVIDER_NAME => 'travisci',
260
+ TAG_WORKSPACE_PATH => env['TRAVIS_BUILD_DIR']
261
+ }
262
+ end
263
+ end
264
+ end
265
+ end