fbe 0.6.0 → 0.7.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/Gemfile +1 -0
- data/Gemfile.lock +4 -2
- data/Rakefile +0 -2
- data/lib/fbe/iterate.rb +12 -8
- data/lib/fbe/octo.rb +3 -5
- data/lib/fbe.rb +1 -1
- data/test/fbe/test_octo.rb +20 -23
- data/test/test__helper.rb +2 -0
- metadata +2 -4
- data/lib/fbe/middleware/quota.rb +0 -64
- data/test/fbe/middleware/test_quota.rb +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af8e39332315cd637642316ea61761792955d43688813b75339b112b58747900
|
4
|
+
data.tar.gz: 6a2fa9d6c135c1ec2500872ace2bba09d00a89fe87c1af6435e54e880f361df4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 94a48b37c3d821a8c609e99accfc1fb350b1e317f2cb27c7d351a8a472ff1565edec77d4a3bd2a1d39c758c8e6faa71e5706a1a30fe0364bceffd25144466642
|
7
|
+
data.tar.gz: 8073b49266007c50ae6989ffb1b006fbcddce056cb042be19f5ca39c4e99ad97b58ad77c598d51102b51ef77b9545a4f86fd29cf0323edb7fee9920ff6e65227
|
data/Gemfile
CHANGED
@@ -17,5 +17,6 @@ gem 'rubocop-performance', '>0', require: false
|
|
17
17
|
gem 'rubocop-rake', '>0', require: false
|
18
18
|
gem 'simplecov', '~>0.22', require: false
|
19
19
|
gem 'simplecov-cobertura', '~>2.1', require: false
|
20
|
+
gem 'veils', '>0', require: false
|
20
21
|
gem 'webmock', '~>3.25', require: false
|
21
22
|
gem 'yard', '~>0.9', require: false
|
data/Gemfile.lock
CHANGED
@@ -99,7 +99,7 @@ GEM
|
|
99
99
|
fiber-storage (1.0.0)
|
100
100
|
gli (2.22.2)
|
101
101
|
ostruct
|
102
|
-
graphql (2.5.
|
102
|
+
graphql (2.5.3)
|
103
103
|
base64
|
104
104
|
fiber-storage
|
105
105
|
logger
|
@@ -158,7 +158,7 @@ GEM
|
|
158
158
|
os (1.1.4)
|
159
159
|
ostruct (0.6.1)
|
160
160
|
others (0.0.3)
|
161
|
-
parallel (1.
|
161
|
+
parallel (1.27.0)
|
162
162
|
parser (3.3.8.0)
|
163
163
|
ast (~> 2.4.1)
|
164
164
|
racc
|
@@ -225,6 +225,7 @@ GEM
|
|
225
225
|
unicode-emoji (~> 4.0, >= 4.0.4)
|
226
226
|
unicode-emoji (4.0.4)
|
227
227
|
uri (1.0.3)
|
228
|
+
veils (0.4.0)
|
228
229
|
verbose (0.0.2)
|
229
230
|
loog (~> 0.2)
|
230
231
|
tago (~> 0.0)
|
@@ -257,6 +258,7 @@ DEPENDENCIES
|
|
257
258
|
rubocop-rake (> 0)
|
258
259
|
simplecov (~> 0.22)
|
259
260
|
simplecov-cobertura (~> 2.1)
|
261
|
+
veils (> 0)
|
260
262
|
webmock (~> 3.25)
|
261
263
|
yard (~> 0.9)
|
262
264
|
|
data/Rakefile
CHANGED
data/lib/fbe/iterate.rb
CHANGED
@@ -107,11 +107,23 @@ class Fbe::Iterate
|
|
107
107
|
raise 'Use "by" first' if @query.nil?
|
108
108
|
seen = {}
|
109
109
|
oct = Fbe.octo(loog: @loog, options: @options, global: @global)
|
110
|
+
if oct.off_quota
|
111
|
+
@loog.debug('We are off GitHub quota, cannot even start, sorry')
|
112
|
+
return
|
113
|
+
end
|
110
114
|
repos = Fbe.unmask_repos(loog: @loog, options: @options, global: @global)
|
111
115
|
restarted = []
|
112
116
|
start = Time.now
|
113
117
|
loop do
|
118
|
+
if oct.off_quota
|
119
|
+
@loog.info("We are off GitHub quota, time to stop after #{start.ago}")
|
120
|
+
break
|
121
|
+
end
|
114
122
|
repos.each do |repo|
|
123
|
+
if oct.off_quota
|
124
|
+
@loog.debug("We are off GitHub quota, we must skip #{repo}")
|
125
|
+
break
|
126
|
+
end
|
115
127
|
if Time.now - start > timeout
|
116
128
|
$loog.info("We are doing this for #{start.ago} already, won't check #{repo}")
|
117
129
|
next
|
@@ -152,14 +164,6 @@ class Fbe::Iterate
|
|
152
164
|
end
|
153
165
|
f.what = @label
|
154
166
|
seen[repo] += 1
|
155
|
-
if oct.off_quota
|
156
|
-
@loog.debug('We are off GitHub quota, time to stop')
|
157
|
-
break
|
158
|
-
end
|
159
|
-
end
|
160
|
-
if oct.off_quota
|
161
|
-
@loog.info("We are off GitHub quota, time to stop after #{start.ago}")
|
162
|
-
break
|
163
167
|
end
|
164
168
|
unless seen.any? { |r, v| v < @repeats && !restarted.include?(r) }
|
165
169
|
@loog.debug("No more repos to scan (out of #{repos.size}), quitting after #{start.ago}")
|
data/lib/fbe/octo.rb
CHANGED
@@ -13,7 +13,6 @@ require 'verbose'
|
|
13
13
|
require_relative '../fbe'
|
14
14
|
require_relative 'middleware'
|
15
15
|
require_relative 'middleware/formatter'
|
16
|
-
require_relative 'middleware/quota'
|
17
16
|
|
18
17
|
# Makes a call to the GitHub API.
|
19
18
|
#
|
@@ -71,7 +70,6 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
71
70
|
methods: [:get],
|
72
71
|
backoff_factor: 2
|
73
72
|
)
|
74
|
-
builder.use(Fbe::Middleware::Quota, loog:, pause: options.github_api_pause || 60)
|
75
73
|
builder.use(Faraday::HttpCache, serializer: Marshal, shared_cache: false, logger: Loog::NULL)
|
76
74
|
builder.use(Octokit::Response::RaiseError)
|
77
75
|
builder.use(Faraday::Response::Logger, loog, formatter: Fbe::Middleware::Formatter)
|
@@ -84,10 +82,10 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
84
82
|
o = Fbe::FakeOctokit.new
|
85
83
|
end
|
86
84
|
decoor(o, loog:) do
|
87
|
-
def off_quota
|
85
|
+
def off_quota(threshold: 50)
|
88
86
|
left = @origin.rate_limit.remaining
|
89
|
-
if left <
|
90
|
-
@loog.info("Too much GitHub API quota consumed already (
|
87
|
+
if left < threshold
|
88
|
+
@loog.info("Too much GitHub API quota consumed already (#{left} < #{threshold}), stopping")
|
91
89
|
true
|
92
90
|
else
|
93
91
|
false
|
data/lib/fbe.rb
CHANGED
data/test/fbe/test_octo.rb
CHANGED
@@ -133,29 +133,20 @@ class TestOcto < Fbe::Test
|
|
133
133
|
|
134
134
|
def test_pauses_when_quota_is_exceeded
|
135
135
|
WebMock.disable_net_connect!
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
'x-ratelimit-remaining' => limit.to_s
|
151
|
-
}
|
152
|
-
)
|
153
|
-
.times(1)
|
154
|
-
o.user(user)
|
155
|
-
refute(o.off_quota) if n > 100
|
156
|
-
limit -= 1
|
157
|
-
end
|
158
|
-
assert_in_delta(pause, Time.now - start_time, 5)
|
136
|
+
o = Fbe.octo(loog: Loog::NULL, global: {}, options: Judges::Options.new({ 'github_api_pause' => 0.01 }))
|
137
|
+
stub_request(:get, 'https://api.github.com/users/foo')
|
138
|
+
.to_return(
|
139
|
+
status: 200, body: '{}',
|
140
|
+
headers: { 'x-ratelimit-remaining' => '1' }
|
141
|
+
)
|
142
|
+
.to_return(
|
143
|
+
status: 200, body: '{}',
|
144
|
+
headers: { 'x-ratelimit-remaining' => '10000' }
|
145
|
+
)
|
146
|
+
o.user('foo')
|
147
|
+
assert(o.off_quota)
|
148
|
+
o.user('foo')
|
149
|
+
refute(o.off_quota)
|
159
150
|
end
|
160
151
|
|
161
152
|
def test_fetches_fake_check_runs_for_ref
|
@@ -193,4 +184,10 @@ class TestOcto < Fbe::Test
|
|
193
184
|
result = o.workflow_run_job('zerocracy/baza', 0)
|
194
185
|
assert_equal(0, result[:id])
|
195
186
|
end
|
187
|
+
|
188
|
+
def test_reads_quota
|
189
|
+
WebMock.enable_net_connect!
|
190
|
+
o = Fbe.octo(loog: Loog::VERBOSE, global: {}, options: Judges::Options.new({ 'github_api_pause' => 0.01 }))
|
191
|
+
refute_nil(o.off_quota)
|
192
|
+
end
|
196
193
|
end
|
data/test/test__helper.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fbe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-04-
|
10
|
+
date: 2025-04-15 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: backtrace
|
@@ -305,7 +305,6 @@ files:
|
|
305
305
|
- lib/fbe/just_one.rb
|
306
306
|
- lib/fbe/middleware.rb
|
307
307
|
- lib/fbe/middleware/formatter.rb
|
308
|
-
- lib/fbe/middleware/quota.rb
|
309
308
|
- lib/fbe/octo.rb
|
310
309
|
- lib/fbe/overwrite.rb
|
311
310
|
- lib/fbe/pmp.rb
|
@@ -317,7 +316,6 @@ files:
|
|
317
316
|
- renovate.json
|
318
317
|
- rules/basic.fe
|
319
318
|
- test/fbe/middleware/test_formatter.rb
|
320
|
-
- test/fbe/middleware/test_quota.rb
|
321
319
|
- test/fbe/test_award.rb
|
322
320
|
- test/fbe/test_bylaws.rb
|
323
321
|
- test/fbe/test_conclude.rb
|
data/lib/fbe/middleware/quota.rb
DELETED
@@ -1,64 +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_relative '../middleware'
|
8
|
-
|
9
|
-
# Faraday Middleware that monitors GitHub API rate limits.
|
10
|
-
#
|
11
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
12
|
-
# Copyright:: Copyright (c) 2024-2025 Zerocracy
|
13
|
-
# License:: MIT
|
14
|
-
class Fbe::Middleware::Quota < Faraday::Middleware
|
15
|
-
# Constructor.
|
16
|
-
#
|
17
|
-
# @param [Object] app The Faraday app
|
18
|
-
# @param [Loog] loog The logging facility
|
19
|
-
# @param [Integer] pause Seconds to pause when rate limit is reached
|
20
|
-
# @param [Integer] limit Maximum number of requests before checking rate limit
|
21
|
-
# @param [Integer] rate Minimum remaining requests threshold
|
22
|
-
def initialize(app, loog: Loog::NULL, pause: 60, limit: 100, rate: 5)
|
23
|
-
super(app)
|
24
|
-
@requests = 0
|
25
|
-
@app = app
|
26
|
-
raise 'The "loog" cannot be nil' if loog.nil?
|
27
|
-
@loog = loog
|
28
|
-
raise 'The "pause" cannot be nil' if pause.nil?
|
29
|
-
raise 'The "pause" must be a positive integer' unless pause.positive?
|
30
|
-
@pause = pause
|
31
|
-
raise 'The "limit" cannot be nil' if limit.nil?
|
32
|
-
raise 'The "limit" must be a positive integer' unless limit.positive?
|
33
|
-
@limit = limit
|
34
|
-
raise 'The "rate" cannot be nil' if rate.nil?
|
35
|
-
raise 'The "rate" must be a positive integer' unless rate.positive?
|
36
|
-
@rate = rate
|
37
|
-
end
|
38
|
-
|
39
|
-
# Process the request and handle rate limiting.
|
40
|
-
#
|
41
|
-
# @param [Faraday::Env] env The environment
|
42
|
-
# @return [Faraday::Response] The response
|
43
|
-
def call(env)
|
44
|
-
@requests += 1
|
45
|
-
response = @app.call(env)
|
46
|
-
if out_of_limit?(env)
|
47
|
-
@loog.info("Too much GitHub API quota consumed, pausing for #{@pause} seconds")
|
48
|
-
sleep(@pause)
|
49
|
-
@requests = 0
|
50
|
-
end
|
51
|
-
response
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
# Check if we're approaching the rate limit.
|
57
|
-
#
|
58
|
-
# @param [Faraday::Env] env The environment
|
59
|
-
# @return [Boolean] True if we should pause to avoid hitting rate limits
|
60
|
-
def out_of_limit?(env)
|
61
|
-
remaining = env.response_headers['x-ratelimit-remaining'].to_i
|
62
|
-
(@requests % @limit).zero? && remaining < @rate
|
63
|
-
end
|
64
|
-
end
|
@@ -1,66 +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 'logger'
|
8
|
-
require 'loog'
|
9
|
-
require 'judges'
|
10
|
-
require 'judges/options'
|
11
|
-
require_relative '../../../lib/fbe/middleware'
|
12
|
-
require_relative '../../../lib/fbe/middleware/quota'
|
13
|
-
require_relative '../../test__helper'
|
14
|
-
|
15
|
-
class QuotaTest < Fbe::Test
|
16
|
-
class FakeApp
|
17
|
-
def initialize
|
18
|
-
@calls = 0
|
19
|
-
end
|
20
|
-
|
21
|
-
def call(env)
|
22
|
-
@calls += 1
|
23
|
-
response_headers = {
|
24
|
-
'x-ratelimit-remaining' => (100 - @calls).to_s
|
25
|
-
}
|
26
|
-
env[:response_headers] = response_headers
|
27
|
-
env
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_quota_middleware_pauses_when_quota_low
|
32
|
-
loog = Loog::NULL
|
33
|
-
pause = 0.1
|
34
|
-
app = FakeApp.new
|
35
|
-
middleware = Fbe::Middleware::Quota.new(app, loog:, pause:)
|
36
|
-
start_time = Time.now
|
37
|
-
105.times do
|
38
|
-
env = Judges::Options.new(
|
39
|
-
'method' => :get,
|
40
|
-
'url' => 'http://example.com',
|
41
|
-
'request_headers' => {},
|
42
|
-
'response_headers' => {}
|
43
|
-
)
|
44
|
-
middleware.call(env)
|
45
|
-
end
|
46
|
-
assert_in_delta pause, Time.now - start_time, 0.4
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_quota_middleware_logs_when_quota_low
|
50
|
-
pause = 0.1
|
51
|
-
log_output = StringIO.new
|
52
|
-
loog = Logger.new(log_output)
|
53
|
-
app = FakeApp.new
|
54
|
-
middleware = Fbe::Middleware::Quota.new(app, loog:, pause:)
|
55
|
-
105.times do
|
56
|
-
env = Judges::Options.new(
|
57
|
-
'method' => :get,
|
58
|
-
'url' => 'http://example.com',
|
59
|
-
'request_headers' => {},
|
60
|
-
'response_headers' => {}
|
61
|
-
)
|
62
|
-
middleware.call(env)
|
63
|
-
end
|
64
|
-
assert_match(/Too much GitHub API quota/, log_output.string)
|
65
|
-
end
|
66
|
-
end
|