fbe 0.48.2 → 0.48.4
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/.github/workflows/codecov.yml +2 -2
- data/.github/workflows/markdown-lint.yml +1 -1
- data/.github/workflows/typos.yml +1 -1
- data/.rubocop.yml +93 -41
- data/Gemfile +2 -1
- data/Gemfile.lock +61 -53
- data/Rakefile +1 -1
- data/fbe.gemspec +25 -25
- data/lib/fbe/award.rb +20 -33
- data/lib/fbe/bylaws.rb +7 -7
- data/lib/fbe/conclude.rb +19 -19
- data/lib/fbe/consider.rb +1 -1
- data/lib/fbe/copy.rb +4 -4
- data/lib/fbe/delete.rb +3 -3
- data/lib/fbe/delete_one.rb +3 -3
- data/lib/fbe/enter.rb +5 -5
- data/lib/fbe/fb.rb +6 -10
- data/lib/fbe/github_graph.rb +26 -26
- data/lib/fbe/if_absent.rb +4 -4
- data/lib/fbe/issue.rb +8 -8
- data/lib/fbe/iterate.rb +39 -36
- data/lib/fbe/just_one.rb +2 -2
- data/lib/fbe/kill_if.rb +1 -1
- data/lib/fbe/middleware/formatter.rb +1 -1
- data/lib/fbe/middleware/rate_limit.rb +16 -16
- data/lib/fbe/middleware/sqlite_store.rb +53 -52
- data/lib/fbe/middleware/trace.rb +1 -5
- data/lib/fbe/octo.rb +50 -51
- data/lib/fbe/overwrite.rb +13 -13
- data/lib/fbe/pmp.rb +8 -8
- data/lib/fbe/regularly.rb +6 -6
- data/lib/fbe/repeatedly.rb +6 -6
- data/lib/fbe/sec.rb +2 -2
- data/lib/fbe/tombstone.rb +24 -16
- data/lib/fbe/unmask_repos.rb +14 -7
- data/lib/fbe/who.rb +2 -2
- data/lib/fbe.rb +2 -2
- metadata +2 -2
data/lib/fbe/octo.rb
CHANGED
|
@@ -42,10 +42,10 @@ class Fbe::OffQuota < StandardError; end
|
|
|
42
42
|
# @param [Hash] global Hash of global options
|
|
43
43
|
# @param [Loog] loog Logging facility
|
|
44
44
|
# @return [Hash] Usually returns a JSON, as it comes from the GitHub API
|
|
45
|
-
def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
46
|
-
raise 'The $global is not set' if global.nil?
|
|
47
|
-
raise 'The $options is not set' if options.nil?
|
|
48
|
-
raise 'The $loog is not set' if loog.nil?
|
|
45
|
+
def Fbe.octo(options: $options, global: $global, loog: $loog) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
46
|
+
raise(Fbe::Error, 'The $global is not set') if global.nil?
|
|
47
|
+
raise(Fbe::Error, 'The $options is not set') if options.nil?
|
|
48
|
+
raise(Fbe::Error, 'The $loog is not set') if loog.nil?
|
|
49
49
|
global[:octo] ||=
|
|
50
50
|
begin
|
|
51
51
|
loog.info("Fbe version is #{Fbe::VERSION}")
|
|
@@ -73,12 +73,7 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
|
73
73
|
end
|
|
74
74
|
o.auto_paginate = true
|
|
75
75
|
o.per_page = 100
|
|
76
|
-
o.connection_options = {
|
|
77
|
-
request: {
|
|
78
|
-
open_timeout: 15,
|
|
79
|
-
timeout: 15
|
|
80
|
-
}
|
|
81
|
-
}
|
|
76
|
+
o.connection_options = { request: { open_timeout: 15, timeout: 15 } }
|
|
82
77
|
stack =
|
|
83
78
|
Faraday::RackBuilder.new do |builder|
|
|
84
79
|
builder.use(
|
|
@@ -96,27 +91,21 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
|
96
91
|
builder.use(Fbe::Middleware::RateLimit)
|
|
97
92
|
builder.use(Fbe::Middleware::Trace, trace, ignores: [:fresh])
|
|
98
93
|
if options.sqlite_cache
|
|
99
|
-
maxsize = Filesize.from(options.sqlite_cache_maxsize || '100M')
|
|
100
|
-
maxvsize = Filesize.from(options.sqlite_cache_maxvsize || '100K')
|
|
101
|
-
|
|
94
|
+
maxsize = Integer(Filesize.from(options.sqlite_cache_maxsize || '100M'))
|
|
95
|
+
maxvsize = Integer(Filesize.from(options.sqlite_cache_maxvsize || '100K'))
|
|
96
|
+
minage = options.sqlite_cache_min_age.nil? ? nil : Integer(options.sqlite_cache_min_age.to_s, 10)
|
|
102
97
|
store = Fbe::Middleware::SqliteStore.new(
|
|
103
|
-
options.sqlite_cache, Fbe::VERSION, loog:, maxsize:, maxvsize:, ttl: 24, cache_min_age:
|
|
98
|
+
options.sqlite_cache, Fbe::VERSION, loog:, maxsize:, maxvsize:, ttl: 24, cache_min_age: minage
|
|
104
99
|
)
|
|
105
100
|
loog.info(
|
|
106
101
|
"Using HTTP cache in SQLite file: #{store.path} (" \
|
|
107
102
|
"#{File.exist?(store.path) ? Filesize.from(File.size(store.path).to_s).pretty : 'file is absent'}, " \
|
|
108
103
|
"max size: #{Filesize.from(maxsize.to_s).pretty}, max vsize: #{Filesize.from(maxvsize.to_s).pretty})"
|
|
109
104
|
)
|
|
110
|
-
builder.use(
|
|
111
|
-
Faraday::HttpCache,
|
|
112
|
-
store:, serializer: JSON, shared_cache: false, logger: Loog::NULL
|
|
113
|
-
)
|
|
105
|
+
builder.use(Faraday::HttpCache, store:, serializer: JSON, shared_cache: false, logger: Loog::NULL)
|
|
114
106
|
else
|
|
115
107
|
loog.info("No HTTP cache in SQLite file, because 'sqlite_cache' option is not provided")
|
|
116
|
-
builder.use(
|
|
117
|
-
Faraday::HttpCache,
|
|
118
|
-
serializer: Marshal, shared_cache: false, logger: Loog::NULL
|
|
119
|
-
)
|
|
108
|
+
builder.use(Faraday::HttpCache, serializer: Marshal, shared_cache: false, logger: Loog::NULL)
|
|
120
109
|
end
|
|
121
110
|
builder.adapter(Faraday.default_adapter)
|
|
122
111
|
end
|
|
@@ -133,7 +122,7 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
|
133
122
|
o = Fbe::FakeOctokit.new
|
|
134
123
|
end
|
|
135
124
|
o =
|
|
136
|
-
decoor(o, loog:, trace:) do
|
|
125
|
+
decoor(o, loog:, trace:) do # rubocop:disable Metrics/BlockLength
|
|
137
126
|
def print_trace!(all: false, max: 5)
|
|
138
127
|
if @trace.empty?
|
|
139
128
|
@loog.debug('GitHub API trace is empty')
|
|
@@ -165,8 +154,7 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
|
165
154
|
@trace.clear
|
|
166
155
|
end
|
|
167
156
|
end
|
|
168
|
-
|
|
169
|
-
def off_quota?(threshold: 50)
|
|
157
|
+
def off_quota?(threshold: 50) # rubocop:disable Layout/EmptyLineBetweenDefs
|
|
170
158
|
left = @origin.rate_limit!.remaining
|
|
171
159
|
if left < threshold
|
|
172
160
|
@loog.info("Too much GitHub API quota consumed already (#{left} < #{threshold})")
|
|
@@ -176,34 +164,30 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
|
176
164
|
false
|
|
177
165
|
end
|
|
178
166
|
end
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
raise 'The ID of the user
|
|
182
|
-
raise 'The ID of the user must be an Integer' unless id.is_a?(Integer)
|
|
167
|
+
def user_name_by_id(id) # rubocop:disable Layout/EmptyLineBetweenDefs
|
|
168
|
+
raise(Fbe::Error, 'The ID of the user is nil') if id.nil?
|
|
169
|
+
raise(Fbe::Error, 'The ID of the user must be an Integer') unless id.is_a?(Integer)
|
|
183
170
|
json = @origin.user(id)
|
|
184
171
|
name = json[:login].downcase
|
|
185
172
|
@loog.debug("GitHub user ##{id} has a name: @#{name}")
|
|
186
173
|
name
|
|
187
174
|
end
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
raise 'The name of the repo is nil' if name.nil?
|
|
175
|
+
def repo_id_by_name(name) # rubocop:disable Layout/EmptyLineBetweenDefs
|
|
176
|
+
raise(Fbe::Error, 'The name of the repo is nil') if name.nil?
|
|
191
177
|
json = @origin.repository(name)
|
|
192
178
|
id = json[:id]
|
|
193
|
-
raise "Repository #{name} not found" if id.nil?
|
|
179
|
+
raise(Fbe::Error, "Repository #{name} not found") if id.nil?
|
|
194
180
|
@loog.debug("GitHub repository #{name.inspect} has an ID: ##{id}")
|
|
195
181
|
id
|
|
196
182
|
end
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
raise 'The ID of the repo
|
|
200
|
-
raise 'The ID of the repo must be an Integer' unless id.is_a?(Integer)
|
|
183
|
+
def repo_name_by_id(id) # rubocop:disable Layout/EmptyLineBetweenDefs
|
|
184
|
+
raise(Fbe::Error, 'The ID of the repo is nil') if id.nil?
|
|
185
|
+
raise(Fbe::Error, 'The ID of the repo must be an Integer') unless id.is_a?(Integer)
|
|
201
186
|
json = @origin.repository(id)
|
|
202
187
|
name = json[:full_name].downcase
|
|
203
188
|
@loog.debug("GitHub repository ##{id} has a name: #{name}")
|
|
204
189
|
name
|
|
205
190
|
end
|
|
206
|
-
|
|
207
191
|
# Disable auto pagination for octokit client called in block
|
|
208
192
|
#
|
|
209
193
|
# @yield [octo] Give octokit client with disabled auto pagination
|
|
@@ -214,10 +198,10 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
|
214
198
|
# Fbe.octo.with_disable_auto_paginate do |octo|
|
|
215
199
|
# octo.list_issue('zerocracy/fbe', per_page: 1).first
|
|
216
200
|
# end
|
|
217
|
-
def with_disable_auto_paginate
|
|
201
|
+
def with_disable_auto_paginate # rubocop:disable Layout/EmptyLineBetweenDefs
|
|
218
202
|
ap = @origin.auto_paginate
|
|
219
203
|
@origin.auto_paginate = false
|
|
220
|
-
yield
|
|
204
|
+
yield(self) if block_given?
|
|
221
205
|
ensure
|
|
222
206
|
@origin.auto_paginate = ap
|
|
223
207
|
end
|
|
@@ -225,7 +209,7 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
|
|
|
225
209
|
o =
|
|
226
210
|
intercepted(o) do |e, m, _args, _r|
|
|
227
211
|
if e == :before && m != :off_quota? && m != :print_trace! && m != :rate_limit && o.off_quota?
|
|
228
|
-
raise
|
|
212
|
+
raise(Fbe::OffQuota, "We are off-quota (remaining: #{o.rate_limit.remaining}), can't do #{m}()")
|
|
229
213
|
end
|
|
230
214
|
end
|
|
231
215
|
o
|
|
@@ -250,7 +234,7 @@ end
|
|
|
250
234
|
#
|
|
251
235
|
# @note All methods return static or pseudo-random data
|
|
252
236
|
# @note No actual API calls are made
|
|
253
|
-
class Fbe::FakeOctokit
|
|
237
|
+
class Fbe::FakeOctokit # rubocop:disable Metrics/ClassLength, Style/OneClassPerFile
|
|
254
238
|
# Generates a random time in the past.
|
|
255
239
|
#
|
|
256
240
|
# @return [Time] A random time within the last 10,000 seconds
|
|
@@ -304,6 +288,21 @@ class Fbe::FakeOctokit
|
|
|
304
288
|
]
|
|
305
289
|
end
|
|
306
290
|
|
|
291
|
+
# Lists organization repositories, including private ones when the token has access.
|
|
292
|
+
#
|
|
293
|
+
# @param [String] _org The organization name (ignored in mock)
|
|
294
|
+
# @param [Hash] _options Filters such as +type:+ (e.g. 'all', 'private', 'public')
|
|
295
|
+
# @return [Array<Hash>] Array of repository hashes
|
|
296
|
+
# @example
|
|
297
|
+
# client.organization_repositories('zerocracy', type: 'all')
|
|
298
|
+
# # => [{:id=>123, :full_name=>"yegor256/judges", ...}, ...]
|
|
299
|
+
def organization_repositories(_org, _options = {})
|
|
300
|
+
[
|
|
301
|
+
repository('yegor256/judges'),
|
|
302
|
+
repository('yegor256/factbase')
|
|
303
|
+
]
|
|
304
|
+
end
|
|
305
|
+
|
|
307
306
|
# Gets repository invitations for the authenticated user.
|
|
308
307
|
#
|
|
309
308
|
# @param [Hash] _options Additional options (not used in mock)
|
|
@@ -482,7 +481,7 @@ class Fbe::FakeOctokit
|
|
|
482
481
|
# fake_client.accept_repository_invitation(1) #=> true
|
|
483
482
|
# rubocop:disable Naming/PredicateMethod
|
|
484
483
|
def accept_repository_invitation(id)
|
|
485
|
-
raise
|
|
484
|
+
raise(Octokit::NotFound) if id == 404_000
|
|
486
485
|
true
|
|
487
486
|
end
|
|
488
487
|
# rubocop:enable Naming/PredicateMethod
|
|
@@ -509,7 +508,7 @@ class Fbe::FakeOctokit
|
|
|
509
508
|
# fake_client.user(526_301) #=> {:id=>444, :login=>"yegor256", :type=>"User"}
|
|
510
509
|
# fake_client.user('octocat') #=> {:id=>444, :login=>nil, :type=>"User"}
|
|
511
510
|
def user(uid)
|
|
512
|
-
raise
|
|
511
|
+
raise(Octokit::NotFound) if [404_001, 404_002].include?(uid)
|
|
513
512
|
login = (uid == 526_301 ? 'yegor256' : 'torvalds') if uid.is_a?(Integer)
|
|
514
513
|
{
|
|
515
514
|
id: 444,
|
|
@@ -609,13 +608,13 @@ class Fbe::FakeOctokit
|
|
|
609
608
|
# client.repository('octocat/Hello-World')
|
|
610
609
|
# # => {:id=>1296269, :full_name=>"octocat/Hello-World", ...}
|
|
611
610
|
def repository(name)
|
|
612
|
-
raise
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
611
|
+
raise(Octokit::NotFound) if [404_123, 404_124].include?(name)
|
|
612
|
+
repo = name.is_a?(Integer) ? 'yegor256/test' : name
|
|
613
|
+
repo = 'zerocracy/baza' if name == 1439
|
|
614
|
+
repo = 'foo/bazz' if name == 810
|
|
616
615
|
{
|
|
617
616
|
id: name_to_number(name),
|
|
618
|
-
full_name
|
|
617
|
+
full_name: repo,
|
|
619
618
|
default_branch: 'master',
|
|
620
619
|
private: false,
|
|
621
620
|
owner: { login: name.to_s.split('/')[0], id: 526_301, site_admin: false },
|
|
@@ -1179,7 +1178,7 @@ class Fbe::FakeOctokit
|
|
|
1179
1178
|
]
|
|
1180
1179
|
end
|
|
1181
1180
|
|
|
1182
|
-
def repository_events(repo, _options = {})
|
|
1181
|
+
def repository_events(repo, _options = {}) # rubocop:disable Metrics/MethodLength
|
|
1183
1182
|
[
|
|
1184
1183
|
{
|
|
1185
1184
|
id: '123',
|
|
@@ -1508,7 +1507,7 @@ class Fbe::FakeOctokit
|
|
|
1508
1507
|
]
|
|
1509
1508
|
end
|
|
1510
1509
|
|
|
1511
|
-
def check_runs_for_ref(repo, sha)
|
|
1510
|
+
def check_runs_for_ref(repo, sha) # rubocop:disable Metrics/MethodLength
|
|
1512
1511
|
data = {
|
|
1513
1512
|
'zerocracy/baza' => {
|
|
1514
1513
|
total_count: 7,
|
data/lib/fbe/overwrite.rb
CHANGED
|
@@ -31,9 +31,9 @@ require_relative 'fb'
|
|
|
31
31
|
# user = fb.query('(eq login "john")').first
|
|
32
32
|
# Fbe.overwrite(user, status: 'active', role: 'admin')
|
|
33
33
|
# # All properties preserved, 'status' and 'role' are updated
|
|
34
|
-
def Fbe.overwrite(fact, property_or_hash, values = nil, fb: Fbe.fb, fid: '_id')
|
|
35
|
-
raise 'The fact is nil' if fact.nil?
|
|
36
|
-
raise 'The fb is nil' if fb.nil?
|
|
34
|
+
def Fbe.overwrite(fact, property_or_hash, values = nil, fb: Fbe.fb, fid: '_id') # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
35
|
+
raise(Fbe::Error, 'The fact is nil') if fact.nil?
|
|
36
|
+
raise(Fbe::Error, 'The fb is nil') if fb.nil?
|
|
37
37
|
if property_or_hash.is_a?(Hash)
|
|
38
38
|
before = {}
|
|
39
39
|
fact.all_properties.each do |k|
|
|
@@ -41,7 +41,7 @@ def Fbe.overwrite(fact, property_or_hash, values = nil, fb: Fbe.fb, fid: '_id')
|
|
|
41
41
|
end
|
|
42
42
|
modified = false
|
|
43
43
|
property_or_hash.each do |k, vv|
|
|
44
|
-
raise "The value for #{k} is nil" if vv.nil?
|
|
44
|
+
raise(Fbe::Error, "The value for #{k} is nil") if vv.nil?
|
|
45
45
|
vv = [vv] unless vv.is_a?(Array)
|
|
46
46
|
next if before[k.to_s] == vv
|
|
47
47
|
before[k.to_s] = vv
|
|
@@ -49,27 +49,27 @@ def Fbe.overwrite(fact, property_or_hash, values = nil, fb: Fbe.fb, fid: '_id')
|
|
|
49
49
|
end
|
|
50
50
|
return fact unless modified
|
|
51
51
|
id = fact[fid]&.first
|
|
52
|
-
raise "There is no #{fid} in the fact, cannot use Fbe.overwrite" if id.nil?
|
|
53
|
-
raise "No facts by #{fid} = #{id}" if fb.query("(eq #{fid} #{id})").delete!.zero?
|
|
52
|
+
raise(Fbe::Error, "There is no #{fid} in the fact, cannot use Fbe.overwrite") if id.nil?
|
|
53
|
+
raise(Fbe::Error, "No facts by #{fid} = #{id}") if fb.query("(eq #{fid} #{id})").delete!.zero?
|
|
54
54
|
fb.txn do |fbt|
|
|
55
55
|
n = fbt.insert
|
|
56
56
|
before.each do |k, vv|
|
|
57
57
|
next unless n[k].nil?
|
|
58
58
|
vv.each do |v|
|
|
59
|
-
n.
|
|
59
|
+
n.public_send(:"#{k}=", v)
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
62
|
end
|
|
63
63
|
return
|
|
64
64
|
end
|
|
65
65
|
property = property_or_hash
|
|
66
|
-
raise "The property is not a String but #{property.class} (#{property})" unless property.is_a?(String)
|
|
67
|
-
raise 'The values is nil' if values.nil?
|
|
66
|
+
raise(Fbe::Error, "The property is not a String but #{property.class} (#{property})") unless property.is_a?(String)
|
|
67
|
+
raise(Fbe::Error, 'The values is nil') if values.nil?
|
|
68
68
|
values = [values] unless values.is_a?(Array)
|
|
69
69
|
return fact if !fact[property].nil? && fact[property].one? && values.one? && fact[property].first == values.first
|
|
70
70
|
if fact[property].nil?
|
|
71
71
|
values.each do |v|
|
|
72
|
-
fact.
|
|
72
|
+
fact.public_send(:"#{property}=", v)
|
|
73
73
|
end
|
|
74
74
|
return
|
|
75
75
|
end
|
|
@@ -78,15 +78,15 @@ def Fbe.overwrite(fact, property_or_hash, values = nil, fb: Fbe.fb, fid: '_id')
|
|
|
78
78
|
before[k.to_s] = fact[k]
|
|
79
79
|
end
|
|
80
80
|
id = fact[fid]&.first
|
|
81
|
-
raise "There is no #{fid} in the fact, cannot use Fbe.overwrite" if id.nil?
|
|
82
|
-
raise "No facts by #{fid} = #{id}" if fb.query("(eq #{fid} #{id})").delete!.zero?
|
|
81
|
+
raise(Fbe::Error, "There is no #{fid} in the fact, cannot use Fbe.overwrite") if id.nil?
|
|
82
|
+
raise(Fbe::Error, "No facts by #{fid} = #{id}") if fb.query("(eq #{fid} #{id})").delete!.zero?
|
|
83
83
|
fb.txn do |fbt|
|
|
84
84
|
n = fbt.insert
|
|
85
85
|
before[property.to_s] = values
|
|
86
86
|
before.each do |k, vv|
|
|
87
87
|
next unless n[k].nil?
|
|
88
88
|
vv.each do |v|
|
|
89
|
-
n.
|
|
89
|
+
n.public_send(:"#{k}=", v)
|
|
90
90
|
end
|
|
91
91
|
end
|
|
92
92
|
end
|
data/lib/fbe/pmp.rb
CHANGED
|
@@ -42,14 +42,14 @@ require_relative 'fb'
|
|
|
42
42
|
#
|
|
43
43
|
# # Get deadline from time area
|
|
44
44
|
# deadline = Fbe.pmp.time.deadline
|
|
45
|
-
def Fbe.pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog)
|
|
45
|
+
def Fbe.pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog) # rubocop:disable Metrics/AbcSize
|
|
46
46
|
xml = Nokogiri::XML(File.read(File.join(__dir__, '../../assets/pmp.xml')))
|
|
47
47
|
pmpv =
|
|
48
48
|
Class.new(SimpleDelegator) do
|
|
49
|
-
attr_reader :default, :type, :memo
|
|
50
|
-
|
|
49
|
+
attr_reader :default, :type, :memo, :value # rubocop:disable Layout/EmptyLinesAroundAttributeAccessor
|
|
51
50
|
def initialize(value, default, type, memo)
|
|
52
51
|
super(value)
|
|
52
|
+
@value = value
|
|
53
53
|
@default = default
|
|
54
54
|
@type = type
|
|
55
55
|
@memo = memo
|
|
@@ -62,7 +62,7 @@ def Fbe.pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog)
|
|
|
62
62
|
others do |*args1|
|
|
63
63
|
area = args1.first.to_s
|
|
64
64
|
node = xml.at_xpath("/pmp/area[@name='#{area}']")
|
|
65
|
-
raise "Unknown area #{area.inspect}" if node.nil?
|
|
65
|
+
raise Fbe::Error, "Unknown area #{area.inspect}" if node.nil?
|
|
66
66
|
Class.new do
|
|
67
67
|
define_method(:properties) do
|
|
68
68
|
node.xpath('p/name').map(&:text)
|
|
@@ -81,8 +81,8 @@ def Fbe.pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog)
|
|
|
81
81
|
memo = prop.at_xpath('memo').text
|
|
82
82
|
default =
|
|
83
83
|
case type
|
|
84
|
-
when 'int' then default
|
|
85
|
-
when 'float' then default
|
|
84
|
+
when 'int' then Integer(default, 10)
|
|
85
|
+
when 'float' then Float(default)
|
|
86
86
|
when 'bool' then default == 'true'
|
|
87
87
|
else default
|
|
88
88
|
end
|
|
@@ -90,8 +90,8 @@ def Fbe.pmp(fb: Fbe.fb, global: $global, options: $options, loog: $loog)
|
|
|
90
90
|
result ||= default
|
|
91
91
|
result =
|
|
92
92
|
case type
|
|
93
|
-
when 'int' then result.
|
|
94
|
-
when 'float' then result
|
|
93
|
+
when 'int' then Integer(Float(result).truncate)
|
|
94
|
+
when 'float' then Float(result)
|
|
95
95
|
when 'bool' then result == 'true'
|
|
96
96
|
else result
|
|
97
97
|
end
|
data/lib/fbe/regularly.rb
CHANGED
|
@@ -30,11 +30,11 @@ require_relative 'fb'
|
|
|
30
30
|
# # PMP might have: days_between_cleanups=3, cleanup_history_days=30
|
|
31
31
|
# end
|
|
32
32
|
def Fbe.regularly(area, p_every_days, p_since_days = nil, fb: Fbe.fb, judge: $judge, loog: $loog, &)
|
|
33
|
-
raise 'The area is nil' if area.nil?
|
|
34
|
-
raise 'The p_every_days is nil' if p_every_days.nil?
|
|
35
|
-
raise 'The fb is nil' if fb.nil?
|
|
36
|
-
raise 'The $judge is not set' if judge.nil?
|
|
37
|
-
raise 'The $loog is not set' if loog.nil?
|
|
33
|
+
raise(Fbe::Error, 'The area is nil') if area.nil?
|
|
34
|
+
raise(Fbe::Error, 'The p_every_days is nil') if p_every_days.nil?
|
|
35
|
+
raise(Fbe::Error, 'The fb is nil') if fb.nil?
|
|
36
|
+
raise(Fbe::Error, 'The $judge is not set') if judge.nil?
|
|
37
|
+
raise(Fbe::Error, 'The $loog is not set') if loog.nil?
|
|
38
38
|
pmp = fb.query("(and (eq what 'pmp') (eq area '#{area}') (exists #{p_every_days}))").each.first
|
|
39
39
|
interval = pmp.nil? ? 7 : pmp[p_every_days].first
|
|
40
40
|
recent = fb.query(
|
|
@@ -59,7 +59,7 @@ def Fbe.regularly(area, p_every_days, p_since_days = nil, fb: Fbe.fb, judge: $ju
|
|
|
59
59
|
since = Time.now - (days * 24 * 60 * 60)
|
|
60
60
|
f.since = since
|
|
61
61
|
end
|
|
62
|
-
yield
|
|
62
|
+
yield(f)
|
|
63
63
|
end
|
|
64
64
|
nil
|
|
65
65
|
end
|
data/lib/fbe/repeatedly.rb
CHANGED
|
@@ -32,11 +32,11 @@ require_relative 'overwrite'
|
|
|
32
32
|
# # PMP might have: hours_between_checks=6
|
|
33
33
|
# end
|
|
34
34
|
def Fbe.repeatedly(area, p_every_hours, fb: Fbe.fb, judge: $judge, loog: $loog, &)
|
|
35
|
-
raise 'The area is nil' if area.nil?
|
|
36
|
-
raise 'The p_every_hours is nil' if p_every_hours.nil?
|
|
37
|
-
raise 'The fb is nil' if fb.nil?
|
|
38
|
-
raise 'The $judge is not set' if judge.nil?
|
|
39
|
-
raise 'The $loog is not set' if loog.nil?
|
|
35
|
+
raise(Fbe::Error, 'The area is nil') if area.nil?
|
|
36
|
+
raise(Fbe::Error, 'The p_every_hours is nil') if p_every_hours.nil?
|
|
37
|
+
raise(Fbe::Error, 'The fb is nil') if fb.nil?
|
|
38
|
+
raise(Fbe::Error, 'The $judge is not set') if judge.nil?
|
|
39
|
+
raise(Fbe::Error, 'The $loog is not set') if loog.nil?
|
|
40
40
|
pmp = fb.query("(and (eq what 'pmp') (eq area '#{area}') (exists #{p_every_hours}))").each.first
|
|
41
41
|
hours = pmp.nil? ? 24 : pmp[p_every_hours].first
|
|
42
42
|
recent = fb.query(
|
|
@@ -54,6 +54,6 @@ def Fbe.repeatedly(area, p_every_hours, fb: Fbe.fb, judge: $judge, loog: $loog,
|
|
|
54
54
|
f.what = judge
|
|
55
55
|
end
|
|
56
56
|
Fbe.overwrite(f, 'when', Time.now)
|
|
57
|
-
yield
|
|
57
|
+
yield(fb.query("(and (eq what '#{judge}'))").each.first)
|
|
58
58
|
nil
|
|
59
59
|
end
|
data/lib/fbe/sec.rb
CHANGED
|
@@ -24,7 +24,7 @@ require_relative '../fbe'
|
|
|
24
24
|
# puts Fbe.sec(build_fact, :duration) # => "2 hours ago"
|
|
25
25
|
def Fbe.sec(fact, prop = :seconds)
|
|
26
26
|
s = fact[prop.to_s]
|
|
27
|
-
raise "There is no #{prop.inspect} property" if s.nil?
|
|
28
|
-
s = s.first.
|
|
27
|
+
raise(Fbe::Error, "There is no #{prop.inspect} property") if s.nil?
|
|
28
|
+
s = Integer(s.first.to_s, 10)
|
|
29
29
|
(Time.now + s).ago
|
|
30
30
|
end
|
data/lib/fbe/tombstone.rb
CHANGED
|
@@ -27,35 +27,41 @@ class Fbe::Tombstone
|
|
|
27
27
|
# @param [Integer] repo ID of repository
|
|
28
28
|
# @return [Array<Integer>] IDs of issue
|
|
29
29
|
def issues(where, repo)
|
|
30
|
-
raise 'The type of "where" is not String' unless where.is_a?(String)
|
|
31
|
-
raise 'The type of "repo" is not Integer' unless repo.is_a?(Integer)
|
|
30
|
+
raise(Fbe::Error, 'The type of "where" is not String') unless where.is_a?(String)
|
|
31
|
+
raise(Fbe::Error, 'The type of "repo" is not Integer') unless repo.is_a?(Integer)
|
|
32
32
|
f = @fb.query(
|
|
33
33
|
"(and (eq where '#{where}') (eq what 'tombstone') (eq repository #{repo}) (exists issues))"
|
|
34
34
|
).each.first
|
|
35
35
|
return [] if f.nil?
|
|
36
|
-
f['issues'].
|
|
37
|
-
a, b = ii.split('-').map(
|
|
36
|
+
f['issues'].flat_map do |ii|
|
|
37
|
+
a, b = ii.split('-').map { |i| Integer(i, 10) }
|
|
38
38
|
b = a if b.nil?
|
|
39
|
-
(a..b).
|
|
40
|
-
end
|
|
39
|
+
(a..b).to_a
|
|
40
|
+
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
# Put it there.
|
|
44
44
|
# @param [String] where The place, e.g. "github"
|
|
45
45
|
# @param [Integer] repo ID of repository
|
|
46
46
|
# @param [Integer, Array<Integer>] issue ID of issue (or array of them)
|
|
47
|
-
def bury!(where, repo, issue)
|
|
48
|
-
raise 'The type of "where" is not String' unless where.is_a?(String)
|
|
49
|
-
raise 'The type of "repo" is not Integer' unless repo.is_a?(Integer)
|
|
50
|
-
|
|
47
|
+
def bury!(where, repo, issue) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
48
|
+
raise(Fbe::Error, 'The type of "where" is not String') unless where.is_a?(String)
|
|
49
|
+
raise(Fbe::Error, 'The type of "repo" is not Integer') unless repo.is_a?(Integer)
|
|
50
|
+
unless issue.is_a?(Integer) || issue.is_a?(Array)
|
|
51
|
+
raise(Fbe::Error, 'The type of "issue" is neither Integer nor Array')
|
|
52
|
+
end
|
|
51
53
|
f =
|
|
52
54
|
Fbe.if_absent(fb: @fb, always: true) do |n|
|
|
53
55
|
n.what = 'tombstone'
|
|
54
56
|
n.where = where
|
|
55
57
|
n.repository = repo
|
|
56
58
|
end
|
|
57
|
-
f.
|
|
58
|
-
nn = f['issues']&.map
|
|
59
|
+
f.public_send(:"#{@fid}=", SecureRandom.random_number(99_999)) if f[@fid].nil?
|
|
60
|
+
nn = f['issues']&.map do |ii|
|
|
61
|
+
ii.split('-').map do |i|
|
|
62
|
+
Integer(i, 10)
|
|
63
|
+
end.then { |ii| ii.size == 1 ? ii << ii[0] : ii }
|
|
64
|
+
end || []
|
|
59
65
|
issue = [issue] unless issue.is_a?(Array)
|
|
60
66
|
issue.each do |i|
|
|
61
67
|
nn << [i, i]
|
|
@@ -80,9 +86,11 @@ class Fbe::Tombstone
|
|
|
80
86
|
# @param [Integer, Array<Integer>] issue ID of issue (or array of them)
|
|
81
87
|
# @return [Boolean] True if it's there
|
|
82
88
|
def has?(where, repo, issue)
|
|
83
|
-
raise 'The type of "where" is not String' unless where.is_a?(String)
|
|
84
|
-
raise 'The type of "repo" is not Integer' unless repo.is_a?(Integer)
|
|
85
|
-
|
|
89
|
+
raise(Fbe::Error, 'The type of "where" is not String') unless where.is_a?(String)
|
|
90
|
+
raise(Fbe::Error, 'The type of "repo" is not Integer') unless repo.is_a?(Integer)
|
|
91
|
+
unless issue.is_a?(Integer) || issue.is_a?(Array)
|
|
92
|
+
raise(Fbe::Error, 'The type of "issue" is neither Integer nor Array')
|
|
93
|
+
end
|
|
86
94
|
f = @fb.query(
|
|
87
95
|
"(and (eq where '#{where}') (eq what 'tombstone') (eq repository #{repo}) (exists issues))"
|
|
88
96
|
).each.first
|
|
@@ -90,7 +98,7 @@ class Fbe::Tombstone
|
|
|
90
98
|
issue = [issue] unless issue.is_a?(Array)
|
|
91
99
|
issue.all? do |i|
|
|
92
100
|
f['issues'].any? do |ii|
|
|
93
|
-
a, b = ii.split('-').map(
|
|
101
|
+
a, b = ii.split('-').map { |i| Integer(i, 10) }
|
|
94
102
|
b.nil? ? a == i : (a..b).cover?(i)
|
|
95
103
|
end
|
|
96
104
|
end
|
data/lib/fbe/unmask_repos.rb
CHANGED
|
@@ -23,7 +23,7 @@ require_relative 'over'
|
|
|
23
23
|
# @raise [RuntimeError] If organization part contains asterisk
|
|
24
24
|
def Fbe.mask_to_regex(mask)
|
|
25
25
|
org, repo = mask.split('/')
|
|
26
|
-
raise "Org '#{org}' can't have an asterisk" if org.include?('*')
|
|
26
|
+
raise(Fbe::Error, "Org '#{org}' can't have an asterisk") if org.include?('*')
|
|
27
27
|
Regexp.compile("#{org}/#{repo.gsub('*', '.*')}", Regexp::IGNORECASE)
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -59,12 +59,12 @@ end
|
|
|
59
59
|
# @raise [RuntimeError] If no repositories match the provided masks
|
|
60
60
|
# @note Exclusion patterns must start with '-' (e.g., '-org/pattern*')
|
|
61
61
|
# @note Results are shuffled to distribute load when processing
|
|
62
|
-
def Fbe.unmask_repos(
|
|
62
|
+
def Fbe.unmask_repos( # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
63
63
|
options: $options, global: $global, loog: $loog, epoch: $epoch || Time.now, kickoff: $kickoff || Time.now,
|
|
64
64
|
quota_aware: true, lifetime_aware: true, timeout_aware: true
|
|
65
65
|
)
|
|
66
|
-
raise 'Repositories mask is not specified' unless options.repositories
|
|
67
|
-
raise 'Repositories mask is empty' if options.repositories.empty?
|
|
66
|
+
raise(Fbe::Error, 'Repositories mask is not specified') unless options.repositories
|
|
67
|
+
raise(Fbe::Error, 'Repositories mask is empty') if options.repositories.empty?
|
|
68
68
|
return if block_given? && Fbe.over?(
|
|
69
69
|
global:, options:, loog:, epoch:, kickoff:, quota_aware:, lifetime_aware:, timeout_aware:
|
|
70
70
|
)
|
|
@@ -77,7 +77,14 @@ def Fbe.unmask_repos(
|
|
|
77
77
|
next
|
|
78
78
|
end
|
|
79
79
|
re = Fbe.mask_to_regex(mask)
|
|
80
|
-
|
|
80
|
+
org = mask.split('/')[0]
|
|
81
|
+
list =
|
|
82
|
+
begin
|
|
83
|
+
octo.organization_repositories(org, type: 'all')
|
|
84
|
+
rescue Octokit::NotFound
|
|
85
|
+
octo.repositories(org)
|
|
86
|
+
end
|
|
87
|
+
list.each do |r|
|
|
81
88
|
repos << r[:full_name] if re.match?(r[:full_name])
|
|
82
89
|
end
|
|
83
90
|
end
|
|
@@ -86,13 +93,13 @@ def Fbe.unmask_repos(
|
|
|
86
93
|
repos.reject! { |r| re.match?(r) }
|
|
87
94
|
end
|
|
88
95
|
repos.reject! { |repo| octo.repository(repo)[:archived] }
|
|
89
|
-
raise "No repos found matching: #{options.repositories.inspect}" if repos.empty?
|
|
96
|
+
raise(Fbe::Error, "No repos found matching: #{options.repositories.inspect}") if repos.empty?
|
|
90
97
|
repos.shuffle!
|
|
91
98
|
loog.debug("Scanning #{repos.size} repositories: #{repos.joined}...")
|
|
92
99
|
repos.each { |repo| octo.repository(repo) }
|
|
93
100
|
return repos unless block_given?
|
|
94
101
|
repos.each do |repo|
|
|
95
102
|
break if Fbe.over?(global:, options:, loog:, epoch:, kickoff:, quota_aware:, lifetime_aware:, timeout_aware:)
|
|
96
|
-
yield
|
|
103
|
+
yield(repo)
|
|
97
104
|
end
|
|
98
105
|
end
|
data/lib/fbe/who.rb
CHANGED
|
@@ -28,7 +28,7 @@ require_relative 'octo'
|
|
|
28
28
|
# puts Fbe.who(contributor, :author_id) # => "@yegor256"
|
|
29
29
|
def Fbe.who(fact, prop = :who, options: $options, global: $global, loog: $loog)
|
|
30
30
|
id = fact[prop.to_s]
|
|
31
|
-
raise "There is no #{prop.inspect} property" if id.nil?
|
|
32
|
-
id = id.first.
|
|
31
|
+
raise(Fbe::Error, "There is no #{prop.inspect} property") if id.nil?
|
|
32
|
+
id = Integer(id.first.to_s, 10)
|
|
33
33
|
"@#{Fbe.octo(options:, global:, loog:).user_name_by_id(id)}"
|
|
34
34
|
end
|
data/lib/fbe.rb
CHANGED
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
# Copyright:: Copyright (c) 2024-2026 Zerocracy
|
|
10
10
|
# License:: MIT
|
|
11
11
|
module Fbe
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
VERSION = '0.48.4' unless const_defined?(:VERSION)
|
|
13
|
+
class Error < StandardError; end
|
|
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.48.
|
|
4
|
+
version: 0.48.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yegor Bugayenko
|
|
@@ -422,7 +422,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
422
422
|
requirements:
|
|
423
423
|
- - ">="
|
|
424
424
|
- !ruby/object:Gem::Version
|
|
425
|
-
version: '3.
|
|
425
|
+
version: '3.2'
|
|
426
426
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
427
427
|
requirements:
|
|
428
428
|
- - ">="
|