rspec-mergify 0.1.4 → 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.
@@ -1,14 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'net/http'
4
- require 'json'
5
- require 'uri'
6
3
  require 'set'
7
4
  require_relative 'utils'
5
+ require_relative 'native'
6
+ require_relative 'version'
8
7
 
9
8
  module Mergify
10
9
  module RSpec
11
10
  # Fetches quarantined test names from the Mergify API and tracks which are used.
11
+ #
12
+ # The fetch itself -- pagination, the RFC 8288 `next` links, the status
13
+ # codes that mean "not subscribed" rather than "broken" -- belongs to the
14
+ # shared Rust client now, so every Mergify test client reads a quarantine
15
+ # list the same way. What stays here is what RSpec cares about: which of
16
+ # those tests this session actually ran, and the report at the end.
12
17
  class Quarantine
13
18
  attr_reader :quarantined_tests, :init_error_msg
14
19
 
@@ -19,10 +24,7 @@ module Mergify
19
24
  @used_tests = Set.new
20
25
  @init_error_msg = nil
21
26
 
22
- owner, repo = Utils.split_full_repo_name(repo_name)
23
- fetch_quarantined_tests(api_url, token, owner, repo, branch_name)
24
- rescue Utils::InvalidRepositoryFullNameError => e
25
- @init_error_msg = e.message
27
+ fetch(api_url, token, branch_name)
26
28
  end
27
29
 
28
30
  def include?(example_id)
@@ -53,80 +55,21 @@ module Mergify
53
55
 
54
56
  private
55
57
 
56
- def fetch_quarantined_tests(api_url, token, owner, repo, branch_name)
57
- uri = URI("#{api_url}/v1/ci/#{owner}/repositories/#{repo}/quarantines")
58
- uri.query = URI.encode_www_form(branch: branch_name, per_page: 100)
59
- collected = walk_paginated_quarantines(uri, token)
60
- @quarantined_tests = collected if collected
61
- rescue Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNREFUSED, SocketError => e
62
- @init_error_msg = "Failed to connect to Mergify API: #{e.message}"
63
- rescue JSON::ParserError => e
64
- @init_error_msg = "Mergify API returned a malformed quarantine list: #{e.message}"
65
- end
66
-
67
- # Follows the RFC 5988 `next` link until exhausted. Returns the full list
68
- # on success, or `nil` when the run was aborted (subscription missing or
69
- # an error already recorded in @init_error_msg).
70
- # rubocop:disable-next Metrics/MethodLength,Metrics/AbcSize
71
- def walk_paginated_quarantines(uri, token)
72
- collected = []
73
- # Guard against a server returning a `next` link that loops back to a
74
- # URL we have already fetched.
75
- seen = Set.new
76
- while uri
77
- if seen.include?(uri.to_s)
78
- @init_error_msg = 'Mergify API returned a cyclic `next` link, aborting.'
79
- return nil
80
- end
81
- seen.add(uri.to_s)
82
-
83
- response = perform_request(uri, token)
84
- case response.code.to_i
85
- when 200
86
- data = JSON.parse(response.body)
87
- collected.concat(data.fetch('quarantined_tests', []).map { |t| t['test_name'] })
88
- next_url = parse_next_link(response['Link'])
89
- uri = next_url ? URI(next_url) : nil
90
- when 402
91
- return nil
92
- else
93
- @init_error_msg = "Mergify API returned HTTP #{response.code}"
94
- return nil
95
- end
96
- end
97
- collected
98
- end
99
-
100
- def perform_request(uri, token)
101
- http = Net::HTTP.new(uri.host, uri.port)
102
- http.use_ssl = uri.scheme == 'https'
103
- http.open_timeout = 10
104
- http.read_timeout = 10
105
-
106
- request = Net::HTTP::Get.new(uri)
107
- request['Authorization'] = "Bearer #{token}"
108
- http.request(request)
109
- end
110
-
111
- # Parses RFC 8288 Link headers tolerantly: accepts both quoted
112
- # (`rel="next"`) and token (`rel=next`) forms, and matches when `next`
113
- # is one of several space-separated rel-types (`rel="next prev"`).
114
- def parse_next_link(link_header)
115
- return nil if link_header.nil? || link_header.empty?
116
-
117
- link_header.split(',').each do |part|
118
- match = part.strip.match(/\A<([^>]+)>\s*;\s*(.+)\z/)
119
- next unless match && next_rel?(match[2])
120
-
121
- return match[1]
58
+ # A nil list means the repository has no quarantine subscription, which is
59
+ # not an error: the session simply quarantines nothing. Anything that went
60
+ # genuinely wrong is recorded and the suite carries on -- this plugin has
61
+ # never let the backend fail a test run.
62
+ def fetch(api_url, token, branch_name)
63
+ unless Native.available?
64
+ @init_error_msg = "Mergify native extension unavailable: #{Native.load_error}"
65
+ return
122
66
  end
123
- nil
124
- end
125
67
 
126
- def next_rel?(params)
127
- params.scan(/rel\s*=\s*(?:"([^"]+)"|([^\s;,]+))/i).any? do |quoted, token|
128
- (quoted || token).split.include?('next')
129
- end
68
+ owner, repo = Utils.split_full_repo_name(@repo_name)
69
+ client = Native::Client.new(api_url, token, owner, repo, VERSION)
70
+ @quarantined_tests = client.fetch_quarantine(branch_name) || []
71
+ rescue Utils::InvalidRepositoryFullNameError, Native::ApiError => e
72
+ @init_error_msg = e.message
130
73
  end
131
74
  end
132
75
  end
@@ -1,20 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'opentelemetry-sdk'
4
3
  require 'rspec/core/version'
5
4
 
6
5
  module Mergify
7
6
  module RSpec
8
7
  module Resources
9
- # Detects OpenTelemetry Resource attributes for RSpec.
8
+ # The resource attributes only Ruby knows: which framework ran the suite,
9
+ # and in which language.
10
10
  module RSpec
11
11
  module_function
12
12
 
13
13
  def detect
14
- OpenTelemetry::SDK::Resources::Resource.create(
14
+ {
15
15
  'test.framework' => 'rspec',
16
- 'test.framework.version' => ::RSpec::Core::Version::STRING
17
- )
16
+ 'test.framework.version' => ::RSpec::Core::Version::STRING,
17
+ # Mergify takes a test's language from here when the span does not
18
+ # name one. The OpenTelemetry SDK sets this on its default resource,
19
+ # but this gem never used that resource, so nothing had ever sent it.
20
+ 'telemetry.sdk.language' => 'ruby'
21
+ }
18
22
  end
19
23
  end
20
24
  end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Mergify
6
+ module RSpec
7
+ # The little of OpenTelemetry this plugin actually used.
8
+ #
9
+ # A test run needs identifiers, a start and an end, some attributes and a
10
+ # status -- and the shared Rust client does the rest: the wire format, the
11
+ # compression, the retries, the size limit. The SDK brought samplers,
12
+ # context propagation machinery, batch processors and an exporter registry
13
+ # to do the part that fits here, and its dependency tree landed in every
14
+ # consumer's bundle. So the spans are assembled directly.
15
+ module Trace
16
+ # W3C traceparent: version-traceid-spanid-flags, all lowercase hex.
17
+ TRACEPARENT = /\A00-(?<trace_id>[0-9a-f]{32})-(?<span_id>[0-9a-f]{16})-[0-9a-f]{2}\z/
18
+
19
+ # A span being recorded, and once finished, the record itself.
20
+ class Span
21
+ attr_reader :name, :trace_id, :span_id, :parent_span_id, :attributes
22
+ attr_accessor :status, :status_message
23
+
24
+ def initialize(name:, trace_id:, span_id:, parent_span_id: nil, attributes: {})
25
+ @name = name
26
+ @trace_id = trace_id
27
+ @span_id = span_id
28
+ @parent_span_id = parent_span_id
29
+ @attributes = attributes.transform_keys(&:to_s)
30
+ @status = 'unset'
31
+ @status_message = nil
32
+ @start_unix_nano = Trace.now_unix_nano
33
+ @end_unix_nano = nil
34
+ end
35
+
36
+ # Ids travel as bytes and are read as hex -- in a traceparent, in a
37
+ # backend URL, in a log line.
38
+ def hex_trace_id
39
+ @trace_id.unpack1('H*')
40
+ end
41
+
42
+ def hex_span_id
43
+ @span_id.unpack1('H*')
44
+ end
45
+
46
+ def set_attribute(key, value)
47
+ @attributes[key.to_s] = value
48
+ end
49
+
50
+ def error!(message)
51
+ @status = 'error'
52
+ @status_message = message
53
+ end
54
+
55
+ def ok!
56
+ @status = 'ok'
57
+ end
58
+
59
+ def finish
60
+ @end_unix_nano ||= Trace.now_unix_nano
61
+ self
62
+ end
63
+
64
+ # The shape the binding accepts, which is the wire format's own.
65
+ # rubocop:disable-next Metrics/MethodLength
66
+ def to_h
67
+ {
68
+ 'name' => @name,
69
+ 'trace_id' => @trace_id,
70
+ 'span_id' => @span_id,
71
+ 'parent_span_id' => @parent_span_id,
72
+ 'start_unix_nano' => @start_unix_nano,
73
+ 'end_unix_nano' => @end_unix_nano || Trace.now_unix_nano,
74
+ 'attributes' => @attributes,
75
+ 'status' => @status,
76
+ 'status_message' => @status_message
77
+ }.compact
78
+ end
79
+ end
80
+
81
+ # Collects a run's spans and hands them to the client in one upload.
82
+ #
83
+ # Deliberately not streaming: a suite's spans are worth one request at the
84
+ # end, and exporting mid-run would put HTTP in the middle of the thing
85
+ # being timed. That was already why the gem replaced the SDK's batch
86
+ # processor with its own.
87
+ class Recorder
88
+ attr_reader :resource_attributes, :finished_spans, :trace_id
89
+
90
+ # `traceparent` is the W3C header a caller can hand down to put this
91
+ # run inside a trace it already started; the session span then hangs off
92
+ # that caller's span rather than starting a trace of its own.
93
+ def initialize(resource_attributes: {}, traceparent: nil)
94
+ @resource_attributes = resource_attributes.transform_keys(&:to_s)
95
+ inherited = Trace.parse_traceparent(traceparent)
96
+ @trace_id = inherited ? inherited.first : Trace.generate_trace_id
97
+ @root_parent_span_id = inherited&.last
98
+ @finished_spans = []
99
+ end
100
+
101
+ def start_span(name, parent: nil, attributes: {})
102
+ Span.new(
103
+ name: name,
104
+ trace_id: @trace_id,
105
+ span_id: Trace.generate_span_id,
106
+ parent_span_id: parent&.span_id || @root_parent_span_id,
107
+ attributes: attributes
108
+ )
109
+ end
110
+
111
+ def record(span)
112
+ @finished_spans << span.finish
113
+ span
114
+ end
115
+
116
+ def clear
117
+ @finished_spans = []
118
+ end
119
+ end
120
+
121
+ class << self
122
+ def now_unix_nano
123
+ (Time.now.to_r * 1_000_000_000).to_i
124
+ end
125
+
126
+ def generate_trace_id
127
+ SecureRandom.bytes(16)
128
+ end
129
+
130
+ def generate_span_id
131
+ SecureRandom.bytes(8)
132
+ end
133
+
134
+ # The trace this run belongs to, when a parent handed one down.
135
+ # Returns [trace_id, parent_span_id] as raw bytes, or nil.
136
+ def parse_traceparent(header)
137
+ match = TRACEPARENT.match(header.to_s)
138
+ return nil unless match
139
+
140
+ [[match[:trace_id]].pack('H*'), [match[:span_id]].pack('H*')]
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -1,24 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'open3'
4
-
5
3
  module Mergify
6
4
  module RSpec
7
5
  # Utility methods shared across the rspec-mergify gem.
6
+ #
7
+ # CI detection used to live here -- the provider table, the git shelling
8
+ # out, the per-provider environment mappings. It is the Rust core's now, via
9
+ # the extension in Mergify::RSpec::Native, so that every Mergify test client
10
+ # detects identically. What is left is what is genuinely Ruby's: parsing a
11
+ # repository name the API needs split, and deciding whether the plugin
12
+ # should switch itself on at all.
8
13
  module Utils
9
14
  module_function
10
15
 
11
16
  # Raised when a repository full name (owner/repo) is malformed.
12
17
  class InvalidRepositoryFullNameError < StandardError; end
13
18
 
14
- SUPPORTED_CIS = {
15
- 'GITHUB_ACTIONS' => :github_actions,
16
- 'CIRCLECI' => :circleci,
17
- 'JENKINS_URL' => :jenkins,
18
- 'BUILDKITE' => :buildkite,
19
- '_RSPEC_MERGIFY_TEST' => :rspec_mergify_suite
20
- }.freeze
21
-
22
19
  TRUTHY_STRINGS = %w[y yes t true on 1].freeze
23
20
  FALSY_STRINGS = %w[n no f false off 0].freeze
24
21
 
@@ -40,44 +37,14 @@ module Mergify
40
37
 
41
38
  # Returns true when the suite is running inside CI or when
42
39
  # RSPEC_MERGIFY_ENABLE is set to a truthy value.
40
+ #
41
+ # Deliberately not the core's provider detection: this asks whether the
42
+ # plugin should run, which an unrecognised CI or a developer setting
43
+ # RSPEC_MERGIFY_ENABLE both answer yes to.
43
44
  def in_ci?
44
45
  env_truthy?('CI') || env_truthy?('RSPEC_MERGIFY_ENABLE')
45
46
  end
46
47
 
47
- # Evaluates whether a CI environment variable should be considered enabled.
48
- # rubocop:disable-next Metrics/MethodLength
49
- def ci_provider
50
- SUPPORTED_CIS.each do |envvar, name|
51
- next unless ENV.key?(envvar)
52
-
53
- enabled =
54
- begin
55
- strtobool(ENV.fetch(envvar, ''))
56
- rescue ArgumentError
57
- !ENV.fetch(envvar, '').strip.empty?
58
- end
59
-
60
- return name if enabled
61
- end
62
- nil
63
- end
64
-
65
- # Parse a git remote URL (SSH or HTTPS) into "owner/repo" form.
66
- # Returns nil when the URL cannot be recognised.
67
- def repository_name_from_url(url)
68
- # SSH: git@github.com:owner/repo.git
69
- if (m = url.match(%r{\Agit@[\w.-]+:(?<full_name>[\w.-]+/[\w.-]+?)(?:\.git)?/?$}))
70
- return m[:full_name]
71
- end
72
-
73
- # HTTPS/HTTP with optional host (and optional port)
74
- if (m = url.match(%r{\A(?:https?://[\w.-]+(?::\d+)?/)?(?<full_name>[\w.-]+/[\w.-]+)/?\z}))
75
- return m[:full_name]
76
- end
77
-
78
- nil
79
- end
80
-
81
48
  # Split "owner/repo" into [owner, repo].
82
49
  # Raises InvalidRepositoryFullNameError when the format is wrong.
83
50
  def split_full_repo_name(full_repo_name)
@@ -86,55 +53,6 @@ module Mergify
86
53
 
87
54
  raise InvalidRepositoryFullNameError, "Invalid repository name: #{full_repo_name}"
88
55
  end
89
-
90
- # Run a git subcommand via Open3.
91
- # Returns stripped stdout on success, nil on failure.
92
- def git(*args)
93
- stdout, status = Open3.capture2('git', *args, err: File::NULL)
94
- status.success? ? stdout.strip : nil
95
- rescue StandardError
96
- nil
97
- end
98
-
99
- # Build an attribute hash from a mapping of
100
- # { attr_name => [cast_method_symbol, env_var_name_or_callable] }.
101
- # Attributes whose env var is unset or whose callable returns nil are omitted.
102
- def get_attributes(mapping)
103
- mapping.each_with_object({}) do |(attr, (cast, env_or_callable)), result|
104
- value = env_or_callable.respond_to?(:call) ? env_or_callable.call : ENV.fetch(env_or_callable, nil)
105
-
106
- next if value.nil?
107
- next if value.respond_to?(:empty?) && value.empty?
108
-
109
- result[attr] = value.public_send(cast)
110
- end
111
- end
112
-
113
- # Detect the repository name using CI environment variables or a git
114
- # remote fallback.
115
- # rubocop:disable-next Metrics/MethodLength,Metrics/CyclomaticComplexity
116
- def repository_name
117
- provider = ci_provider
118
-
119
- case provider
120
- when :jenkins
121
- url = ENV.fetch('GIT_URL', nil)
122
- return repository_name_from_url(url) if url
123
- when :github_actions
124
- return ENV.fetch('GITHUB_REPOSITORY', nil)
125
- when :circleci
126
- url = ENV.fetch('CIRCLE_REPOSITORY_URL', nil)
127
- return repository_name_from_url(url) if url
128
- when :buildkite
129
- url = ENV.fetch('BUILDKITE_REPO', nil)
130
- return repository_name_from_url(url) if url
131
- when :rspec_mergify_suite
132
- return 'Mergifyio/rspec-mergify'
133
- end
134
-
135
- url = git('config', '--get', 'remote.origin.url')
136
- repository_name_from_url(url) if url
137
- end
138
56
  end
139
57
  end
140
58
  end
@@ -8,6 +8,6 @@ module Mergify
8
8
  # which resolved against whatever repository happened to be the working
9
9
  # directory at load time -- the monorepo's namespaced tags here, the user's
10
10
  # own tags once the gem was installed.
11
- VERSION = '0.1.4'
11
+ VERSION = '0.3.0'
12
12
  end
13
13
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-mergify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mergify
@@ -9,34 +9,6 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: opentelemetry-exporter-otlp
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '0.29'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - "~>"
24
- - !ruby/object:Gem::Version
25
- version: '0.29'
26
- - !ruby/object:Gem::Dependency
27
- name: opentelemetry-sdk
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - "~>"
31
- - !ruby/object:Gem::Version
32
- version: '1.4'
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '1.4'
40
12
  - !ruby/object:Gem::Dependency
41
13
  name: rspec-core
42
14
  requirement: !ruby/object:Gem::Requirement
@@ -66,15 +38,10 @@ files:
66
38
  - lib/mergify/rspec/configuration.rb
67
39
  - lib/mergify/rspec/flaky_detection.rb
68
40
  - lib/mergify/rspec/formatter.rb
41
+ - lib/mergify/rspec/native.rb
69
42
  - lib/mergify/rspec/quarantine.rb
70
- - lib/mergify/rspec/resources/buildkite.rb
71
- - lib/mergify/rspec/resources/ci.rb
72
- - lib/mergify/rspec/resources/git.rb
73
- - lib/mergify/rspec/resources/github_actions.rb
74
- - lib/mergify/rspec/resources/jenkins.rb
75
- - lib/mergify/rspec/resources/mergify.rb
76
43
  - lib/mergify/rspec/resources/rspec.rb
77
- - lib/mergify/rspec/synchronous_batch_span_processor.rb
44
+ - lib/mergify/rspec/trace.rb
78
45
  - lib/mergify/rspec/utils.rb
79
46
  - lib/mergify/rspec/version.rb
80
47
  - lib/rspec_mergify.rb
@@ -99,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
66
  - !ruby/object:Gem::Version
100
67
  version: '0'
101
68
  requirements: []
102
- rubygems_version: 4.0.16
69
+ rubygems_version: 4.0.20
103
70
  specification_version: 4
104
71
  summary: RSpec plugin for Mergify CI Insights
105
72
  test_files: []
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'opentelemetry-sdk'
4
- require_relative '../utils'
5
- require_relative 'git'
6
-
7
- module Mergify
8
- module RSpec
9
- module Resources
10
- # Detects OpenTelemetry Resource attributes for Buildkite.
11
- module Buildkite
12
- module_function
13
-
14
- BUILDKITE_MAPPING = {
15
- 'cicd.pipeline.name' => [:to_s, 'BUILDKITE_PIPELINE_SLUG'],
16
- 'cicd.pipeline.task.name' => [
17
- :to_s,
18
- lambda {
19
- label = ENV.fetch('BUILDKITE_LABEL', nil)
20
- label && !label.empty? ? label : ENV.fetch('BUILDKITE_STEP_KEY', nil)
21
- }
22
- ],
23
- 'cicd.pipeline.run.id' => [:to_s, 'BUILDKITE_BUILD_ID'],
24
- 'cicd.pipeline.run.url' => [:to_s, 'BUILDKITE_BUILD_URL'],
25
- 'cicd.pipeline.run.attempt' => [
26
- :to_i,
27
- -> { ENV.fetch('BUILDKITE_RETRY_COUNT', '0').to_i + 1 }
28
- ],
29
- 'cicd.pipeline.runner.name' => [:to_s, 'BUILDKITE_AGENT_NAME'],
30
- 'vcs.ref.head.name' => [:to_s, 'BUILDKITE_BRANCH'],
31
- 'vcs.ref.base.name' => [:to_s, 'BUILDKITE_PULL_REQUEST_BASE_BRANCH'],
32
- 'vcs.ref.head.revision' => [:to_s, 'BUILDKITE_COMMIT'],
33
- 'vcs.repository.url.full' => [:to_s, 'BUILDKITE_REPO'],
34
- 'vcs.repository.name' => [
35
- :to_s,
36
- lambda {
37
- url = ENV.fetch('BUILDKITE_REPO', nil)
38
- Utils.repository_name_from_url(url) if url
39
- }
40
- ]
41
- }.freeze
42
-
43
- def detect
44
- return OpenTelemetry::SDK::Resources::Resource.create({}) if Utils.ci_provider != :buildkite
45
-
46
- git_attrs = Utils.get_attributes(Git::GIT_MAPPING)
47
- buildkite_attrs = Utils.get_attributes(BUILDKITE_MAPPING)
48
- merged = git_attrs.merge(buildkite_attrs)
49
- OpenTelemetry::SDK::Resources::Resource.create(merged)
50
- end
51
- end
52
- end
53
- end
54
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'opentelemetry-sdk'
4
- require_relative '../utils'
5
-
6
- module Mergify
7
- module RSpec
8
- module Resources
9
- # Detects OpenTelemetry Resource attributes for the CI provider.
10
- module CI
11
- module_function
12
-
13
- def detect
14
- provider = Utils.ci_provider
15
- return OpenTelemetry::SDK::Resources::Resource.create({}) if provider.nil?
16
-
17
- OpenTelemetry::SDK::Resources::Resource.create(
18
- 'cicd.provider.name' => provider.to_s
19
- )
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'opentelemetry-sdk'
4
- require_relative '../utils'
5
-
6
- module Mergify
7
- module RSpec
8
- module Resources
9
- # Detects OpenTelemetry Resource attributes from git.
10
- module Git
11
- module_function
12
-
13
- GIT_MAPPING = {
14
- 'vcs.ref.head.name' => [:to_s, -> { Utils.git('rev-parse', '--abbrev-ref', 'HEAD') }],
15
- 'vcs.ref.head.revision' => [:to_s, -> { Utils.git('rev-parse', 'HEAD') }],
16
- 'vcs.repository.url.full' => [:to_s, -> { Utils.git('config', '--get', 'remote.origin.url') }],
17
- 'vcs.repository.name' => [
18
- :to_s,
19
- lambda {
20
- url = Utils.git('config', '--get', 'remote.origin.url')
21
- Utils.repository_name_from_url(url) if url
22
- }
23
- ]
24
- }.freeze
25
-
26
- def detect
27
- return OpenTelemetry::SDK::Resources::Resource.create({}) if Utils.ci_provider.nil?
28
-
29
- attributes = Utils.get_attributes(GIT_MAPPING)
30
- OpenTelemetry::SDK::Resources::Resource.create(attributes)
31
- end
32
- end
33
- end
34
- end
35
- end