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.
- checksums.yaml +4 -4
- data/README.md +17 -0
- data/lib/mergify/rspec/ci_insights.rb +49 -86
- data/lib/mergify/rspec/flaky_detection.rb +39 -84
- data/lib/mergify/rspec/formatter.rb +34 -43
- data/lib/mergify/rspec/native.rb +91 -0
- data/lib/mergify/rspec/quarantine.rb +22 -79
- data/lib/mergify/rspec/resources/rspec.rb +9 -5
- data/lib/mergify/rspec/trace.rb +145 -0
- data/lib/mergify/rspec/utils.rb +11 -93
- data/lib/mergify/rspec/version.rb +1 -1
- metadata +4 -37
- data/lib/mergify/rspec/resources/buildkite.rb +0 -54
- data/lib/mergify/rspec/resources/ci.rb +0 -24
- data/lib/mergify/rspec/resources/git.rb +0 -35
- data/lib/mergify/rspec/resources/github_actions.rb +0 -60
- data/lib/mergify/rspec/resources/jenkins.rb +0 -55
- data/lib/mergify/rspec/resources/mergify.rb +0 -24
- data/lib/mergify/rspec/synchronous_batch_span_processor.rb +0 -34
|
@@ -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
|
-
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
data/lib/mergify/rspec/utils.rb
CHANGED
|
@@ -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
|
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.
|
|
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/
|
|
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.
|
|
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
|