fbe 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ # MIT License
4
+ #
5
+ # Copyright (c) 2024 Zerocracy
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ require_relative '../fbe'
26
+ require_relative 'unmask_repos'
27
+ require_relative 'octo'
28
+ require_relative 'fb'
29
+
30
+ # Create a conclude code block.
31
+ def Fbe.iterate(fbx = Fbe.fb, loog = $loog, &)
32
+ c = Fbe::Iterate.new(fbx, loog)
33
+ c.instance_eval(&)
34
+ end
35
+
36
+ # Iterate.
37
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
38
+ # Copyright:: Copyright (c) 2024 Zerocracy
39
+ # License:: MIT
40
+ class Fbe::Iterate
41
+ def initialize(fb, loog)
42
+ @fb = fb
43
+ @loog = loog
44
+ @label = nil
45
+ @since = 0
46
+ @query = nil
47
+ @limit = 100
48
+ @quota_aware = false
49
+ end
50
+
51
+ def quota_aware
52
+ @quota_aware = true
53
+ end
54
+
55
+ def limit(limit)
56
+ raise 'Cannot set "limit" to nil' if limit.nil?
57
+ @limit = limit
58
+ end
59
+
60
+ def by(query)
61
+ raise 'Query is already set' unless @query.nil?
62
+ raise 'Cannot set query to nil' if query.nil?
63
+ @query = query
64
+ end
65
+
66
+ def as(label)
67
+ raise 'Label is already set' unless @label.nil?
68
+ raise 'Cannot set "label" to nil' if label.nil?
69
+ @label = label
70
+ end
71
+
72
+ def over(&)
73
+ raise 'Use "as" first' if @label.nil?
74
+ raise 'Use "by" first' if @query.nil?
75
+ seen = {}
76
+ oct = Fbe.octo(loog: @loog)
77
+ repos = Fbe.unmask_repos(loog: @loog)
78
+ loop do
79
+ repos.each do |repo|
80
+ seen[repo] = 0 if seen[repo].nil?
81
+ next if seen[repo] > @limit
82
+ rid = oct.repo_id_by_name(repo)
83
+ before = Fbe.fb.query("(agg (and (eq what '#{@label}') (eq repository #{rid})) (first latest))").one
84
+ Fbe.fb.query("(and (eq what '#{@label}') (eq repository #{rid}))").delete!
85
+ before = before.nil? ? @since : before[0]
86
+ nxt = Fbe.fb.query(@query).one(before:, repository: rid)
87
+ after = nxt.nil? ? @since : yield(rid, nxt)
88
+ raise "Iterator must return an Integer, while #{after.class} returned" unless after.is_a?(Integer)
89
+ f = Fbe.fb.insert
90
+ f.repository = rid
91
+ f.latest = after.nil? ? nxt : after
92
+ f.what = @label
93
+ seen[repo] += 1
94
+ break if oct.off_quota
95
+ end
96
+ break if oct.off_quota
97
+ unless seen.values.any? { |v| v < @limit }
98
+ @loog.debug("Finished scanning #{repos.size} repos: #{seen.map { |k, v| "#{k}:#{v}" }.join(', ')}")
99
+ break
100
+ end
101
+ end
102
+ end
103
+ end
data/lib/fbe/octo.rb ADDED
@@ -0,0 +1,260 @@
1
+ # frozen_string_literal: true
2
+
3
+ # MIT License
4
+ #
5
+ # Copyright (c) 2024 Zerocracy
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ require 'loog'
26
+ require 'decoor'
27
+ require 'obk'
28
+ require 'octokit'
29
+ require 'verbose'
30
+ require 'faraday/http_cache'
31
+ require 'faraday/retry'
32
+ require_relative '../fbe'
33
+
34
+ def Fbe.octo(options: $options, global: $global, loog: Loog::NULL)
35
+ raise 'The $global is not set' if global.nil?
36
+ global[:octo] ||= begin
37
+ if options.testing.nil?
38
+ o = Octokit::Client.new
39
+ token = options.token
40
+ loog.debug("The 'token' option is not provided") if token.nil?
41
+ token = ENV.fetch('GITHUB_TOKEN', nil) if token.nil?
42
+ loog.debug("The 'GITHUB_TOKEN' environment variable is not set") if token.nil?
43
+ if token.nil?
44
+ loog.warn('Accessing GitHub API without a token!')
45
+ else
46
+ o = Octokit::Client.new(access_token: token)
47
+ loog.info("Accessing GitHub API with a token (#{token.length} chars)")
48
+ end
49
+ o.auto_paginate = true
50
+ o.connection_options = {
51
+ request: {
52
+ open_timeout: 15,
53
+ timeout: 15
54
+ }
55
+ }
56
+ stack = Faraday::RackBuilder.new do |builder|
57
+ builder.use(Faraday::Retry::Middleware)
58
+ builder.use(Faraday::HttpCache, serializer: Marshal, shared_cache: false)
59
+ builder.use(Octokit::Response::RaiseError)
60
+ builder.adapter(Faraday.default_adapter)
61
+ end
62
+ o.middleware = stack
63
+ o = Verbose.new(o, log: loog)
64
+ else
65
+ loog.debug('The connection to GitHub API is mocked')
66
+ o = Fbe::FakeOctokit.new
67
+ end
68
+ decoor(o, loog:) do
69
+ def off_quota
70
+ left = @origin.rate_limit.remaining
71
+ if left < 5
72
+ @loog.info("To much GitHub API quota consumed already (remaining=#{left}), stopping")
73
+ true
74
+ else
75
+ false
76
+ end
77
+ end
78
+
79
+ def user_name_by_id(id)
80
+ json = @origin.user(id)
81
+ name = json[:login]
82
+ @loog.debug("GitHub user ##{id} has a name: @#{name}")
83
+ name
84
+ end
85
+
86
+ def repo_id_by_name(name)
87
+ json = @origin.repository(name)
88
+ id = json[:id]
89
+ @loog.debug("GitHub repository #{name} has an ID: ##{id}")
90
+ id
91
+ end
92
+
93
+ def repo_name_by_id(id)
94
+ json = @origin.repository(id)
95
+ name = json[:full_name]
96
+ @loog.debug("GitHub repository ##{id} has a name: #{name}")
97
+ name
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ # Fake GitHub client, for tests.
104
+ class Fbe::FakeOctokit
105
+ def random_time
106
+ Time.now - rand(10_000)
107
+ end
108
+
109
+ def name_to_number(name)
110
+ return name unless name.is_a?(String)
111
+ name.chars.map(&:ord).inject(0, :+)
112
+ end
113
+
114
+ def rate_limit
115
+ o = Object.new
116
+ def o.remaining
117
+ 100
118
+ end
119
+ o
120
+ end
121
+
122
+ def repositories(_user = nil)
123
+ [
124
+ {
125
+ name: 'judges',
126
+ full_name: 'yegor256/judges',
127
+ id: 444
128
+ }
129
+ ]
130
+ end
131
+
132
+ def user(name)
133
+ {
134
+ id: 444,
135
+ login: 'yegor256',
136
+ type: name == 29_139_614 ? 'Bot' : 'User'
137
+ }
138
+ end
139
+
140
+ def repository(name)
141
+ {
142
+ id: name_to_number(name),
143
+ full_name: name.is_a?(Integer) ? 'yegor256/test' : name
144
+ }
145
+ end
146
+
147
+ def add_comment(_repo, _issue, _text)
148
+ 42
149
+ end
150
+
151
+ def search_issues(_query, _options = {})
152
+ {
153
+ items: [
154
+ {
155
+ number: 42,
156
+ labels: [
157
+ {
158
+ name: 'bug'
159
+ }
160
+ ]
161
+ }
162
+ ]
163
+ }
164
+ end
165
+
166
+ def issue_timeline(_repo, _issue, _options = {})
167
+ [
168
+ {
169
+ actor: {
170
+ id: 888,
171
+ login: 'torvalds'
172
+ },
173
+ repository: {
174
+ id: name_to_number('yegor256/judges'),
175
+ full_name: 'yegor256/judges'
176
+ },
177
+ event: 'renamed',
178
+ rename: {
179
+ from: 'before',
180
+ to: 'after'
181
+ },
182
+ created_at: random_time
183
+ },
184
+ {
185
+ actor: {
186
+ id: 888,
187
+ login: 'torvalds'
188
+ },
189
+ repository: {
190
+ id: name_to_number('yegor256/judges'),
191
+ full_name: 'yegor256/judges'
192
+ },
193
+ event: 'labeled',
194
+ label: {
195
+ name: 'bug'
196
+ },
197
+ created_at: random_time
198
+ }
199
+ ]
200
+ end
201
+
202
+ def repository_events(repo, _options = {})
203
+ [
204
+ {
205
+ id: '123',
206
+ repo: {
207
+ id: name_to_number(repo),
208
+ name: repo
209
+ },
210
+ type: 'PushEvent',
211
+ payload: {
212
+ push_id: 42
213
+ },
214
+ actor: {
215
+ id: 888,
216
+ login: 'torvalds'
217
+ },
218
+ created_at: random_time
219
+ },
220
+ {
221
+ id: '124',
222
+ repo: {
223
+ id: name_to_number(repo),
224
+ name: repo
225
+ },
226
+ type: 'IssuesEvent',
227
+ payload: {
228
+ action: 'closed',
229
+ issue: {
230
+ number: 42
231
+ }
232
+ },
233
+ actor: {
234
+ id: 888,
235
+ login: 'torvalds'
236
+ },
237
+ created_at: random_time
238
+ },
239
+ {
240
+ id: '125',
241
+ repo: {
242
+ id: name_to_number(repo),
243
+ name: repo
244
+ },
245
+ type: 'IssuesEvent',
246
+ payload: {
247
+ action: 'opened',
248
+ issue: {
249
+ number: 42
250
+ }
251
+ },
252
+ actor: {
253
+ id: 888,
254
+ login: 'torvalds'
255
+ },
256
+ created_at: random_time
257
+ }
258
+ ]
259
+ end
260
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # MIT License
4
+ #
5
+ # Copyright (c) 2024 Zerocracy
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ require_relative 'octo'
26
+
27
+ # Unmask.
28
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
+ # Copyright:: Copyright (c) 2024 Zerocracy
30
+ # License:: MIT
31
+ module Fbe
32
+ def self.mask_to_regex(mask)
33
+ org, repo = mask.split('/')
34
+ raise "Org '#{org}' can't have an asterisk" if org.include?('*')
35
+ Regexp.compile("#{org}/#{repo.gsub('*', '.*')}")
36
+ end
37
+
38
+ def self.unmask_repos(options: $options, global: $global, loog: $loog)
39
+ repos = []
40
+ masks = (options.repositories || '').split(',')
41
+ masks.reject { |m| m.start_with?('-') }.each do |mask|
42
+ unless mask.include?('*')
43
+ repos << mask
44
+ next
45
+ end
46
+ re = Fbe.mask_to_regex(mask)
47
+ Fbe.octo(loog:, global:, options:).repositories(mask.split('/')[0]).each do |r|
48
+ repos << r[:full_name] if re.match?(r[:full_name])
49
+ end
50
+ end
51
+ masks.select { |m| m.start_with?('-') }.each do |mask|
52
+ re = Fbe.mask_to_regex(mask[1..])
53
+ repos.reject! { |r| re.match?(r) }
54
+ end
55
+ loog.debug("Scanning #{repos.size} repositories: #{repos.join(', ')}...")
56
+ repos
57
+ end
58
+ end
data/lib/fbe.rb ADDED
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2024 Zerocracy
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ # The module.
24
+ #
25
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
26
+ # Copyright:: Copyright (c) 2024 Zerocracy
27
+ # License:: MIT
28
+ module Fbe
29
+ # Current version of the gem (changed by .rultor.yml on every release)
30
+ VERSION = '0.0.1'
31
+ end
data/renovate.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": [
4
+ "config:base"
5
+ ]
6
+ }
data/rules/basic.fe ADDED
@@ -0,0 +1,158 @@
1
+ # MIT License
2
+ #
3
+ # Copyright (c) 2024 Zerocracy
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ (undef explain)
24
+ (defn explain '
25
+ r = @operands[0].evaluate(fact, maps);
26
+ if !r && !$loog.nil?
27
+ $loog.error(\'This rule failed: \' + self.to_s)
28
+ end
29
+ return r
30
+ ')
31
+
32
+ (explain (when
33
+ (exists what)
34
+ (or
35
+ (eq what 'events-were-scanned')
36
+ (eq what 'labels-were-scanned')
37
+ (eq what 'bug-was-accepted')
38
+ (eq what 'bug-was-resolved')
39
+ (eq what 'comment-was-posted')
40
+ (eq what 'git-was-pushed')
41
+ (eq what 'events-were-scanned')
42
+ (eq what 'issue-was-closed')
43
+ (eq what 'issue-was-opened')
44
+ (eq what 'issue-was-assigned')
45
+ (eq what 'label-was-attached')
46
+ (eq what 'release-published')
47
+ (eq what 'reward-for-bug-reported')
48
+ (eq what 'reward-for-resolved-bug')
49
+ (eq what 'tag-was-created'))))
50
+
51
+ (explain (when
52
+ (exists what)
53
+ (matches what "^[a-z]+(-[a-z]+)*$")))
54
+
55
+ (explain (when
56
+ (exists details)
57
+ (and
58
+ (not (matches details " "))
59
+ (not (matches details "^.{,120}$"))
60
+ (not (matches details "[^.]$")))))
61
+
62
+ (explain (when
63
+ (exists _id)
64
+ (eq "Integer" (type _id))))
65
+ (explain (when
66
+ (exists _time)
67
+ (eq "Time" (type _time))))
68
+ (explain (when
69
+ (exists _version)
70
+ (eq "String" (type _version))))
71
+ (explain (when
72
+ (exists issue)
73
+ (and
74
+ (eq "Integer" (type issue))
75
+ (gt issue 0))))
76
+ (explain (when
77
+ (exists repository)
78
+ (eq "Integer" (type repository))))
79
+ (explain (when
80
+ (exists who)
81
+ (eq "Integer" (type who))))
82
+ (explain (when
83
+ (exists award)
84
+ (eq "Integer" (type award))))
85
+
86
+ (explain (when
87
+ (exists when)
88
+ (eq "Time" (type when))))
89
+
90
+ (explain (when
91
+ (exists issue)
92
+ (exists repository)))
93
+
94
+ (explain (when
95
+ (exists award)
96
+ (and
97
+ (exists when)
98
+ (exists who)
99
+ (exists reason))))
100
+
101
+ (explain (when
102
+ (eq what 'events-were-scanned')
103
+ (and
104
+ (exists repository)
105
+ (exists latest)
106
+ (eq "Integer" (type latest)))))
107
+
108
+ (explain (when
109
+ (eq what 'label-was-attached')
110
+ (and
111
+ (exists issue)
112
+ (exists label)
113
+ (eq "String" (type label)))))
114
+
115
+ (explain (when
116
+ (eq what 'issue-was-opened')
117
+ (and
118
+ (exists issue)
119
+ (exists when)
120
+ (exists who))))
121
+
122
+ (explain (when
123
+ (eq what 'issue-was-closed')
124
+ (and
125
+ (exists issue)
126
+ (exists when)
127
+ (exists who))))
128
+
129
+ (explain (when
130
+ (eq what 'bug-was-resolved')
131
+ (and
132
+ (exists cause)
133
+ (exists when)
134
+ (exists issue)
135
+ (exists details)
136
+ (exists who))))
137
+
138
+ (explain (when
139
+ (eq what 'bug-was-accepted')
140
+ (and
141
+ (exists cause)
142
+ (exists when)
143
+ (exists issue)
144
+ (exists details)
145
+ (exists reporter)
146
+ (eq "Integer" (type reporter))
147
+ (exists who))))
148
+
149
+ (explain (when
150
+ (eq what 'bug-report-was-rewarded')
151
+ (and
152
+ (exists cause)
153
+ (exists award)
154
+ (eq "Integer" (type award))
155
+ (exists when)
156
+ (exists issue)
157
+ (exists repository))))
158
+
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ # MIT License
4
+ #
5
+ # Copyright (c) 2024 Zerocracy
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in all
15
+ # copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ # SOFTWARE.
24
+
25
+ require 'minitest/autorun'
26
+ require 'loog'
27
+ require 'factbase'
28
+ require 'factbase/syntax'
29
+ require 'judges/options'
30
+ require_relative '../../lib/fbe/conclude'
31
+ require_relative '../../lib/fbe/fb'
32
+
33
+ # Test.
34
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
35
+ # Copyright:: Copyright (c) 2024 Zerocracy
36
+ # License:: MIT
37
+ class TestConclude < Minitest::Test
38
+ def test_draw
39
+ fb = Factbase.new
40
+ fb.insert.foo = 1
41
+ fb.insert.bar = 2
42
+ Fbe.conclude(fb, 'judge-one', Loog::NULL) do
43
+ on '(exists foo)'
44
+ draw do |n, prev|
45
+ n.sum = prev.foo + 1
46
+ 'something funny'
47
+ end
48
+ end
49
+ f = fb.query('(exists sum)').each.to_a[0]
50
+ assert_equal(2, f.sum)
51
+ assert_equal('judge-one', f.what)
52
+ assert_equal('something funny', f.details)
53
+ end
54
+
55
+ def test_maybe
56
+ $fb = Factbase.new
57
+ $options = Judges::Options.new
58
+ $loog = Loog::NULL
59
+ Fbe.fb.insert.foo = 1
60
+ Fbe.conclude(Fbe.fb, 'issue-was-opened', Loog::NULL) do
61
+ on '(exists foo)'
62
+ maybe do |n, prev|
63
+ n.repository = 111
64
+ n.issue = prev.foo
65
+ n.who = 777
66
+ n.when = Time.now
67
+ "it's a test." * 20
68
+ end
69
+ end
70
+ f = Fbe.fb.query('(exists issue)').each.to_a[0]
71
+ assert_equal(1, f.issue)
72
+ assert(f._id.positive?)
73
+ end
74
+
75
+ def test_consider
76
+ $fb = Factbase.new
77
+ $options = Judges::Options.new
78
+ $loog = Loog::NULL
79
+ Fbe.fb.insert.foo = 1
80
+ Fbe.conclude(Fbe.fb, 'issue-was-closed', Loog::NULL) do
81
+ on '(exists foo)'
82
+ consider do |_prev|
83
+ Fbe.fb.insert.bar = 42
84
+ end
85
+ end
86
+ f = Fbe.fb.query('(exists bar)').each.to_a[0]
87
+ assert_equal(42, f.bar)
88
+ end
89
+ end