fbe 0.24.1 → 0.24.3
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.lock +5 -3
- data/fbe.gemspec +1 -0
- data/lib/fbe/award.rb +2 -1
- data/lib/fbe/conclude.rb +16 -13
- data/lib/fbe/iterate.rb +2 -1
- data/lib/fbe/octo.rb +13 -3
- data/lib/fbe/unmask_repos.rb +5 -2
- data/lib/fbe.rb +1 -1
- data/test/fbe/test_conclude.rb +44 -0
- data/test/fbe/test_octo.rb +47 -0
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce758baa2b569c87b5c6318bd2a58df0a5041c578164bb07f337c197a83ef4a7
|
4
|
+
data.tar.gz: fa85c249bc4ea36ecf435e0412bccd9a1c8885ed222f0538be0c02ebd4f59ccc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 43e184c1ee6955ca80cd5a4ba01aa47cf5e59ce8ad1767c03e535c77c253a1bb9223d6603825ef99c6d094828d03e3ae7b6a68e3cc4b7766cfb108c3058fa714
|
7
|
+
data.tar.gz: f1399b8d6b1022a2460f6c1049bd2b58aa924933773c0bdbec3cc21ba65e28aeca6712d382fdd070e0ec5f44f8c5ac3608aacdb9d87857c11f00b45bc6efd728
|
data/Gemfile.lock
CHANGED
@@ -14,6 +14,7 @@ PATH
|
|
14
14
|
filesize (~> 0.2)
|
15
15
|
graphql-client (~> 0.26)
|
16
16
|
intercepted (~> 0.2)
|
17
|
+
joined (~> 0.1)
|
17
18
|
judges (~> 0.46)
|
18
19
|
liquid (~> 5.5)
|
19
20
|
loog (~> 0.6)
|
@@ -46,7 +47,7 @@ GEM
|
|
46
47
|
ast (2.4.3)
|
47
48
|
backtrace (0.4.1)
|
48
49
|
base64 (0.3.0)
|
49
|
-
baza.rb (0.9.
|
50
|
+
baza.rb (0.9.8)
|
50
51
|
backtrace (~> 0.4)
|
51
52
|
elapsed (~> 0.0)
|
52
53
|
faraday (~> 2.13)
|
@@ -86,7 +87,7 @@ GEM
|
|
86
87
|
others (~> 0.0)
|
87
88
|
tago (~> 0.0)
|
88
89
|
yaml (~> 0.3)
|
89
|
-
faraday (2.13.
|
90
|
+
faraday (2.13.2)
|
90
91
|
faraday-net_http (>= 2.0, < 3.5)
|
91
92
|
json
|
92
93
|
logger
|
@@ -118,6 +119,7 @@ GEM
|
|
118
119
|
concurrent-ruby (~> 1.0)
|
119
120
|
intercepted (0.2.0)
|
120
121
|
iri (0.11.2)
|
122
|
+
joined (0.3.0)
|
121
123
|
json (2.12.2)
|
122
124
|
judges (0.51.0)
|
123
125
|
backtrace (~> 0.4)
|
@@ -187,7 +189,7 @@ GEM
|
|
187
189
|
regexp_parser (2.10.0)
|
188
190
|
retries (0.0.5)
|
189
191
|
rexml (3.4.1)
|
190
|
-
rubocop (1.
|
192
|
+
rubocop (1.78.0)
|
191
193
|
json (~> 2.3)
|
192
194
|
language_server-protocol (~> 3.17.0.2)
|
193
195
|
lint_roller (~> 1.1.0)
|
data/fbe.gemspec
CHANGED
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
|
|
34
34
|
s.add_dependency 'filesize', '~>0.2'
|
35
35
|
s.add_dependency 'graphql-client', '~>0.26'
|
36
36
|
s.add_dependency 'intercepted', '~>0.2'
|
37
|
+
s.add_dependency 'joined', '~>0.1'
|
37
38
|
s.add_dependency 'judges', '~>0.46'
|
38
39
|
s.add_dependency 'liquid', '~>5.5'
|
39
40
|
s.add_dependency 'loog', '~>0.6'
|
data/lib/fbe/award.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
6
|
require 'factbase/syntax'
|
7
|
+
require 'joined'
|
7
8
|
require_relative 'fb'
|
8
9
|
|
9
10
|
# A generator of awards.
|
@@ -146,7 +147,7 @@ class Fbe::Award
|
|
146
147
|
any.calc(bill)
|
147
148
|
elsif any.is_a?(Symbol)
|
148
149
|
v = bill.vars[any]
|
149
|
-
raise "Unknown name #{any.inspect} among: #{bill.vars.keys.map(&:inspect).
|
150
|
+
raise "Unknown name #{any.inspect} among: #{bill.vars.keys.map(&:inspect).joined}" if v.nil?
|
150
151
|
v
|
151
152
|
else
|
152
153
|
any
|
data/lib/fbe/conclude.rb
CHANGED
@@ -17,13 +17,13 @@ require_relative 'if_absent'
|
|
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, &)
|
20
|
+
def Fbe.conclude(fb: Fbe.fb, judge: $judge, loog: $loog, options: $options, global: $global, time: Time, &)
|
21
21
|
raise 'The fb is nil' if fb.nil?
|
22
22
|
raise 'The $judge is not set' if judge.nil?
|
23
23
|
raise 'The $global is not set' if global.nil?
|
24
24
|
raise 'The $options is not set' if options.nil?
|
25
25
|
raise 'The $loog is not set' if loog.nil?
|
26
|
-
c = Fbe::Conclude.new(fb:, judge:, loog:, options:, global:)
|
26
|
+
c = Fbe::Conclude.new(fb:, judge:, loog:, options:, global:, time:)
|
27
27
|
c.instance_eval(&)
|
28
28
|
end
|
29
29
|
|
@@ -58,7 +58,8 @@ class Fbe::Conclude
|
|
58
58
|
# @param [Hash] global The hash for global caching
|
59
59
|
# @param [Judges::Options] options The options coming from the +judges+ tool
|
60
60
|
# @param [Loog] loog The logging facility
|
61
|
-
|
61
|
+
# @param [Time] time The time
|
62
|
+
def initialize(fb:, judge:, global:, options:, loog:, time: Time)
|
62
63
|
@fb = fb
|
63
64
|
@judge = judge
|
64
65
|
@loog = loog
|
@@ -68,6 +69,7 @@ class Fbe::Conclude
|
|
68
69
|
@follows = []
|
69
70
|
@quota_aware = false
|
70
71
|
@timeout = 60
|
72
|
+
@time = time
|
71
73
|
end
|
72
74
|
|
73
75
|
# Make this block aware of GitHub API quota.
|
@@ -180,22 +182,23 @@ class Fbe::Conclude
|
|
180
182
|
# end
|
181
183
|
def roll(&)
|
182
184
|
passed = 0
|
183
|
-
start =
|
185
|
+
start = @time.now
|
184
186
|
oct = Fbe.octo(loog: @loog, options: @options, global: @global)
|
185
187
|
@fb.query(@query).each do |a|
|
188
|
+
if @quota_aware && oct.off_quota?
|
189
|
+
@loog.debug('We ran out of GitHub quota, must stop here')
|
190
|
+
break
|
191
|
+
end
|
192
|
+
now = @time.now
|
193
|
+
if now > start + @timeout
|
194
|
+
@loog.debug("We've spent more than #{start.ago}, must stop here")
|
195
|
+
break
|
196
|
+
end
|
186
197
|
@fb.txn do |fbt|
|
187
|
-
if @quota_aware && oct.off_quota?
|
188
|
-
@loog.debug('We ran out of GitHub quota, must stop here')
|
189
|
-
throw :commit
|
190
|
-
end
|
191
|
-
if Time.now > start + @timeout
|
192
|
-
@loog.debug("We've spent more than #{start.ago}, must stop here")
|
193
|
-
throw :commit
|
194
|
-
end
|
195
198
|
n = yield fbt, a
|
196
199
|
@loog.info("#{n.what}: #{n.details}") unless n.nil?
|
197
|
-
passed += 1
|
198
200
|
end
|
201
|
+
passed += 1
|
199
202
|
end
|
200
203
|
@loog.debug("Found and processed #{passed} facts by: #{@query}")
|
201
204
|
passed
|
data/lib/fbe/iterate.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
|
+
require 'joined'
|
6
7
|
require 'tago'
|
7
8
|
require 'time'
|
8
9
|
require_relative '../fbe'
|
@@ -270,6 +271,6 @@ class Fbe::Iterate
|
|
270
271
|
break
|
271
272
|
end
|
272
273
|
end
|
273
|
-
@loog.debug("Finished scanning #{repos.size} repos in #{start.ago}: #{seen.map { |k, v| "#{k}:#{v}" }.
|
274
|
+
@loog.debug("Finished scanning #{repos.size} repos in #{start.ago}: #{seen.map { |k, v| "#{k}:#{v}" }.joined}")
|
274
275
|
end
|
275
276
|
end
|
data/lib/fbe/octo.rb
CHANGED
@@ -665,7 +665,8 @@ class Fbe::FakeOctokit
|
|
665
665
|
user: { login: 'yegor256', id: 526_301, type: 'User' },
|
666
666
|
created_at: Time.parse('2025-06-01 12:00:55 UTC'),
|
667
667
|
updated_at: Time.parse('2025-06-01 15:47:18 UTC'),
|
668
|
-
closed_at: Time.parse('2025-06-02 15:00:00 UTC')
|
668
|
+
closed_at: Time.parse('2025-06-02 15:00:00 UTC'),
|
669
|
+
closed_by: { id: 526_301, login: 'yegor256' }
|
669
670
|
}
|
670
671
|
elsif number == 143
|
671
672
|
{
|
@@ -676,7 +677,8 @@ class Fbe::FakeOctokit
|
|
676
677
|
pull_request: { merged_at: nil },
|
677
678
|
created_at: Time.parse('2025-05-29 17:00:55 UTC'),
|
678
679
|
updated_at: Time.parse('2025-05-29 19:00:00 UTC'),
|
679
|
-
closed_at: Time.parse('2025-06-01 18:20:00 UTC')
|
680
|
+
closed_at: Time.parse('2025-06-01 18:20:00 UTC'),
|
681
|
+
closed_by: { id: 526_301, login: 'yegor256' }
|
680
682
|
}
|
681
683
|
else
|
682
684
|
{
|
@@ -708,6 +710,12 @@ class Fbe::FakeOctokit
|
|
708
710
|
repo: {
|
709
711
|
full_name: repo
|
710
712
|
},
|
713
|
+
base: {
|
714
|
+
repo: {
|
715
|
+
full_name: repo
|
716
|
+
}
|
717
|
+
},
|
718
|
+
state: 'closed',
|
711
719
|
user: { login: 'yegor256', id: 526_301, type: 'User' },
|
712
720
|
head: { ref: 'master', sha: '6dcb09b5b57875f334f61aebed695e2e4193db5e' },
|
713
721
|
additions: 12,
|
@@ -715,7 +723,9 @@ class Fbe::FakeOctokit
|
|
715
723
|
changed_files: 3,
|
716
724
|
comments: 2,
|
717
725
|
review_comments: 2,
|
718
|
-
|
726
|
+
closed_at: Time.parse('2024-12-20'),
|
727
|
+
merged_at: Time.parse('2024-12-20'),
|
728
|
+
created_at: Time.parse('2024-09-20')
|
719
729
|
}
|
720
730
|
end
|
721
731
|
|
data/lib/fbe/unmask_repos.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
|
+
require 'joined'
|
6
7
|
require_relative '../fbe'
|
7
8
|
require_relative 'octo'
|
8
9
|
|
@@ -53,6 +54,8 @@ end
|
|
53
54
|
# @note Exclusion patterns must start with '-' (e.g., '-org/pattern*')
|
54
55
|
# @note Results are shuffled to distribute load when processing
|
55
56
|
def Fbe.unmask_repos(options: $options, global: $global, loog: $loog)
|
57
|
+
raise 'Repositories mask is not specified' unless options.repositories
|
58
|
+
raise 'Repositories mask is empty' if options.repositories.empty?
|
56
59
|
repos = []
|
57
60
|
octo = Fbe.octo(loog:, global:, options:)
|
58
61
|
masks = (options.repositories || '').split(',')
|
@@ -71,8 +74,8 @@ def Fbe.unmask_repos(options: $options, global: $global, loog: $loog)
|
|
71
74
|
repos.reject! { |r| re.match?(r) }
|
72
75
|
end
|
73
76
|
repos.reject! { |repo| octo.repository(repo)[:archived] }
|
74
|
-
raise "No repos found matching: #{options.repositories}" if repos.empty?
|
77
|
+
raise "No repos found matching: #{options.repositories.inspect}" if repos.empty?
|
75
78
|
repos.shuffle!
|
76
|
-
loog.debug("Scanning #{repos.size} repositories: #{repos.
|
79
|
+
loog.debug("Scanning #{repos.size} repositories: #{repos.joined}...")
|
77
80
|
repos
|
78
81
|
end
|
data/lib/fbe.rb
CHANGED
data/test/fbe/test_conclude.rb
CHANGED
@@ -125,4 +125,48 @@ class TestConclude < Fbe::Test
|
|
125
125
|
end
|
126
126
|
assert_equal(2, fb.size)
|
127
127
|
end
|
128
|
+
|
129
|
+
def test_stop_if_timeout_exceeded
|
130
|
+
$fb = Factbase.new
|
131
|
+
$fb.insert.then do |f|
|
132
|
+
f._id = 1
|
133
|
+
f.foo = 5
|
134
|
+
end
|
135
|
+
$fb.insert.then do |f|
|
136
|
+
f._id = 2
|
137
|
+
f.foo = 4
|
138
|
+
end
|
139
|
+
$fb.insert.then do |f|
|
140
|
+
f._id = 3
|
141
|
+
f.bar = 3
|
142
|
+
end
|
143
|
+
$fb.insert.then do |f|
|
144
|
+
f._id = 4
|
145
|
+
f.foo = 2
|
146
|
+
end
|
147
|
+
$fb.insert.then do |f|
|
148
|
+
f._id = 5
|
149
|
+
f.foo = 1
|
150
|
+
end
|
151
|
+
$global = {}
|
152
|
+
$options = Judges::Options.new({ 'testing' => true })
|
153
|
+
$loog = Loog::NULL
|
154
|
+
$judge = ''
|
155
|
+
total = 0
|
156
|
+
now = Time.now
|
157
|
+
time = Minitest::Mock.new
|
158
|
+
time.expect(:now, now)
|
159
|
+
time.expect(:now, now + 4)
|
160
|
+
time.expect(:now, now + 8)
|
161
|
+
time.expect(:now, now + 12)
|
162
|
+
Fbe.conclude(time: time) do
|
163
|
+
on '(exists foo)'
|
164
|
+
timeout 10
|
165
|
+
consider do |f|
|
166
|
+
total += f.foo
|
167
|
+
end
|
168
|
+
end
|
169
|
+
assert_equal(9, total)
|
170
|
+
time.verify
|
171
|
+
end
|
128
172
|
end
|
data/test/fbe/test_octo.rb
CHANGED
@@ -662,4 +662,51 @@ class TestOcto < Fbe::Test
|
|
662
662
|
https://github.com/octokit/octokit.rb/blob/ea3413c3174571e87c83d358fc893cc7613091fa/lib/octokit/connection.rb#L109-L119
|
663
663
|
MSG
|
664
664
|
end
|
665
|
+
|
666
|
+
def test_octo_cache_still_available_on_duration_of_age
|
667
|
+
WebMock.disable_net_connect!
|
668
|
+
now = Time.now
|
669
|
+
age = 60
|
670
|
+
stub_request(:get, 'https://api.github.com/rate_limit')
|
671
|
+
.to_return(
|
672
|
+
status: 200, headers: { 'Content-Type' => 'application/json', 'X-RateLimit-Remaining' => '5000' },
|
673
|
+
body: { 'rate' => { 'limit' => 5000, 'remaining' => 5000, 'reset' => 1_672_531_200 } }.to_json
|
674
|
+
)
|
675
|
+
Dir.mktmpdir do |dir|
|
676
|
+
sqlite_cache = File.expand_path('t.db', dir)
|
677
|
+
o = Fbe.octo(loog: fake_loog, global: {}, options: Judges::Options.new({ 'sqlite_cache' => sqlite_cache }))
|
678
|
+
stub_request(:get, 'https://api.github.com/repositories/798641472').to_return(
|
679
|
+
status: 200,
|
680
|
+
body: { id: 798_641_472, name: 'factbase' }.to_json,
|
681
|
+
headers: {
|
682
|
+
'Date' => now.httpdate,
|
683
|
+
'Content-Type' => 'application/json; charset=utf-8',
|
684
|
+
'Cache-Control' => "public, max-age=#{age}, s-maxage=#{age}",
|
685
|
+
'Etag' => 'W/"f5f1ea995fd7266816f681aca5a81f539420c469070a47568bebdaa3055487bc"',
|
686
|
+
'Last-Modified' => 'Fri, 04 Jul 2025 13:39:42 GMT'
|
687
|
+
}
|
688
|
+
).times(1).then.to_raise('no more request to /repositories/798641472')
|
689
|
+
assert_equal('factbase', o.repo(798_641_472)['name'])
|
690
|
+
Time.stub(:now, now + age - 1) do
|
691
|
+
assert_equal('factbase', o.repo(798_641_472)['name'])
|
692
|
+
end
|
693
|
+
stub_request(:get, 'https://api.github.com/repositories/798641472').to_return(
|
694
|
+
status: 200,
|
695
|
+
body: { id: 798_641_472, name: 'factbase_changed' }.to_json,
|
696
|
+
headers: {
|
697
|
+
'Date' => (now + age).httpdate,
|
698
|
+
'Content-Type' => 'application/json; charset=utf-8',
|
699
|
+
'Cache-Control' => "public, max-age=#{age}, s-maxage=#{age}",
|
700
|
+
'Etag' => 'W/"f5f1ea995fd7266816f681aca5a81f539420c469070a47568bebdaa3055487be"',
|
701
|
+
'Last-Modified' => 'Fri, 04 Jul 2025 13:39:42 GMT'
|
702
|
+
}
|
703
|
+
).times(1).then.to_raise('no more request to /repositories/798641472')
|
704
|
+
Time.stub(:now, now + age) do
|
705
|
+
assert_equal('factbase_changed', o.repo(798_641_472)['name'])
|
706
|
+
end
|
707
|
+
Time.stub(:now, now + (2 * age) - 1) do
|
708
|
+
assert_equal('factbase_changed', o.repo(798_641_472)['name'])
|
709
|
+
end
|
710
|
+
end
|
711
|
+
end
|
665
712
|
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.24.
|
4
|
+
version: 0.24.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
@@ -177,6 +177,20 @@ dependencies:
|
|
177
177
|
- - "~>"
|
178
178
|
- !ruby/object:Gem::Version
|
179
179
|
version: '0.2'
|
180
|
+
- !ruby/object:Gem::Dependency
|
181
|
+
name: joined
|
182
|
+
requirement: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - "~>"
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0.1'
|
187
|
+
type: :runtime
|
188
|
+
prerelease: false
|
189
|
+
version_requirements: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - "~>"
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0.1'
|
180
194
|
- !ruby/object:Gem::Dependency
|
181
195
|
name: judges
|
182
196
|
requirement: !ruby/object:Gem::Requirement
|