fbe 0.30.0 → 0.31.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d28d22ca3024f7acbd6630b903aeaaf5391e2debb3cd7dbab920c664473f1567
4
- data.tar.gz: 955bd9e464b2450eeeee67c9cbcc222687c00a1bb6bc5d9b5e37539d7b43700b
3
+ metadata.gz: 5ed41fbbf01d78ba6023ca93c5956fc9c37bb32624fd0ff1e589deed34b5c5dd
4
+ data.tar.gz: 34495a35e25f5a6241080c4fca1a6c7d78728e66fe809f989dbadfbcebae2f8f
5
5
  SHA512:
6
- metadata.gz: 87935f90c30759d39a960e0c44c717bf7cd6080114aa538546b3970efdec95449a3e749fbe6b575cf064cbd536f133a694d1ba11a9e608cf6fc43c058ec85867
7
- data.tar.gz: e1b306dfdb743aac0efaaa41fbaa73aeb327cdeae33a254046211eb98608c876e7ae351800dde5ff72a74741774985cad53c264a51d24d8cfa12cb570d044189
6
+ metadata.gz: 2178c31a1bce0a392b717a8429036cf6018325a77714f68f25dd2d8bdb5bbaf8e822cb358a26d7a47a18cb894b00e9ea99040685a9c1f317f6bbcda0501edc6b
7
+ data.tar.gz: ca9db41e2ed0f7fcc618c9bce81d5720e3c3b820a54e74ff16661eccd6e111117f78a307358bcef7163527ea64adfa92f326112de9581b1d47934c80cd2f0a10
data/fbe.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
19
19
  s.authors = ['Yegor Bugayenko']
20
20
  s.email = 'yegor256@gmail.com'
21
21
  s.homepage = 'https://github.com/zerocracy/fbe'
22
- s.files = `git ls-files`.split($RS)
22
+ s.files = `git ls-files | grep -v -E '^(test/|renovate|coverage)'`.split($RS)
23
23
  s.rdoc_options = ['--charset=UTF-8']
24
24
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
25
25
  s.add_dependency 'backtrace', '~>0.4'
data/lib/fbe/conclude.rb CHANGED
@@ -17,13 +17,16 @@ require_relative 'octo'
17
17
  # @param [Judges::Options] options The options coming from the +judges+ tool
18
18
  # @param [Loog] loog The logging facility
19
19
  # @yield [Factbase::Fact] The fact
20
- def Fbe.conclude(fb: Fbe.fb, judge: $judge, loog: $loog, options: $options, global: $global, time: Time, &)
20
+ def Fbe.conclude(
21
+ fb: Fbe.fb, judge: $judge, loog: $loog, options: $options, global: $global,
22
+ start: $start, time: Time, &
23
+ )
21
24
  raise 'The fb is nil' if fb.nil?
22
25
  raise 'The $judge is not set' if judge.nil?
23
26
  raise 'The $global is not set' if global.nil?
24
27
  raise 'The $options is not set' if options.nil?
25
28
  raise 'The $loog is not set' if loog.nil?
26
- c = Fbe::Conclude.new(fb:, judge:, loog:, options:, global:, time:)
29
+ c = Fbe::Conclude.new(fb:, judge:, loog:, options:, global:, start:, time:)
27
30
  c.instance_eval(&)
28
31
  end
29
32
 
@@ -59,28 +62,38 @@ class Fbe::Conclude
59
62
  # @param [Judges::Options] options The options coming from the +judges+ tool
60
63
  # @param [Loog] loog The logging facility
61
64
  # @param [Time] time The time
62
- def initialize(fb:, judge:, global:, options:, loog:, time: Time)
65
+ def initialize(fb:, judge:, global:, options:, loog:, start:, time: Time)
63
66
  @fb = fb
64
67
  @judge = judge
65
68
  @loog = loog
66
69
  @options = options
67
70
  @global = global
71
+ @start = start
68
72
  @query = nil
69
73
  @follows = []
70
- @quota_aware = false
74
+ @lifetime_aware = true
75
+ @quota_aware = true
71
76
  @timeout = 60
72
77
  @time = time
73
78
  end
74
79
 
75
- # Make this block aware of GitHub API quota.
80
+ # Make this block not aware of GitHub API quota.
76
81
  #
77
- # When the quota is reached, the loop will gracefully stop to avoid
78
- # hitting GitHub API rate limits. This helps prevent interruptions
79
- # in long-running operations.
82
+ # When the quota is reached, the loop will NOT gracefully stop to avoid
83
+ # hitting GitHub API rate limits.
80
84
  #
81
85
  # @return [nil] Nothing is returned
82
- def quota_aware
83
- @quota_aware = true
86
+ def quota_unaware
87
+ @quota_aware = false
88
+ end
89
+
90
+ # Make this block NOT aware of lifetime limitations.
91
+ #
92
+ # When the lifetime is over, the loop will NOT gracefully stop.
93
+ #
94
+ # @return [nil] Nothing is returned
95
+ def lifetime_aware
96
+ @lifetime_aware = false
84
97
  end
85
98
 
86
99
  # Make sure this block runs for less than allowed amount of seconds.
@@ -186,7 +199,11 @@ class Fbe::Conclude
186
199
  oct = Fbe.octo(loog: @loog, options: @options, global: @global)
187
200
  @fb.query(@query).each do |a|
188
201
  if @quota_aware && oct.off_quota?
189
- @loog.debug('We ran out of GitHub quota, must stop here')
202
+ @loog.info('We ran out of GitHub quota, must stop here')
203
+ break
204
+ end
205
+ if @lifetime_aware && @options.lifetime && Time.now - @start > @options.lifetime - 10
206
+ @loog.debug('We ran out of lifetime, must stop here')
190
207
  break
191
208
  end
192
209
  now = @time.now
data/lib/fbe/fb.rb CHANGED
@@ -44,8 +44,12 @@ def Fbe.fb(fb: $fb, global: $global, options: $options, loog: $loog)
44
44
  max = fbt.query('(max _id)').one
45
45
  f._id = (max.nil? ? 0 : max) + 1
46
46
  f._time = Time.now
47
- f._version = "#{Factbase::VERSION}/#{Judges::VERSION}/#{options.action_version}"
48
- f._job = options.job_id unless options.job_id.nil?
47
+ f._version = [
48
+ Factbase::VERSION,
49
+ Judges::VERSION,
50
+ options.action_version
51
+ ].compact.join('/')
52
+ f._job = options.job_id.to_i if options.job_id
49
53
  end
50
54
  Factbase::Impatient.new(
51
55
  Factbase::Logged.new(
data/lib/fbe/iterate.rb CHANGED
@@ -201,7 +201,7 @@ class Fbe::Iterate
201
201
  seen = {}
202
202
  oct = Fbe.octo(loog: @loog, options: @options, global: @global)
203
203
  if oct.off_quota?
204
- @loog.debug('We are off GitHub quota, cannot even start, sorry')
204
+ @loog.info('We are off GitHub quota, cannot even start, sorry')
205
205
  return
206
206
  end
207
207
  repos = Fbe.unmask_repos(
@@ -234,7 +234,7 @@ class Fbe::Iterate
234
234
  end
235
235
  repos.each do |repo|
236
236
  if @quota_aware && oct.off_quota?
237
- @loog.debug("We are off GitHub quota, we must skip #{repo}")
237
+ @loog.info("We are off GitHub quota, we must skip #{repo}")
238
238
  break
239
239
  end
240
240
  if Time.now - start > timeout
data/lib/fbe/octo.rb CHANGED
@@ -164,7 +164,7 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
164
164
  def off_quota?(threshold: 50)
165
165
  left = @origin.rate_limit!.remaining
166
166
  if left < threshold
167
- @loog.info("Too much GitHub API quota consumed already (#{left} < #{threshold}), stopping")
167
+ @loog.info("Too much GitHub API quota consumed already (#{left} < #{threshold})")
168
168
  true
169
169
  else
170
170
  @loog.debug("Still #{left} GitHub API quota left (>#{threshold})")
@@ -712,29 +712,40 @@ class Fbe::FakeOctokit
712
712
  # client.pull_request('octocat/Hello-World', 1)
713
713
  # # => {:id=>42, :number=>1, :additions=>12, ...}
714
714
  def pull_request(repo, number)
715
- {
716
- id: 42,
717
- number:,
718
- repo: {
719
- full_name: repo
720
- },
721
- base: {
715
+ if number == 29
716
+ {
717
+ id: 42,
718
+ number:,
719
+ user: { id: 421, login: 'user' },
720
+ created_at: Time.parse('2024-08-20 15:35:30 UTC'),
721
+ additions: 12,
722
+ deletions: 5
723
+ }
724
+ else
725
+ {
726
+ id: 42,
727
+ number:,
722
728
  repo: {
723
729
  full_name: repo
724
- }
725
- },
726
- state: 'closed',
727
- user: { login: 'yegor256', id: 526_301, type: 'User' },
728
- head: { ref: 'master', sha: '6dcb09b5b57875f334f61aebed695e2e4193db5e' },
729
- additions: 12,
730
- deletions: 5,
731
- changed_files: 3,
732
- comments: 2,
733
- review_comments: 2,
734
- closed_at: Time.parse('2024-12-20'),
735
- merged_at: Time.parse('2024-12-20'),
736
- created_at: Time.parse('2024-09-20')
737
- }
730
+ },
731
+ base: {
732
+ repo: {
733
+ full_name: repo
734
+ }
735
+ },
736
+ state: 'closed',
737
+ user: { login: 'yegor256', id: 526_301, type: 'User' },
738
+ head: { ref: 'master', sha: '6dcb09b5b57875f334f61aebed695e2e4193db5e' },
739
+ additions: 12,
740
+ deletions: 5,
741
+ changed_files: 3,
742
+ comments: 2,
743
+ review_comments: 2,
744
+ closed_at: Time.parse('2024-12-20'),
745
+ merged_at: Time.parse('2024-12-20'),
746
+ created_at: Time.parse('2024-09-20')
747
+ }
748
+ end
738
749
  end
739
750
 
740
751
  # Lists pull requests for a repository.
@@ -831,6 +842,13 @@ class Fbe::FakeOctokit
831
842
  ]
832
843
  end
833
844
 
845
+ def pull_request_review_comments(_repo, _number, _review, _options = {})
846
+ [
847
+ { id: 22_447_120, user: { login: 'yegor256', id: 526_301, type: 'User' } },
848
+ { id: 22_447_121, user: { login: 'yegor256', id: 526_301, type: 'User' } }
849
+ ]
850
+ end
851
+
834
852
  def review_comments(_repo, _number)
835
853
  [
836
854
  {
data/lib/fbe.rb CHANGED
@@ -10,5 +10,5 @@
10
10
  # License:: MIT
11
11
  module Fbe
12
12
  # Current version of the gem (changed by +.rultor.yml+ on every release)
13
- VERSION = '0.30.0' unless const_defined?(:VERSION)
13
+ VERSION = '0.31.1' unless const_defined?(:VERSION)
14
14
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fbe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.0
4
+ version: 0.31.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -391,37 +391,7 @@ files:
391
391
  - lib/fbe/tombstone.rb
392
392
  - lib/fbe/unmask_repos.rb
393
393
  - lib/fbe/who.rb
394
- - renovate.json
395
394
  - rules/basic.fe
396
- - test/fbe/middleware/test_formatter.rb
397
- - test/fbe/middleware/test_rate_limit.rb
398
- - test/fbe/middleware/test_sqlite_store.rb
399
- - test/fbe/middleware/test_trace.rb
400
- - test/fbe/test_award.rb
401
- - test/fbe/test_bylaws.rb
402
- - test/fbe/test_conclude.rb
403
- - test/fbe/test_copy.rb
404
- - test/fbe/test_delete.rb
405
- - test/fbe/test_delete_one.rb
406
- - test/fbe/test_enter.rb
407
- - test/fbe/test_fb.rb
408
- - test/fbe/test_github_graph.rb
409
- - test/fbe/test_if_absent.rb
410
- - test/fbe/test_issue.rb
411
- - test/fbe/test_iterate.rb
412
- - test/fbe/test_just_one.rb
413
- - test/fbe/test_kill_if.rb
414
- - test/fbe/test_octo.rb
415
- - test/fbe/test_overwrite.rb
416
- - test/fbe/test_pmp.rb
417
- - test/fbe/test_regularly.rb
418
- - test/fbe/test_repeatedly.rb
419
- - test/fbe/test_sec.rb
420
- - test/fbe/test_tombstone.rb
421
- - test/fbe/test_unmask_repos.rb
422
- - test/fbe/test_who.rb
423
- - test/test__helper.rb
424
- - test/test_fbe.rb
425
395
  homepage: https://github.com/zerocracy/fbe
426
396
  licenses:
427
397
  - MIT
data/renovate.json DELETED
@@ -1,6 +0,0 @@
1
- {
2
- "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
- "extends": [
4
- "config:base"
5
- ]
6
- }
@@ -1,104 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
4
- # SPDX-License-Identifier: MIT
5
-
6
- require 'faraday'
7
- require 'loog'
8
- require 'securerandom'
9
- require_relative '../../../lib/fbe'
10
- require_relative '../../../lib/fbe/middleware'
11
- require_relative '../../../lib/fbe/middleware/formatter'
12
- require_relative '../../test__helper'
13
-
14
- # Test.
15
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
16
- # Copyright:: Copyright (c) 2024-2025 Zerocracy
17
- # License:: MIT
18
- class LoggingFormatterTest < Fbe::Test
19
- def test_success_response
20
- log_it(status: 200) do |loog|
21
- assert_empty(loog.to_s)
22
- end
23
- end
24
-
25
- def test_forward_response
26
- log_it(status: 303) do |loog|
27
- assert_empty(loog.to_s)
28
- end
29
- end
30
-
31
- def test_error_response
32
- log_it(status: 401) do |loog|
33
- str = loog.to_s
34
- refute_empty(str)
35
- [
36
- %r{http://example.com},
37
- /Authorization:/,
38
- %r{HTTP/1.1 401},
39
- /x-github-api-version-selected: "2022-11-28"/,
40
- /hello, world!/,
41
- /request body/
42
- ].each { |ptn| assert_match(ptn, str) }
43
- end
44
- end
45
-
46
- def test_limit_response
47
- log_it(status: 403) do |loog|
48
- str = loog.to_s
49
- refute_empty(str)
50
- end
51
- end
52
-
53
- def test_truncate_body_for_error_text_response
54
- body = SecureRandom.alphanumeric(120)
55
- log_it(
56
- status: 502,
57
- response_body: body,
58
- response_headers: {
59
- 'content-type' => 'text/html; charset=utf-8',
60
- 'x-github-api-version-selected' => '2022-11-28'
61
- }
62
- ) do |loog|
63
- str = loog.to_s
64
- refute_empty(str)
65
- [
66
- %r{http://example.com},
67
- /Authorization:/,
68
- /some request body/,
69
- %r{HTTP/1.1 502},
70
- /x-github-api-version-selected: "2022-11-28"/,
71
- %r{content-type: "text/html; charset=utf-8"},
72
- "#{body.slice(0, 97)}..."
73
- ].each { |ptn| assert_match(ptn, str) }
74
- end
75
- end
76
-
77
- private
78
-
79
- def log_it(
80
- status:,
81
- method: :get,
82
- response_body: '{"message": "hello, world!"}',
83
- response_headers: { 'content-type' => 'application/json', 'x-github-api-version-selected' => '2022-11-28' }
84
- )
85
- loog = Loog::Buffer.new
86
- formatter = Fbe::Middleware::Formatter.new(logger: loog, options: {})
87
- formatter.request(
88
- Faraday::Env.from(
89
- {
90
- method:,
91
- request_body: 'some request body',
92
- url: URI('http://example.com'),
93
- request_headers: {
94
- 'Authorization' => 'Bearer github_pat_11AAsecret'
95
- }
96
- }
97
- )
98
- )
99
- formatter.response(
100
- Faraday::Env.from({ status:, response_body:, response_headers: })
101
- )
102
- yield loog
103
- end
104
- end
@@ -1,152 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
4
- # SPDX-License-Identifier: MIT
5
-
6
- require 'faraday'
7
- require 'webmock'
8
- require_relative '../../../lib/fbe'
9
- require_relative '../../../lib/fbe/middleware'
10
- require_relative '../../../lib/fbe/middleware/rate_limit'
11
- require_relative '../../test__helper'
12
-
13
- # Test.
14
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
15
- # Copyright:: Copyright (c) 2024-2025 Zerocracy
16
- # License:: MIT
17
- class RateLimitTest < Fbe::Test
18
- def test_caches_rate_limit_response_on_first_call
19
- rate_limit_response = {
20
- 'rate' => {
21
- 'limit' => 5000,
22
- 'remaining' => 4999,
23
- 'reset' => 1_672_531_200
24
- }
25
- }
26
- stub_request(:get, 'https://api.github.com/rate_limit')
27
- .to_return(status: 200, body: rate_limit_response.to_json, headers: { 'Content-Type' => 'application/json' })
28
- conn = create_connection
29
- response = conn.get('/rate_limit')
30
- assert_equal 200, response.status
31
- assert_equal 4999, response.body['rate']['remaining']
32
- end
33
-
34
- def test_returns_cached_response_on_subsequent_calls
35
- rate_limit_response = {
36
- 'rate' => {
37
- 'limit' => 5000,
38
- 'remaining' => 4999,
39
- 'reset' => 1_672_531_200
40
- }
41
- }
42
- stub_request(:get, 'https://api.github.com/rate_limit')
43
- .to_return(status: 200, body: rate_limit_response.to_json, headers: { 'Content-Type' => 'application/json' })
44
- .times(1)
45
- conn = create_connection
46
- conn.get('/rate_limit')
47
- response = conn.get('/rate_limit')
48
- assert_equal 200, response.status
49
- assert_equal 4999, response.body['rate']['remaining']
50
- assert_requested :get, 'https://api.github.com/rate_limit', times: 1
51
- end
52
-
53
- def test_decrements_remaining_count_for_non_rate_limit_requests
54
- rate_limit_response = {
55
- 'rate' => {
56
- 'limit' => 5000,
57
- 'remaining' => 4999,
58
- 'reset' => 1_672_531_200
59
- }
60
- }
61
- stub_request(:get, 'https://api.github.com/rate_limit')
62
- .to_return(status: 200, body: rate_limit_response.to_json, headers: { 'Content-Type' => 'application/json',
63
- 'X-RateLimit-Remaining' => '4999' })
64
- stub_request(:get, 'https://api.github.com/user')
65
- .to_return(status: 200, body: '{"login": "test"}', headers: { 'Content-Type' => 'application/json' })
66
- conn = create_connection
67
- conn.get('/rate_limit')
68
- conn.get('/user')
69
- response = conn.get('/rate_limit')
70
- assert_equal 4998, response.body['rate']['remaining']
71
- assert_equal '4998', response.headers['x-ratelimit-remaining']
72
- end
73
-
74
- def test_refreshes_cache_after_hundred_requests
75
- rate_limit_response = {
76
- 'rate' => {
77
- 'limit' => 5000,
78
- 'remaining' => 4999,
79
- 'reset' => 1_672_531_200
80
- }
81
- }
82
- refreshed_response = {
83
- 'rate' => {
84
- 'limit' => 5000,
85
- 'remaining' => 4950,
86
- 'reset' => 1_672_531_200
87
- }
88
- }
89
- stub_request(:get, 'https://api.github.com/rate_limit')
90
- .to_return(status: 200, body: rate_limit_response.to_json, headers: { 'Content-Type' => 'application/json' })
91
- .then
92
- .to_return(status: 200, body: refreshed_response.to_json, headers: { 'Content-Type' => 'application/json' })
93
- stub_request(:get, 'https://api.github.com/user')
94
- .to_return(status: 200, body: '{"login": "test"}', headers: { 'Content-Type' => 'application/json' })
95
- .times(100)
96
- conn = create_connection
97
- conn.get('/rate_limit')
98
- 100.times { conn.get('/user') }
99
- response = conn.get('/rate_limit')
100
- assert_equal 4950, response.body['rate']['remaining']
101
- assert_requested :get, 'https://api.github.com/rate_limit', times: 2
102
- end
103
-
104
- def test_handles_response_without_rate_data
105
- stub_request(:get, 'https://api.github.com/rate_limit')
106
- .to_return(status: 200, body: '{}', headers: { 'Content-Type' => 'application/json' })
107
- conn = create_connection
108
- response = conn.get('/rate_limit')
109
- assert_equal 200, response.status
110
- assert_empty(response.body)
111
- end
112
-
113
- def test_ignores_non_hash_response_body
114
- stub_request(:get, 'https://api.github.com/rate_limit')
115
- .to_return(status: 200, body: 'invalid json', headers: { 'Content-Type' => 'text/plain' })
116
- conn = create_connection
117
- response = conn.get('/rate_limit')
118
- assert_equal 200, response.status
119
- assert_equal 'invalid json', response.body
120
- end
121
-
122
- def test_handles_zero_remaining_count
123
- rate_limit_response = {
124
- 'rate' => {
125
- 'limit' => 5000,
126
- 'remaining' => 1,
127
- 'reset' => 1_672_531_200
128
- }
129
- }
130
- stub_request(:get, 'https://api.github.com/rate_limit')
131
- .to_return(status: 200, body: rate_limit_response.to_json, headers: { 'Content-Type' => 'application/json' })
132
- stub_request(:get, 'https://api.github.com/user')
133
- .to_return(status: 200, body: '{"login": "test"}', headers: { 'Content-Type' => 'application/json' })
134
- .times(2)
135
- conn = create_connection
136
- conn.get('/rate_limit')
137
- conn.get('/user')
138
- conn.get('/user')
139
- response = conn.get('/rate_limit')
140
- assert_equal 0, response.body['rate']['remaining']
141
- end
142
-
143
- private
144
-
145
- def create_connection
146
- Faraday.new(url: 'https://api.github.com') do |f|
147
- f.use Fbe::Middleware::RateLimit
148
- f.response :json
149
- f.adapter :net_http
150
- end
151
- end
152
- end