fbe 0.16.1 → 0.18.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 011c5a07ab2d1b15194cd2950da1cd466698d37a9aa0bbd07225ce7bca335881
4
- data.tar.gz: 1fa420cebbdc70897a4779601a5cc8e4596a9542a223e64e020086ff0ec10826
3
+ metadata.gz: 4a99af1e0cf0824c00460e0166b3b9882c40b49421989e94c5abcda5d1766042
4
+ data.tar.gz: e7963ae2eb4bdb52745a10dc5f4d240abf768549f1461098c93e7dc81986936a
5
5
  SHA512:
6
- metadata.gz: 1790fa88d1d97b8509d61c85592c36ca5147e97e982015991fc15128315a210190505310cf1d53b618507b354e1b77b065bbc1cbfff4b8ffc771f50bea5778fa
7
- data.tar.gz: 4bf95961acba3192c824e48054c8a36d7aa72184645305c8fcc6ef9e5926cd08c7f661353bc6244b8e789b1fb5ea2e4dcf8a089969267bc55b80fdf9b641b775
6
+ metadata.gz: 0f90f11a2f21822ab37f5b9300ee1dd35858f9ded52baed36404af1bc27d1ebf9880e720a08b0caff73e932fefad80716bddcdafb87f0e8b7c4c5b2f84014e6c
7
+ data.tar.gz: 01612e41f4b1d8432b55dff2a4ce3b77af9686a9f9b6b1e3c9ff099f10ec447ee1b7594bf9808297d3a799656f92909a2112f7234d6a603199bd5c2c154fe6a5
data/.gitignore CHANGED
@@ -8,3 +8,4 @@ doc/
8
8
  node_modules/
9
9
  rdoc/
10
10
  vendor/
11
+ .claude/
data/.rubocop.yml CHANGED
@@ -14,6 +14,8 @@ plugins:
14
14
  - rubocop-minitest
15
15
  - rubocop-performance
16
16
  - rubocop-rake
17
+ Minitest/MultipleAssertions:
18
+ Max: 10
17
19
  Minitest/EmptyLineBeforeAssertionMethods:
18
20
  Enabled: false
19
21
  Style/GlobalVars:
@@ -54,4 +56,3 @@ Metrics/ParameterLists:
54
56
  Enabled: false
55
57
  Layout/MultilineAssignmentLayout:
56
58
  Enabled: true
57
- require: []
data/Gemfile.lock CHANGED
@@ -17,6 +17,7 @@ PATH
17
17
  obk (> 0)
18
18
  octokit (~> 10.0)
19
19
  others (> 0)
20
+ sqlite3 (~> 2.6)
20
21
  tago (> 0)
21
22
  verbose (> 0)
22
23
 
@@ -217,6 +218,10 @@ GEM
217
218
  simplecov (~> 0.19)
218
219
  simplecov-html (0.13.1)
219
220
  simplecov_json_formatter (0.1.4)
221
+ sqlite3 (2.6.0-arm64-darwin)
222
+ sqlite3 (2.6.0-x64-mingw-ucrt)
223
+ sqlite3 (2.6.0-x86_64-darwin)
224
+ sqlite3 (2.6.0-x86_64-linux-gnu)
220
225
  strscan (3.1.5)
221
226
  tago (0.1.0)
222
227
  timeout (0.4.3)
data/Rakefile CHANGED
@@ -16,7 +16,7 @@ def version
16
16
  Gem::Specification.load(Dir['*.gemspec'].first).version
17
17
  end
18
18
 
19
- task default: %i[clean test picks rubocop yard]
19
+ task default: %i[clean test rubocop picks yard]
20
20
 
21
21
  require 'rake/testtask'
22
22
  desc 'Run all unit tests'
data/fbe.gemspec CHANGED
@@ -37,6 +37,7 @@ Gem::Specification.new do |s|
37
37
  s.add_dependency 'obk', '>0'
38
38
  s.add_dependency 'octokit', '~>10.0'
39
39
  s.add_dependency 'others', '>0'
40
+ s.add_dependency 'sqlite3', '~> 2.6'
40
41
  s.add_dependency 'tago', '>0'
41
42
  s.add_dependency 'verbose', '>0'
42
43
  s.metadata['rubygems_mfa_required'] = 'true'
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require 'json'
7
+ require 'sqlite3'
8
+ require_relative '../../fbe'
9
+ require_relative '../../fbe/middleware'
10
+
11
+ # Persisted SQLite store for Faraday::HttpCache
12
+ #
13
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
14
+ # Copyright:: Copyright (c) 2024-2025 Zerocracy
15
+ # License:: MIT
16
+ class Fbe::Middleware::SqliteStore
17
+ def initialize(path)
18
+ raise ArgumentError, 'Database path cannot be nil or empty' if path.nil? || path.empty?
19
+ dir = File.dirname(path)
20
+ raise ArgumentError, "Directory #{dir} does not exist" unless File.directory?(dir)
21
+ @path = path
22
+ open
23
+ prepare
24
+ at_exit { close }
25
+ end
26
+
27
+ def read(key)
28
+ value = perform { _1.execute('SELECT value FROM cache WHERE key = ? LIMIT 1', [key]) }.dig(0, 0)
29
+ JSON.parse(value) if value
30
+ end
31
+
32
+ def delete(key)
33
+ perform { _1.execute('DELETE FROM cache WHERE key = ?', [key]) }
34
+ nil
35
+ end
36
+
37
+ def write(key, value)
38
+ value = JSON.dump(value)
39
+ perform do |tdb|
40
+ tdb.execute(<<~SQL, [key, value])
41
+ INSERT INTO cache(key, value) VALUES(?1, ?2)
42
+ ON CONFLICT(key) DO UPDATE SET value = ?2
43
+ SQL
44
+ end
45
+ nil
46
+ end
47
+
48
+ def open
49
+ return if @db
50
+ @db = SQLite3::Database.new(@path)
51
+ end
52
+
53
+ def prepare
54
+ perform do |tdb|
55
+ tdb.execute 'CREATE TABLE IF NOT EXISTS cache(key TEXT UNIQUE NOT NULL, value TEXT);'
56
+ tdb.execute 'CREATE INDEX IF NOT EXISTS key_idx ON cache(key);'
57
+ end
58
+ end
59
+
60
+ def close
61
+ return if !@db || @db.closed?
62
+ @db.close
63
+ @db = nil
64
+ end
65
+
66
+ def clear
67
+ perform { _1.execute 'DELETE FROM cache;' }
68
+ end
69
+
70
+ def drop
71
+ perform { _1.execute 'DROP TABLE IF EXISTS cache;' }
72
+ end
73
+
74
+ def all
75
+ perform { _1.execute('SELECT key, value FROM cache') }
76
+ end
77
+
78
+ private
79
+
80
+ def perform(&)
81
+ @db.transaction(&)
82
+ end
83
+ end
@@ -0,0 +1,58 @@
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 '../../fbe'
8
+ require_relative '../../fbe/middleware'
9
+
10
+ # Faraday middleware that traces all API calls.
11
+ #
12
+ # This middleware records all HTTP requests and responses in a trace array,
13
+ # capturing method, URL, status, and timing information for debugging and
14
+ # monitoring purposes.
15
+ #
16
+ # @example Usage in Faraday middleware stack
17
+ # trace = []
18
+ # connection = Faraday.new do |f|
19
+ # f.use Fbe::Middleware::Trace, trace
20
+ # end
21
+ # connection.get('/api/endpoint')
22
+ # trace.first[:method] #=> :get
23
+ # trace.first[:url] #=> 'https://example.com/api/endpoint'
24
+ # trace.first[:status] #=> 200
25
+ #
26
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
27
+ # Copyright:: Copyright (c) 2024-2025 Zerocracy
28
+ # License:: MIT
29
+ class Fbe::Middleware::Trace < Faraday::Middleware
30
+ # Initializes the trace middleware.
31
+ #
32
+ # @param [Object] app The next middleware in the stack
33
+ # @param [Array] trace The array to store trace entries
34
+ def initialize(app, trace)
35
+ super(app)
36
+ @trace = trace
37
+ end
38
+
39
+ # Processes the HTTP request and records trace information.
40
+ #
41
+ # @param [Faraday::Env] env The request environment
42
+ # @return [Faraday::Response] The response from the next middleware
43
+ def call(env)
44
+ started = Time.now
45
+ entry = {
46
+ method: env.method,
47
+ url: env.url.to_s,
48
+ started_at: started
49
+ }
50
+ @app.call(env).on_complete do |response_env|
51
+ finished = Time.now
52
+ entry[:status] = response_env.status
53
+ entry[:finished_at] = finished
54
+ entry[:duration] = finished - started
55
+ @trace << entry
56
+ end
57
+ end
58
+ end
data/lib/fbe/octo.rb CHANGED
@@ -3,16 +3,20 @@
3
3
  # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
+ require 'json'
6
7
  require 'decoor'
7
8
  require 'faraday/http_cache'
8
9
  require 'faraday/retry'
9
10
  require 'loog'
10
11
  require 'obk'
11
12
  require 'octokit'
13
+ require 'uri'
12
14
  require 'verbose'
13
15
  require_relative '../fbe'
14
16
  require_relative 'middleware'
15
17
  require_relative 'middleware/formatter'
18
+ require_relative 'middleware/trace'
19
+ require_relative 'middleware/sqlite_store'
16
20
 
17
21
  # Makes a call to the GitHub API.
18
22
  #
@@ -30,6 +34,7 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
30
34
  raise 'The $loog is not set' if loog.nil?
31
35
  global[:octo] ||=
32
36
  begin
37
+ trace = []
33
38
  if options.testing.nil?
34
39
  o = Octokit::Client.new
35
40
  token = options.github_token
@@ -50,8 +55,10 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
50
55
  loog.warn('The GitHub API token is an empty string, won\'t use it')
51
56
  else
52
57
  o = Octokit::Client.new(access_token: token)
53
- loog.info("Accessing GitHub API with a token (#{token.length} chars, ending by #{token[-4..].inspect}, " \
54
- "#{Octokit::Client.new(access_token: token).rate_limit.remaining} quota remaining)")
58
+ loog.info(
59
+ "Accessing GitHub API with a token (#{token.length} chars, ending by #{token[-4..].inspect}, " \
60
+ "#{Octokit::Client.new(access_token: token).rate_limit.remaining} quota remaining)"
61
+ )
55
62
  end
56
63
  o.auto_paginate = true
57
64
  o.per_page = 100
@@ -73,9 +80,18 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
73
80
  methods: [:get],
74
81
  backoff_factor: 2
75
82
  )
76
- builder.use(Faraday::HttpCache, serializer: Marshal, shared_cache: false, logger: Loog::NULL)
83
+ serializer = Marshal
84
+ if options.sqlite_cache
85
+ store = Fbe::Middleware::SqliteStore.new(options.sqlite_cache)
86
+ serializer = JSON
87
+ end
88
+ builder.use(
89
+ Faraday::HttpCache,
90
+ store: store, serializer: serializer, shared_cache: false, logger: Loog::NULL
91
+ )
77
92
  builder.use(Octokit::Response::RaiseError)
78
93
  builder.use(Faraday::Response::Logger, loog, formatter: Fbe::Middleware::Formatter)
94
+ builder.use(Fbe::Middleware::Trace, trace)
79
95
  builder.adapter(Faraday.default_adapter)
80
96
  end
81
97
  o.middleware = stack
@@ -84,7 +100,25 @@ def Fbe.octo(options: $options, global: $global, loog: $loog)
84
100
  loog.debug('The connection to GitHub API is mocked')
85
101
  o = Fbe::FakeOctokit.new
86
102
  end
87
- decoor(o, loog:) do
103
+ decoor(o, loog:, trace:) do
104
+ def print_trace!
105
+ if @trace.empty?
106
+ @loog.debug('GitHub API trace is empty')
107
+ else
108
+ grouped =
109
+ @trace.group_by do |entry|
110
+ uri = URI.parse(entry[:url])
111
+ "#{uri.scheme}://#{uri.host}#{uri.path}"
112
+ end
113
+ message = grouped
114
+ .sort_by { |_path, entries| -entries.count }
115
+ .map { |path, entries| " #{path}: #{entries.count}" }
116
+ .join("\n")
117
+ @loog.info("GitHub API trace (#{grouped.count} URLs vs #{@trace.count} requests):\n#{message}")
118
+ @trace.clear
119
+ end
120
+ end
121
+
88
122
  def off_quota(threshold: 50)
89
123
  left = @origin.rate_limit.remaining
90
124
  if left < threshold
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.16.1' unless const_defined?(:VERSION)
13
+ VERSION = '0.18.0' unless const_defined?(:VERSION)
14
14
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Zerocracy
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative '../../test__helper'
7
+ require_relative '../../../lib/fbe/middleware'
8
+ require_relative '../../../lib/fbe/middleware/sqlite_store'
9
+
10
+ # Test.
11
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
12
+ # Copyright:: Copyright (c) 2024-2025 Zerocracy
13
+ # License:: MIT
14
+ class SqliteStoreTest < Fbe::Test
15
+ def test_sqlite_store
16
+ Dir.mktmpdir do |dir|
17
+ store = Fbe::Middleware::SqliteStore.new(File.expand_path('test.db', dir))
18
+ assert_nil(store.read('my_key'))
19
+ assert_nil(store.delete('my_key'))
20
+ assert_nil(store.write('my_key', 'some value'))
21
+ assert_equal('some value', store.read('my_key'))
22
+ assert_nil(store.write('my_key', 'some value 2'))
23
+ assert_equal('some value 2', store.read('my_key'))
24
+ assert_nil(store.delete('my_key'))
25
+ assert_nil(store.read('my_key'))
26
+ end
27
+ end
28
+
29
+ def test_sqlite_store_empty_all
30
+ Dir.mktmpdir do |dir|
31
+ store = Fbe::Middleware::SqliteStore.new(File.expand_path('test.db', dir))
32
+ assert_empty(store.all)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,106 @@
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 '../../test__helper'
9
+ require_relative '../../../lib/fbe'
10
+ require_relative '../../../lib/fbe/middleware'
11
+ require_relative '../../../lib/fbe/middleware/trace'
12
+
13
+ # Test.
14
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
15
+ # Copyright:: Copyright (c) 2024-2025 Zerocracy
16
+ # License:: MIT
17
+ class TraceTest < Fbe::Test
18
+ def test_traces_successful_request
19
+ trace = []
20
+ stub_request(:get, 'http://example.com/test')
21
+ .to_return(status: 200, body: 'success')
22
+ conn =
23
+ Faraday.new do |f|
24
+ f.use Fbe::Middleware::Trace, trace
25
+ f.adapter :net_http
26
+ end
27
+ conn.get('http://example.com/test')
28
+ assert_equal 1, trace.size
29
+ entry = trace.first
30
+ assert_equal :get, entry[:method]
31
+ assert_equal 'http://example.com/test', entry[:url]
32
+ assert_equal 200, entry[:status]
33
+ assert_instance_of Time, entry[:started_at]
34
+ assert_instance_of Time, entry[:finished_at]
35
+ assert_instance_of Float, entry[:duration]
36
+ assert_operator entry[:duration], :>=, 0
37
+ assert_operator entry[:finished_at], :>=, entry[:started_at]
38
+ end
39
+
40
+ def test_traces_multiple_requests
41
+ trace = []
42
+ stub_request(:get, 'http://example.com/endpoint1').to_return(status: 200)
43
+ stub_request(:post, 'http://example.com/endpoint2').to_return(status: 201)
44
+ stub_request(:delete, 'http://example.com/endpoint3').to_return(status: 404)
45
+ conn =
46
+ Faraday.new do |f|
47
+ f.use Fbe::Middleware::Trace, trace
48
+ f.adapter :net_http
49
+ end
50
+ conn.get('http://example.com/endpoint1')
51
+ conn.post('http://example.com/endpoint2')
52
+ conn.delete('http://example.com/endpoint3')
53
+ assert_equal 3, trace.size
54
+ assert_equal :get, trace[0][:method]
55
+ assert_equal 200, trace[0][:status]
56
+ assert_equal :post, trace[1][:method]
57
+ assert_equal 201, trace[1][:status]
58
+ assert_equal :delete, trace[2][:method]
59
+ assert_equal 404, trace[2][:status]
60
+ end
61
+
62
+ def test_traces_error_responses
63
+ trace = []
64
+ stub_request(:get, 'http://example.com/error').to_return(status: 500, body: 'error')
65
+ conn =
66
+ Faraday.new do |f|
67
+ f.use Fbe::Middleware::Trace, trace
68
+ f.adapter :net_http
69
+ end
70
+ conn.get('http://example.com/error')
71
+ assert_equal 1, trace.size
72
+ entry = trace.first
73
+ assert_equal 500, entry[:status]
74
+ assert_equal 'http://example.com/error', entry[:url]
75
+ end
76
+
77
+ def test_handles_connection_errors
78
+ trace = []
79
+ stub_request(:get, 'http://example.com/timeout').to_timeout
80
+ conn =
81
+ Faraday.new do |f|
82
+ f.use Fbe::Middleware::Trace, trace
83
+ f.adapter :net_http
84
+ end
85
+ assert_raises(Faraday::ConnectionFailed) do
86
+ conn.get('http://example.com/timeout')
87
+ end
88
+ assert_equal 0, trace.size
89
+ end
90
+
91
+ def test_preserves_request_with_query_params
92
+ trace = []
93
+ stub_request(:get, 'http://example.com/search').with(query: { 'q' => 'test', 'page' => '2' }).to_return(status: 200)
94
+ conn =
95
+ Faraday.new do |f|
96
+ f.use Fbe::Middleware::Trace, trace
97
+ f.adapter :net_http
98
+ end
99
+ conn.get('http://example.com/search?q=test&page=2')
100
+ assert_equal 1, trace.size
101
+ url = trace.first[:url]
102
+ assert url.start_with?('http://example.com/search?')
103
+ assert_includes url, 'q=test'
104
+ assert_includes url, 'page=2'
105
+ end
106
+ end
data/test/fbe/test_fb.rb CHANGED
@@ -27,6 +27,28 @@ class TestFb < Fbe::Test
27
27
  assert_includes(stdout, 'Inserted new fact #1', stdout)
28
28
  end
29
29
 
30
+ def test_defends_against_improper_facts
31
+ $fb = Factbase.new
32
+ $global = {}
33
+ $options = Judges::Options.new
34
+ $loog = Loog::Buffer.new
35
+ assert_raises(StandardError, 'issue without repository') do
36
+ Fbe.fb.txn do |fbt|
37
+ f = fbt.insert
38
+ f.what = 'issue-was-opened'
39
+ f.issue = 42
40
+ f.where = 'github'
41
+ end
42
+ end
43
+ assert_raises(StandardError, 'repository without where') do
44
+ Fbe.fb.txn do |fbt|
45
+ f = fbt.insert
46
+ f.what = 'issue-was-opened'
47
+ f.repository = 44
48
+ end
49
+ end
50
+ end
51
+
30
52
  def test_increment_id_in_transaction
31
53
  $fb = Factbase.new
32
54
  $global = {}
@@ -322,4 +322,72 @@ class TestOcto < Fbe::Test
322
322
  }
323
323
  end
324
324
  end
325
+
326
+ def test_print_trace
327
+ loog = Loog::Buffer.new
328
+ WebMock.disable_net_connect!
329
+ stub_request(:get, 'https://api.github.com/user/123').to_return(
330
+ status: 200,
331
+ body: '{"id":123,"login":"test"}'
332
+ )
333
+ stub_request(:get, 'https://api.github.com/repos/foo/bar').to_return(
334
+ status: 200,
335
+ body: '{"id":456,"full_name":"foo/bar"}'
336
+ )
337
+ octo = Fbe.octo(loog:, global: {}, options: Judges::Options.new)
338
+ octo.user(123)
339
+ octo.repository('foo/bar')
340
+ octo.repository('foo/bar')
341
+ octo.print_trace!
342
+ output = loog.to_s
343
+ assert_includes output, 'GitHub API trace (2 URLs vs 3 requests)'
344
+ assert_includes output, 'https://api.github.com/user/123: 1'
345
+ assert_includes output, 'https://api.github.com/repos/foo/bar: 2'
346
+ repo_index = output.index('https://api.github.com/repos/foo/bar: 2')
347
+ user_index = output.index('https://api.github.com/user/123: 1')
348
+ assert_operator repo_index, :<, user_index, 'URLs should be sorted by request count (highest first)'
349
+ end
350
+
351
+ def test_trace_gets_cleared_after_print
352
+ WebMock.disable_net_connect!
353
+ stub_request(:get, 'https://api.github.com/user/456').to_return(
354
+ status: 200,
355
+ body: '{"id":456,"login":"testuser"}'
356
+ )
357
+ first_loog = Loog::Buffer.new
358
+ octo = Fbe.octo(loog: first_loog, global: {}, options: Judges::Options.new)
359
+ octo.user(456)
360
+ octo.print_trace!
361
+ first_output = first_loog.to_s
362
+ assert_includes first_output, 'GitHub API trace'
363
+ second_loog = Loog::Buffer.new
364
+ octo.instance_variable_set(:@loog, second_loog)
365
+ octo.print_trace!
366
+ second_output = second_loog.to_s
367
+ assert_includes second_output, 'GitHub API trace is empty'
368
+ end
369
+
370
+ def test_sqlite_store
371
+ WebMock.disable_net_connect!
372
+ Dir.mktmpdir do |dir|
373
+ global = {}
374
+ sqlite_cache = File.expand_path('test.db', dir)
375
+ o = Fbe.octo(loog: Loog::NULL, global:, options: Judges::Options.new({ 'sqlite_cache' => sqlite_cache }))
376
+ stub = stub_request(:get, 'https://api.github.com/user/42').to_return(
377
+ status: 200,
378
+ body: { login: 'user1' }.to_json,
379
+ headers: {
380
+ 'Content-Type' => 'application/json',
381
+ 'Cache-Control' => 'public, max-age=60, s-maxage=60',
382
+ 'Etag' => 'W/"2ff9dd4c3153f006830b2b8b721f6a4bb400a1eb81a2e1fa0a3b846ad349b9ec"',
383
+ 'Last-Modified' => 'Wed, 01 May 2025 20:00:00 GMT'
384
+ }
385
+ )
386
+ assert_equal('user1', o.user_name_by_id(42))
387
+ WebMock.remove_request_stub(stub)
388
+ global = {}
389
+ o = Fbe.octo(loog: Loog::NULL, global:, options: Judges::Options.new({ 'sqlite_cache' => sqlite_cache }))
390
+ assert_equal('user1', o.user_name_by_id(42))
391
+ end
392
+ end
325
393
  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.16.1
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -219,6 +219,20 @@ dependencies:
219
219
  - - ">"
220
220
  - !ruby/object:Gem::Version
221
221
  version: '0'
222
+ - !ruby/object:Gem::Dependency
223
+ name: sqlite3
224
+ requirement: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "~>"
227
+ - !ruby/object:Gem::Version
228
+ version: '2.6'
229
+ type: :runtime
230
+ prerelease: false
231
+ version_requirements: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - "~>"
234
+ - !ruby/object:Gem::Version
235
+ version: '2.6'
222
236
  - !ruby/object:Gem::Dependency
223
237
  name: tago
224
238
  requirement: !ruby/object:Gem::Requirement
@@ -307,6 +321,8 @@ files:
307
321
  - lib/fbe/just_one.rb
308
322
  - lib/fbe/middleware.rb
309
323
  - lib/fbe/middleware/formatter.rb
324
+ - lib/fbe/middleware/sqlite_store.rb
325
+ - lib/fbe/middleware/trace.rb
310
326
  - lib/fbe/octo.rb
311
327
  - lib/fbe/overwrite.rb
312
328
  - lib/fbe/pmp.rb
@@ -318,6 +334,8 @@ files:
318
334
  - renovate.json
319
335
  - rules/basic.fe
320
336
  - test/fbe/middleware/test_formatter.rb
337
+ - test/fbe/middleware/test_sqlite_store.rb
338
+ - test/fbe/middleware/test_trace.rb
321
339
  - test/fbe/test_award.rb
322
340
  - test/fbe/test_bylaws.rb
323
341
  - test/fbe/test_conclude.rb