judges 0.11.0 → 0.13.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: 9ef24207b8d6248eb98283c45d490b6d8b74fd8c00a6ef8f81dffa546dd6d270
4
- data.tar.gz: 856eeb0c1f19d4d28055880514aca057cb0ec7b8584898bb44c30e9382e5e139
3
+ metadata.gz: '098f6126af6c35b9ee74dca41bbfb5b8e6b1357aee5dcec215a2819929e859d5'
4
+ data.tar.gz: 139a4b55ea82a090e385c4f54be682dd74d0922c66d77824c8d33cecaa799a84
5
5
  SHA512:
6
- metadata.gz: ca5c1ef2e4cd29c60a1b0c3eba7c9578f5ef7d835c70bfaa994f5a3adbb2b6d98a5dd1b96847a06ec9ab281991b7933db860b651f6f0c7df06aa1dceccc34092
7
- data.tar.gz: f884e4007e22b4be4efb7513eb7101c4913071bfc916b80041109d62fa655ed48424aea3af351ce1976dfad198f6e5cd1495c3e13e2c0fcf574aa6ba225fae2e
6
+ metadata.gz: 0e173739bc5341c55f869375fef959ff9e6ca57c1e0b814a29d4920700f640fc788a948932221c9fbf6f9e7d9d90501e274645f3de213b7f9b3211549652ad1c
7
+ data.tar.gz: 52f4c44351e5f3c9efb873913f26c8a7c2c5c08dbf490434145cc691968eec240ef95bb5007568b623c043f48ab658624a573664598df587282cb1cfb43ef94b
data/Gemfile.lock CHANGED
@@ -3,7 +3,7 @@ PATH
3
3
  specs:
4
4
  judges (0.0.0)
5
5
  backtrace (~> 0.3)
6
- concurrent-ruby (= 1.2.3)
6
+ concurrent-ruby (~> 1.2)
7
7
  factbase (~> 0.0)
8
8
  gli (~> 2.21)
9
9
  iri (~> 0.8)
@@ -51,7 +51,7 @@ GEM
51
51
  base64 (0.2.0)
52
52
  bigdecimal (3.1.8)
53
53
  builder (3.3.0)
54
- concurrent-ruby (1.2.3)
54
+ concurrent-ruby (1.3.3)
55
55
  connection_pool (2.4.1)
56
56
  crack (1.0.0)
57
57
  bigdecimal
@@ -180,7 +180,7 @@ GEM
180
180
  reline (0.5.9)
181
181
  io-console (~> 0.5)
182
182
  retries (0.0.5)
183
- rexml (3.3.0)
183
+ rexml (3.3.1)
184
184
  strscan
185
185
  rspec-core (3.13.0)
186
186
  rspec-support (~> 3.13.0)
data/bin/judges CHANGED
@@ -65,6 +65,8 @@ class App
65
65
  c.flag([:'max-cycles'], default_value: 8, type: Integer)
66
66
  c.desc 'Stay quiet even if some judges fail'
67
67
  c.switch([:q, :quiet], default_value: false)
68
+ c.desc 'Place a summarization fact into the factbase'
69
+ c.switch([:summary], default_value: false)
68
70
  c.desc 'Use default logging facility'
69
71
  c.switch([:log], default_value: true)
70
72
  c.action do |global, options, args|
@@ -167,6 +169,8 @@ class App
167
169
  c.flag([:timeout], default_value: 30, type: Integer)
168
170
  c.desc 'Shall SSL be used?'
169
171
  c.switch([:ssl], default_value: true)
172
+ c.desc 'A unique name to use for a lock/unlock'
173
+ c.flag([:owner], default_value: 'default', type: String)
170
174
  c.action do |global, options, args|
171
175
  require_relative '../lib/judges/commands/push'
172
176
  Judges::Push.new(loog).run(options, args)
@@ -187,6 +191,8 @@ class App
187
191
  c.flag([:timeout], default_value: 30, type: Integer)
188
192
  c.desc 'Shall SSL be used?'
189
193
  c.switch([:ssl], default_value: true)
194
+ c.desc 'A unique name to use for a lock/unlock'
195
+ c.flag([:owner], default_value: 'default', type: String)
190
196
  c.action do |global, options, args|
191
197
  require_relative '../lib/judges/commands/pull'
192
198
  Judges::Pull.new(loog).run(options, args)
data/judges.gemspec CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
27
27
  s.required_ruby_version = '>=3.2'
28
28
  s.name = 'judges'
29
- s.version = '0.11.0'
29
+ s.version = '0.13.0'
30
30
  s.license = 'MIT'
31
31
  s.summary = 'Command-Line Tool for a Factbase'
32
32
  s.description =
@@ -43,7 +43,7 @@ Gem::Specification.new do |s|
43
43
  s.rdoc_options = ['--charset=UTF-8']
44
44
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
45
45
  s.add_runtime_dependency 'backtrace', '~>0.3'
46
- s.add_runtime_dependency 'concurrent-ruby', '1.2.3'
46
+ s.add_runtime_dependency 'concurrent-ruby', '~>1.2'
47
47
  s.add_runtime_dependency 'factbase', '~>0.0'
48
48
  s.add_runtime_dependency 'gli', '~>2.21'
49
49
  s.add_runtime_dependency 'iri', '~>0.8'
data/lib/judges/baza.rb CHANGED
@@ -110,6 +110,36 @@ class Judges::Baza
110
110
  finished
111
111
  end
112
112
 
113
+ # Lock the name.
114
+ def lock(name, owner)
115
+ elapsed(@loog) do
116
+ with_retries do
117
+ checked(
118
+ Typhoeus::Request.get(
119
+ home.append('lock').append(name).add(owner:).to_s,
120
+ headers:
121
+ ),
122
+ 302
123
+ )
124
+ end
125
+ end
126
+ end
127
+
128
+ # Unlock the name.
129
+ def unlock(name, owner)
130
+ elapsed(@loog) do
131
+ with_retries do
132
+ checked(
133
+ Typhoeus::Request.get(
134
+ home.append('unlock').append(name).add(owner:).to_s,
135
+ headers:
136
+ ),
137
+ 302
138
+ )
139
+ end
140
+ end
141
+ end
142
+
113
143
  def recent(name)
114
144
  job = 0
115
145
  elapsed(@loog) do
data/lib/judges/churn.rb CHANGED
@@ -27,34 +27,40 @@ require_relative '../judges'
27
27
  # Copyright:: Copyright (c) 2024 Yegor Bugayenko
28
28
  # License:: MIT
29
29
  class Judges::Churn
30
- attr_reader :added, :removed
30
+ attr_reader :added, :removed, :errors
31
31
 
32
- def initialize(added, removed)
32
+ def initialize(added, removed, errors = [])
33
33
  @added = added
34
34
  @removed = removed
35
+ @errors = errors
35
36
  end
36
37
 
37
38
  def to_s
38
- "#{@added}/#{@removed}"
39
+ "#{@added}/#{@removed}#{@errors.empty? ? '' : "/#{@errors.size}"}"
39
40
  end
40
41
 
41
42
  def zero?
42
- @added.zero? && @removed.zero?
43
+ @added.zero? && @removed.zero? && @errors.empty?
44
+ end
45
+
46
+ def <<(error)
47
+ @errors << error
48
+ nil
43
49
  end
44
50
 
45
51
  def +(other)
46
52
  if other.is_a?(Judges::Churn)
47
- Judges::Churn.new(@added + other.added, @removed + other.removed)
53
+ Judges::Churn.new(@added + other.added, @removed + other.removed, @errors + other.errors)
48
54
  else
49
- Judges::Churn.new(@added + other, @removed)
55
+ Judges::Churn.new(@added + other, @removed, @errors)
50
56
  end
51
57
  end
52
58
 
53
59
  def -(other)
54
60
  if other.is_a?(Judges::Churn)
55
- Judges::Churn.new(@added - other.added, @removed - other.removed)
61
+ Judges::Churn.new(@added - other.added, @removed - other.removed, @errors + other.errors)
56
62
  else
57
- Judges::Churn.new(@added, @removed + other)
63
+ Judges::Churn.new(@added, @removed + other, @errors)
58
64
  end
59
65
  end
60
66
  end
@@ -47,6 +47,7 @@ class Judges::Pull
47
47
  name = args[0]
48
48
  elapsed(@loog) do
49
49
  if baza.name_exists?(name)
50
+ baza.lock(name, opts['owner'])
50
51
  fb.import(baza.pull(wait(baza, baza.recent(name), opts['wait'])))
51
52
  Judges::Impex.new(@loog, args[1]).export(fb)
52
53
  throw :"Pulled #{fb.size} facts by the name '#{name}'"
@@ -46,7 +46,9 @@ class Judges::Push
46
46
  loog: @loog
47
47
  )
48
48
  elapsed(@loog) do
49
+ baza.lock(name, opts['owner'])
49
50
  id = baza.push(name, fb.export)
51
+ baza.unlock(name, opts['owner'])
50
52
  throw :"Pushed #{fb.size} facts, job ID is #{id}"
51
53
  end
52
54
  end
@@ -72,6 +72,17 @@ class Judges::Update
72
72
  end
73
73
  throw :"Update finished in #{c} cycle(s), modified #{churn} fact(s)"
74
74
  end
75
+ return if churn.zero? || !opts['summary']
76
+ fb.query('(eq what "judges-summary")').delete!
77
+ f = fb.insert
78
+ f.what = 'judges-summary'
79
+ f.when = Time.now
80
+ f.version = Judges::VERSION
81
+ f.cycles = c
82
+ f.added = churn.added.size
83
+ f.removed = churn.removed.size
84
+ churn.errors.each { |e| f.error = e }
85
+ impex.export(fb)
75
86
  end
76
87
 
77
88
  private
@@ -79,12 +90,11 @@ class Judges::Update
79
90
  # Run all judges in a full cycle, one by one.
80
91
  # @return [Churn] How many modifications have been made
81
92
  def cycle(opts, judges, fb, options)
82
- errors = []
83
93
  churn = Judges::Churn.new(0, 0)
84
94
  global = {}
85
95
  elapsed(@loog) do
86
96
  done = judges.each_with_index do |p, i|
87
- @loog.info("\n\n👉 Running #{p.name} (##{i}) at #{p.dir.to_rel}...")
97
+ @loog.info("\n👉 Running #{p.name} (##{i}) at #{p.dir.to_rel}...")
88
98
  elapsed(@loog) do
89
99
  c = one_judge(fb, p, global, options)
90
100
  churn += c
@@ -92,13 +102,13 @@ class Judges::Update
92
102
  end
93
103
  rescue StandardError, SyntaxError => e
94
104
  @loog.warn(Backtrace.new(e))
95
- errors << p.script
105
+ churn << e.message
96
106
  end
97
- throw :"👍 #{done} judge(s) processed" if errors.empty?
98
- throw :"❌ #{done} judge(s) processed with #{errors.size} errors"
107
+ throw :"👍 #{done} judge(s) processed" if churn.errors.empty?
108
+ throw :"❌ #{done} judge(s) processed with #{churn.errors.size} errors"
99
109
  end
100
- unless errors.empty?
101
- raise "Failed to update correctly (#{errors.size} errors)" unless opts['quiet']
110
+ unless churn.errors.empty?
111
+ raise "Failed to update correctly (#{churn.errors.size} errors)" unless opts['quiet']
102
112
  @loog.info('Not failing because of the --quiet flag provided')
103
113
  end
104
114
  churn
data/lib/judges.rb CHANGED
@@ -25,5 +25,5 @@
25
25
  # Copyright:: Copyright (c) 2024 Yegor Bugayenko
26
26
  # License:: MIT
27
27
  module Judges
28
- VERSION = '0.11.0'
28
+ VERSION = '0.13.0'
29
29
  end
@@ -34,6 +34,7 @@ require_relative '../../lib/judges/commands/pull'
34
34
  class TestPull < Minitest::Test
35
35
  def test_pull_simple_factbase
36
36
  WebMock.disable_net_connect!
37
+ stub_request(:get, 'http://example.org/lock/foo?owner=none').to_return(status: 302)
37
38
  stub_request(:get, 'http://example.org/exists/foo').to_return(body: 'yes')
38
39
  stub_request(:get, 'http://example.org/recent/foo.txt').to_return(body: '42')
39
40
  stub_request(:get, 'http://example.org/finished/42').to_return(body: 'yes')
@@ -48,7 +49,8 @@ class TestPull < Minitest::Test
48
49
  'host' => 'example.org',
49
50
  'port' => 80,
50
51
  'ssl' => false,
51
- 'wait' => 10
52
+ 'wait' => 10,
53
+ 'owner' => 'none'
52
54
  },
53
55
  ['foo', file]
54
56
  )
@@ -33,6 +33,8 @@ require_relative '../../lib/judges/commands/push'
33
33
  class TestPush < Minitest::Test
34
34
  def test_push_simple_factbase
35
35
  WebMock.disable_net_connect!
36
+ stub_request(:get, 'https://example.org/lock/foo?owner=none').to_return(status: 302)
37
+ stub_request(:get, 'https://example.org/unlock/foo?owner=none').to_return(status: 302)
36
38
  stub_request(:put, 'https://example.org/push/foo').to_return(
37
39
  status: 200, body: '42'
38
40
  )
@@ -46,7 +48,8 @@ class TestPush < Minitest::Test
46
48
  'token' => '000',
47
49
  'host' => 'example.org',
48
50
  'port' => 443,
49
- 'ssl' => true
51
+ 'ssl' => true,
52
+ 'owner' => 'none'
50
53
  },
51
54
  ['foo', file]
52
55
  )
@@ -55,6 +58,7 @@ class TestPush < Minitest::Test
55
58
 
56
59
  def test_fails_on_http_error
57
60
  WebMock.disable_net_connect!
61
+ stub_request(:get, 'http://example.org/lock/foo?owner=none').to_return(status: 302)
58
62
  stub_request(:put, 'http://example.org/push/foo').to_return(status: 500)
59
63
  Dir.mktmpdir do |d|
60
64
  file = File.join(d, 'base.fb')
@@ -67,7 +71,8 @@ class TestPush < Minitest::Test
67
71
  'token' => '000',
68
72
  'host' => 'example.org',
69
73
  'port' => 80,
70
- 'ssl' => false
74
+ 'ssl' => false,
75
+ 'owner' => 'none'
71
76
  },
72
77
  ['foo', file]
73
78
  )
@@ -64,7 +64,7 @@ class TestUpdate < Minitest::Test
64
64
  Dir.mktmpdir do |d|
65
65
  File.write(File.join(d, 'foo.rb'), 'this$is$a$broken$Ruby$script')
66
66
  file = File.join(d, 'base.fb')
67
- Judges::Update.new(Loog::NULL).run({ 'quiet' => true }, [d, file])
67
+ Judges::Update.new(Loog::NULL).run({ 'quiet' => true, 'max-cycles' => 2 }, [d, file])
68
68
  end
69
69
  end
70
70
 
@@ -77,4 +77,23 @@ class TestUpdate < Minitest::Test
77
77
  end
78
78
  end
79
79
  end
80
+
81
+ def test_update_with_error_and_summary
82
+ Dir.mktmpdir do |d|
83
+ File.write(File.join(d, 'foo.rb'), 'this$is$a$broken$Ruby$script')
84
+ file = File.join(d, 'base.fb')
85
+ 2.times do
86
+ Judges::Update.new(Loog::NULL).run(
87
+ { 'quiet' => true, 'summary' => true, 'max-cycles' => 2 },
88
+ [d, file]
89
+ )
90
+ end
91
+ fb = Factbase.new
92
+ fb.import(File.binread(file))
93
+ sums = fb.query('(eq what "judges-summary")').each.to_a
94
+ assert_equal(1, sums.size)
95
+ f = sums.first
96
+ assert(f.error.include?('unexpected global variable'), f.error)
97
+ end
98
+ end
80
99
  end
data/test/test_churn.rb CHANGED
@@ -35,4 +35,12 @@ class TestChurn < Minitest::Test
35
35
  assert_equal('42/0', (churn + 42).to_s)
36
36
  assert_equal('0/17', (churn - 17).to_s)
37
37
  end
38
+
39
+ def test_with_errors
40
+ churn = Judges::Churn.new(0, 0)
41
+ churn << 'oops'
42
+ assert_equal('0/0/1', churn.to_s)
43
+ assert_equal('42/0/1', (churn + 42).to_s)
44
+ assert_equal('0/0/1', (Judges::Churn.new(0, 0) + churn).to_s)
45
+ end
38
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: judges
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-24 00:00:00.000000000 Z
11
+ date: 2024-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: backtrace
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: concurrent-ruby
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.2.3
33
+ version: '1.2'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.2.3
40
+ version: '1.2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: factbase
43
43
  requirement: !ruby/object:Gem::Requirement