rspec-buildkite-analytics 0.7.0 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b1c6bc2713e36242b9d710e348574bd05b8cda4e4d3961742a781256595114f
4
- data.tar.gz: f221e0f6486ceeb41547a344ec72b47c1385d1ec41689d61aa4e9d9653fa51e3
3
+ metadata.gz: df185766b2de68f6e2e22fb9c72744728364495d6377b26dce7cf33dda1ff731
4
+ data.tar.gz: 9b0f066bc54f5b4437ecb35fcf76dfc7d8b123ebe85ef694e78e68647a4f7c54
5
5
  SHA512:
6
- metadata.gz: a2fd21327c874a8efac7822e995ce9b487029462905ea24ea45aa7e34b89ff2fdf90aec46e1a048fed546ea78192471ce05018546845434821c952f76be36951
7
- data.tar.gz: 29ca02ed84c008bf2adad2ee75d2d02562d398ef976bf5f00b0c4f30ca3ddb3a4475c7ba1e5d6eb1a7d3de0f6628421dc1b7b83bc902506440d417da4b7a8078
6
+ metadata.gz: 9916640fd397348738c50e21dc7139b1a88d1385a9dc1d2740d4db31158d12388276523e97c0b2f53fac5434dfaf9dfad13f8f63f5b32198aefb04e1bbc62e6e
7
+ data.tar.gz: e1f7c45eb96cfe67fd698aed7d17288bbc497b278cde989d051c80dd1777b2f2164894e3cc34689c1793c274a4ecbbe4df9be5f5313b86cbbab83b57a3198f06
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # CHANGELOG
2
+
3
+ ## v0.8.1
4
+
5
+ - Improve the EOT confirmation #93 — @blaknite
6
+
7
+ ## v0.8.0
8
+
9
+ - Support multiple CI platforms and generic env #80 — @blaknite
10
+ - Replace invalid UTF-8 characters in test names #85 — @mariovisic
11
+ - Relax Active Support constraint #87 — @ags
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rspec-buildkite-analytics (0.7.0)
5
- activesupport (>= 5.2, <= 7.0)
4
+ rspec-buildkite-analytics (0.8.1)
5
+ activesupport (>= 5.2, < 8)
6
6
  rspec-core (~> 3.10)
7
7
  rspec-expectations (~> 3.10)
8
8
  websocket (~> 1.2)
@@ -10,14 +10,14 @@ PATH
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- activesupport (7.0.0)
13
+ activesupport (7.0.2.4)
14
14
  concurrent-ruby (~> 1.0, >= 1.0.2)
15
15
  i18n (>= 1.6, < 2)
16
16
  minitest (>= 5.1)
17
17
  tzinfo (~> 2.0)
18
- concurrent-ruby (1.1.9)
18
+ concurrent-ruby (1.1.10)
19
19
  diff-lcs (1.4.4)
20
- i18n (1.9.1)
20
+ i18n (1.10.0)
21
21
  concurrent-ruby (~> 1.0)
22
22
  minitest (5.15.0)
23
23
  rake (13.0.6)
@@ -2,30 +2,85 @@
2
2
 
3
3
  require "securerandom"
4
4
 
5
- module RSpec::Buildkite::Analytics::CI
5
+ class RSpec::Buildkite::Analytics::CI
6
6
  def self.env
7
- if ENV["BUILDKITE_BUILD_ID"]
8
- {
9
- "CI" => "buildkite",
10
- "key" => ENV["BUILDKITE_BUILD_ID"],
11
- "url" => ENV["BUILDKITE_BUILD_URL"],
12
- "branch" => ENV["BUILDKITE_BRANCH"],
13
- "commit_sha" => ENV["BUILDKITE_COMMIT"],
14
- "number" => ENV["BUILDKITE_BUILD_NUMBER"],
15
- "job_id" => ENV["BUILDKITE_JOB_ID"],
16
- "message" => ENV["BUILDKITE_MESSAGE"],
17
- "debug" => ENV["BUILDKITE_ANALYTICS_DEBUG_ENABLED"],
18
- "version" => RSpec::Buildkite::Analytics::VERSION,
19
- "collector" => RSpec::Buildkite::Analytics::NAME
20
- }
21
- else
22
- {
23
- "CI" => nil,
24
- "key" => SecureRandom.uuid,
25
- "debug" => ENV["BUILDKITE_ANALYTICS_DEBUG_ENABLED"],
26
- "version" => RSpec::Buildkite::Analytics::VERSION,
27
- "collector" => RSpec::Buildkite::Analytics::NAME
28
- }
29
- end
7
+ new.env
8
+ end
9
+
10
+ # The analytics env are more specific than the automatic ci platform env.
11
+ # If they've been specified we'll assume the user wants to use that value instead.
12
+ def env
13
+ ci_env.merge(analytics_env)
14
+ end
15
+
16
+ private
17
+
18
+ def ci_env
19
+ return buildkite if ENV["BUILDKITE_BUILD_ID"]
20
+ return github_actions if ENV["GITHUB_RUN_NUMBER"]
21
+ return circleci if ENV["CIRCLE_BUILD_NUM"]
22
+ return generic if ENV["CI"]
23
+
24
+ {
25
+ "CI" => nil,
26
+ "key" => SecureRandom.uuid,
27
+ }
28
+ end
29
+
30
+ def analytics_env
31
+ {
32
+ "key" => ENV["BUILDKITE_ANALYTICS_KEY"],
33
+ "url" => ENV["BUILDKITE_ANALYTICS_URL"],
34
+ "branch" => ENV["BUILDKITE_ANALYTICS_BRANCH"],
35
+ "commit_sha" => ENV["BUILDKITE_ANALYTICS_SHA"],
36
+ "number" => ENV["BUILDKITE_ANALYTICS_NUMBER"],
37
+ "job_id" => ENV["BUILDKITE_ANALYTICS_JOB_ID"],
38
+ "message" => ENV["BUILDKITE_ANANLYTICS_MESSAGE"],
39
+ "debug" => ENV["BUILDKITE_ANALYTICS_DEBUG_ENABLED"],
40
+ "version" => RSpec::Buildkite::Analytics::VERSION,
41
+ "collector" => RSpec::Buildkite::Analytics::NAME,
42
+ }.compact
43
+ end
44
+
45
+ def generic
46
+ {
47
+ "CI" => "generic",
48
+ "key" => SecureRandom.uuid,
49
+ }
50
+ end
51
+
52
+ def buildkite
53
+ {
54
+ "CI" => "buildkite",
55
+ "key" => ENV["BUILDKITE_BUILD_ID"],
56
+ "url" => ENV["BUILDKITE_BUILD_URL"],
57
+ "branch" => ENV["BUILDKITE_BRANCH"],
58
+ "commit_sha" => ENV["BUILDKITE_COMMIT"],
59
+ "number" => ENV["BUILDKITE_BUILD_NUMBER"],
60
+ "job_id" => ENV["BUILDKITE_JOB_ID"],
61
+ "message" => ENV["BUILDKITE_MESSAGE"],
62
+ }
63
+ end
64
+
65
+ def github_actions
66
+ {
67
+ "CI" => "github_actions",
68
+ "key" => "#{ENV["GITHUB_ACTION"]}-#{ENV["GITHUB_RUN_NUMBER"]}-#{ENV["GITHUB_RUN_ATTEMPT"]}",
69
+ "url" => File.join("https://github.com", ENV["GITHUB_REPOSITORY"], "actions/runs", ENV["GITHUB_RUN_ID"]),
70
+ "branch" => ENV["GITHUB_REF"],
71
+ "commit_sha" => ENV["GITHUB_SHA"],
72
+ "number" => ENV["GITHUB_RUN_NUMBER"],
73
+ }
74
+ end
75
+
76
+ def circleci
77
+ {
78
+ "CI" => "circleci",
79
+ "key" => "#{ENV["CIRCLE_WORKFLOW_ID"]}-#{ENV["CIRCLE_BUILD_NUM"]}",
80
+ "url" => ENV["CIRCLE_BUILD_URL"],
81
+ "branch" => ENV["CIRCLE_BRANCH"],
82
+ "commit_sha" => ENV["CIRCLE_SHA1"],
83
+ "number" => ENV["CIRCLE_BUILD_NUM"],
84
+ }
30
85
  end
31
86
  end
@@ -5,9 +5,9 @@ require_relative "socket_connection"
5
5
  module RSpec::Buildkite::Analytics
6
6
  class Session
7
7
  # Picked 75 as the magic timeout number as it's longer than the TCP timeout of 60s 🤷‍♀️
8
- CONFIRMATION_TIMEOUT = 75
9
- MAX_RECONNECTION_ATTEMPTS = 3
10
- WAIT_BETWEEN_RECONNECTIONS = 5
8
+ CONFIRMATION_TIMEOUT = ENV.fetch("BUILDKITE_ANALYTICS_CONFIRMATION_TIMEOUT") { 75 }.to_i
9
+ MAX_RECONNECTION_ATTEMPTS = ENV.fetch("BUILDKITE_ANALYTICS_RECONNECTION_ATTEMPTS") { 3 }.to_i
10
+ WAIT_BETWEEN_RECONNECTIONS = ENV.fetch("BUILDKITE_ANALYTICS_RECONNECTION_WAIT") { 5 }.to_i
11
11
 
12
12
  class RejectedSubscription < StandardError; end
13
13
  class InitialConnectionFailure < StandardError; end
@@ -116,20 +116,24 @@ module RSpec::Buildkite::Analytics
116
116
  # to which the server will respond with the last bits of data
117
117
  send_eot
118
118
 
119
+ # After EOT, we wait for 75 seconds for the send queue to be drained and for the
120
+ # server to confirm the last idents. If everything has already been confirmed we can
121
+ # proceed without waiting.
119
122
  @idents_mutex.synchronize do
120
- @logger.write("waiting for last confirm")
121
- # Here, we sleep for 75 seconds while waiting for the send
122
- # queue to be drained and for the server to confirm the last
123
- # idents.
124
- # We are woken up when the unconfirmed_idents is empty, and given back the mutex to
125
- # continue operation.
126
- @empty.wait(@idents_mutex, CONFIRMATION_TIMEOUT) unless @unconfirmed_idents.empty?
123
+ if @unconfirmed_idents.any?
124
+ puts "Waiting for Buildkite Test Analytics to send results..."
125
+ @logger.write("waiting for last confirm")
126
+
127
+ @empty.wait(@idents_mutex, CONFIRMATION_TIMEOUT)
128
+ end
127
129
  end
128
130
 
129
131
  # Then we always disconnect cos we can't wait forever? 🤷‍♀️
130
132
  @connection.close
131
133
  # We kill the write thread cos it's got a while loop in it, so it won't finish otherwise
132
134
  @write_thread&.kill
135
+
136
+ puts "Buildkite Test Analytics completed"
133
137
  @logger.write("socket connection closed")
134
138
  end
135
139
 
@@ -183,6 +187,7 @@ module RSpec::Buildkite::Analytics
183
187
 
184
188
  wait_for_confirm
185
189
 
190
+ puts "Connected to Buildkite Test Analytics!"
186
191
  @logger.write("connected")
187
192
  end
188
193
 
@@ -255,23 +260,21 @@ module RSpec::Buildkite::Analytics
255
260
  @idents_mutex.synchronize do
256
261
  @unconfirmed_idents[ident] = result_as_hash
257
262
 
258
- data = {
263
+ @send_queue << {
259
264
  "action" => "record_results",
260
265
  "results" => [result_as_hash]
261
266
  }
262
-
263
- @send_queue << data
264
267
  end
265
268
  end
266
269
 
267
- def remove_unconfirmed_idents(idents)
268
- return if idents.empty?
270
+ def confirm_idents(idents)
271
+ retransmit_required = @closing
269
272
 
270
273
  @idents_mutex.synchronize do
271
274
  # Remove received idents from unconfirmed_idents
272
275
  idents.each { |key| @unconfirmed_idents.delete(key) }
273
276
 
274
- @logger.write("received confirm for indentifiers: #{idents.join(", ")}")
277
+ @logger.write("received confirm for indentifiers: #{idents}")
275
278
 
276
279
  # This @empty ConditionVariable broadcasts every time that @unconfirmed_idents is
277
280
  # empty, which will happen about every 10mb of data as that's when the server
@@ -281,23 +284,27 @@ module RSpec::Buildkite::Analytics
281
284
  # send the EOT message, so the prior broadcasts shouldn't do anything.
282
285
  if @unconfirmed_idents.empty?
283
286
  @empty.broadcast
284
- @logger.write("broadcast empty")
287
+
288
+ retransmit_required = false
289
+
290
+ @logger.write("all identifiers have been confirmed")
285
291
  else
286
- @logger.write("still waiting on confirm for #{@unconfirmed_idents.keys}")
292
+ @logger.write("still waiting on confirm for identifiers: #{@unconfirmed_idents.keys}")
287
293
  end
288
294
  end
295
+
296
+ # If we're closing, any unconfirmed results need to be retransmitted.
297
+ retransmit if retransmit_required
289
298
  end
290
299
 
291
300
  def send_eot
292
301
  @eot_queued_mutex.synchronize do
293
302
  return if @eot_queued
294
- # Expect server to respond with data of indentifiers last upload part
295
- data = {
303
+
304
+ @send_queue << {
296
305
  "action" => "end_of_transmission",
297
306
  "examples_count" => @examples_count.to_json
298
307
  }
299
-
300
- @send_queue << data
301
308
  @eot_queued = true
302
309
 
303
310
  @logger.write("added EOT to send queue")
@@ -310,7 +317,7 @@ module RSpec::Buildkite::Analytics
310
317
 
311
318
  case
312
319
  when data["message"].key?("confirm")
313
- remove_unconfirmed_idents(data["message"]["confirm"])
320
+ confirm_idents(data["message"]["confirm"])
314
321
  else
315
322
  # unhandled message
316
323
  @logger.write("received unhandled message #{data["message"]}")
@@ -322,13 +329,12 @@ module RSpec::Buildkite::Analytics
322
329
  results = @unconfirmed_idents.values
323
330
 
324
331
  # queue the contents of the buffer, unless it's empty
325
- unless results.empty?
326
- data = {
332
+ if results.any?
333
+ @send_queue << {
327
334
  "action" => "record_results",
328
335
  "results" => results
329
336
  }
330
337
 
331
- @send_queue << data
332
338
  @logger.write("queueing up retransmitted results #{@unconfirmed_idents.keys}")
333
339
  end
334
340
  end
@@ -42,7 +42,7 @@ module RSpec::Buildkite::Analytics
42
42
  end
43
43
 
44
44
  def as_hash
45
- {
45
+ strip_invalid_utf8_chars(
46
46
  id: @id,
47
47
  scope: example.example_group.metadata[:full_description],
48
48
  name: example.description,
@@ -53,14 +53,14 @@ module RSpec::Buildkite::Analytics
53
53
  failure_reason: failure_reason,
54
54
  failure_expanded: failure_expanded,
55
55
  history: history,
56
- }.with_indifferent_access.compact
56
+ ).with_indifferent_access.compact
57
57
  end
58
58
 
59
59
  private
60
60
 
61
61
  def generate_file_name(example)
62
62
  file_path_regex = /^(.*?\.(rb|feature))/
63
- identifier_file_name = example.id[file_path_regex]
63
+ identifier_file_name = strip_invalid_utf8_chars(example.id)[file_path_regex]
64
64
  location_file_name = example.location[file_path_regex]
65
65
 
66
66
  if identifier_file_name != location_file_name
@@ -78,6 +78,18 @@ module RSpec::Buildkite::Analytics
78
78
  identifier_file_name
79
79
  end
80
80
  end
81
+
82
+ def strip_invalid_utf8_chars(object)
83
+ if object.is_a?(Hash)
84
+ Hash[object.map { |key, value| [key, strip_invalid_utf8_chars(value)] }]
85
+ elsif object.is_a?(Array)
86
+ object.map { |value| strip_invalid_utf8_chars(value) }
87
+ elsif object.is_a?(String)
88
+ object.encode('UTF-8', :invalid => :replace, :undef => :replace)
89
+ else
90
+ object
91
+ end
92
+ end
81
93
  end
82
94
 
83
95
  def self.traces
@@ -3,7 +3,7 @@
3
3
  module RSpec
4
4
  module Buildkite
5
5
  module Analytics
6
- VERSION = "0.7.0"
6
+ VERSION = "0.8.2"
7
7
  NAME = "rspec-buildkite"
8
8
  end
9
9
  end
@@ -26,6 +26,8 @@ module RSpec::Buildkite::Analytics
26
26
  self.debug_enabled = debug_enabled || !!(ENV["BUILDKITE_ANALYTICS_DEBUG_ENABLED"])
27
27
  self.debug_filepath = debug_filepath || ENV["BUILDKITE_ANALYTICS_DEBUG_FILEPATH"] || Dir.tmpdir
28
28
 
29
+ Kernel.warn "UNSUPPORTED: The rspec-buildkite-analytics gem has been renamed to buildkite-test_collector. rspec-buildkite-analytics will not receive any further maintenance. Please follow our docs https://buildkite.com/docs/test-analytics/ruby-collectors to upgrade to the new gem: https://rubygems.org/gems/buildkite-test_collector. Thank you!"
30
+
29
31
  require_relative "analytics/uploader"
30
32
 
31
33
  self::Uploader.configure
@@ -6,12 +6,17 @@ Gem::Specification.new do |spec|
6
6
  spec.name = "rspec-buildkite-analytics"
7
7
  spec.version = RSpec::Buildkite::Analytics::VERSION
8
8
  spec.authors = ["Buildkite"]
9
- spec.email = ["hello@buildkite.com"]
9
+ spec.email = ["support+analytics@buildkite.com"]
10
10
 
11
11
  spec.summary = "Track execution of specs and report to Buildkite Analytics"
12
+ spec.description = "UNSUPPORTED: The rspec-buildkite-analytics gem has been renamed to buildkite-test_collector. rspec-buildkite-analytics will not receive any further maintenance. Please follow our docs https://buildkite.com/docs/test-analytics/ruby-collectors to upgrade to the new gem: https://rubygems.org/gems/buildkite-test_collector. Thank you!"
12
13
  spec.homepage = "https://github.com/buildkite/rspec-buildkite-analytics"
13
14
  spec.license = "MIT"
14
15
 
16
+ spec.post_install_message = <<~MSG
17
+ UNSUPPORTED: The rspec-buildkite-analytics gem has been renamed to buildkite-test_collector. rspec-buildkite-analytics will not receive any further maintenance. Please follow our docs https://buildkite.com/docs/test-analytics/ruby-collectors to upgrade to the new gem: https://rubygems.org/gems/buildkite-test_collector. Thank you!
18
+ MSG
19
+
15
20
  spec.metadata["homepage_uri"] = spec.homepage
16
21
  spec.metadata["source_code_uri"] = "https://github.com/buildkite/rspec-buildkite-analytics"
17
22
 
@@ -24,7 +29,7 @@ Gem::Specification.new do |spec|
24
29
 
25
30
  spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
26
31
 
27
- spec.add_dependency "activesupport", ">= 5.2", "<= 7.0"
32
+ spec.add_dependency "activesupport", ">= 5.2", "< 8"
28
33
  spec.add_dependency "rspec-core", '~> 3.10'
29
34
  spec.add_dependency "rspec-expectations", '~> 3.10'
30
35
  spec.add_dependency "websocket", '~> 1.2'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-buildkite-analytics
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Buildkite
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-08 00:00:00.000000000 Z
11
+ date: 2022-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -17,9 +17,9 @@ dependencies:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '5.2'
20
- - - "<="
20
+ - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '7.0'
22
+ version: '8'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -27,9 +27,9 @@ dependencies:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
29
  version: '5.2'
30
- - - "<="
30
+ - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '7.0'
32
+ version: '8'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: rspec-core
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -72,15 +72,19 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '1.2'
75
- description:
75
+ description: 'UNSUPPORTED: The rspec-buildkite-analytics gem has been renamed to buildkite-test_collector.
76
+ rspec-buildkite-analytics will not receive any further maintenance. Please follow
77
+ our docs https://buildkite.com/docs/test-analytics/ruby-collectors to upgrade to
78
+ the new gem: https://rubygems.org/gems/buildkite-test_collector. Thank you!'
76
79
  email:
77
- - hello@buildkite.com
80
+ - support+analytics@buildkite.com
78
81
  executables: []
79
82
  extensions: []
80
83
  extra_rdoc_files: []
81
84
  files:
82
85
  - ".gitignore"
83
86
  - ".rspec"
87
+ - CHANGELOG.md
84
88
  - Gemfile
85
89
  - Gemfile.lock
86
90
  - LICENSE.txt
@@ -106,7 +110,13 @@ licenses:
106
110
  metadata:
107
111
  homepage_uri: https://github.com/buildkite/rspec-buildkite-analytics
108
112
  source_code_uri: https://github.com/buildkite/rspec-buildkite-analytics
109
- post_install_message:
113
+ post_install_message: 'UNSUPPORTED: The rspec-buildkite-analytics gem has been renamed
114
+ to buildkite-test_collector. rspec-buildkite-analytics will not receive any further
115
+ maintenance. Please follow our docs https://buildkite.com/docs/test-analytics/ruby-collectors
116
+ to upgrade to the new gem: https://rubygems.org/gems/buildkite-test_collector. Thank
117
+ you!
118
+
119
+ '
110
120
  rdoc_options: []
111
121
  require_paths:
112
122
  - lib
@@ -121,8 +131,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
131
  - !ruby/object:Gem::Version
122
132
  version: '0'
123
133
  requirements: []
124
- rubygems_version: 3.1.4
125
- signing_key:
134
+ rubygems_version: 3.3.3
135
+ signing_key:
126
136
  specification_version: 4
127
137
  summary: Track execution of specs and report to Buildkite Analytics
128
138
  test_files: []