fluentd 0.14.23.rc1 → 0.14.23

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of fluentd might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e963518d8ad90373d793c9af9275cc45720d45e
4
- data.tar.gz: 43875ee26f0702c7c23514d5b38ef8b163e0e6d8
3
+ metadata.gz: 295a3c8dbe521b90ed22fcbc07ed1934d77325ad
4
+ data.tar.gz: 57bcb6c43a76065fc9b3fd681a83f3a4aa2c0eae
5
5
  SHA512:
6
- metadata.gz: ec41c99be159e167051b78446a57e89d7627b7f940d10f4c5bc012224c5e7756fd4cbeccd4e4e59fc2d96204e57851f85c5e089896a4fd0acbe914bfd82e3158
7
- data.tar.gz: 8b2f5f28e11ed7342f816f1e35e5fa9c4de984aad1cbf24c36c273ddc90f4982b06386bdebd31a8259b2dd924d965b84bc194e28cbc6bb6436a71d62109c0cb1
6
+ metadata.gz: ff0029c699dbe57532351805e5d2cd4bc0d65d1635219b18eeddb019b1ff8845b71ac1029367024765b48f2971fa4f999fd7fa361329ecc4394b806651b539f4
7
+ data.tar.gz: d7cb461f8f6cf8d65e088e1ea2db7aed60387280ac7b95c15b0220ee5e527f947cc0cecd9541162a81960f9dbce2393f26eddf4239745270763a59ad7303dbae
@@ -13,7 +13,7 @@ matrix:
13
13
  os: linux
14
14
  - rvm: 2.3.3
15
15
  os: linux
16
- - rvm: 2.4.1
16
+ - rvm: 2.4.2
17
17
  os: linux
18
18
  - rvm: ruby-head
19
19
  os: linux
@@ -26,7 +26,7 @@ matrix:
26
26
  # - rvm: 2.3.3
27
27
  # os: osx
28
28
  # osx_image: xcode8.2 # OSX 10.12
29
- - rvm: 2.4.0
29
+ - rvm: 2.4.1
30
30
  os: osx
31
31
  osx_image: xcode8.3 # OSX 10.12
32
32
  - rvm: ruby-head
@@ -1,5 +1,29 @@
1
1
  # v0.14
2
2
 
3
+ ## Release v0.14.23 - 2017/11/15
4
+
5
+ ### New features / Enhancements
6
+
7
+ * in_udp: Add remove_newline parameter
8
+ https://github.com/fluent/fluentd/pull/1747
9
+
10
+ ### Bug fixes
11
+
12
+ * buffer: Lock buffers in order of metadata
13
+ https://github.com/fluent/fluentd/pull/1722
14
+ * in_tcp: Fix log corruption under load.
15
+ https://github.com/fluent/fluentd/pull/1729
16
+ * out_forward: Fix elapsed time miscalculation in tcp heartbeat
17
+ https://github.com/fluent/fluentd/pull/1738
18
+ * supervisor: Fix worker pid handling during worker restart
19
+ https://github.com/fluent/fluentd/pull/1739
20
+ * in_tail: Skip setup failed watcher to avoid resource leak and log bloat
21
+ https://github.com/fluent/fluentd/pull/1742
22
+ * agent: Add error location to emit error logs
23
+ https://github.com/fluent/fluentd/pull/1746
24
+ * command: Consider hyphen and underscore in fluent-plugin-generate arguments
25
+ https://github.com/fluent/fluentd/pull/1751
26
+
3
27
  ## Release v0.14.22 - 2017/11/01
4
28
 
5
29
  ### New features / Enhancements
@@ -0,0 +1,55 @@
1
+ # Fluentd Governance
2
+
3
+ ## Principles
4
+
5
+ The Fluentd community adheres to the following principles:
6
+
7
+ - Open: Fluentd is open source. See repository guidelines and CLA, below.
8
+ - Welcoming and respectful: See Code of Conduct, below.
9
+ - Transparent and accessible: Work and collaboration are done in public.
10
+ - Merit: Ideas and contributions are accepted according to their technical merit and alignment with project objectives, scope, and design principles.
11
+
12
+ ## Voting
13
+
14
+ The Fluentd project employs "organization voting" to ensure no single organization can dominate the project.
15
+
16
+ Individuals not associated with or employed by a company or organization are allowed one organization vote. Each company or organization (regardless of the number of maintainers associated with or employed by that company/organization) receives one organization vote.
17
+
18
+ In other words, if two maintainers are employed by Company X, two by Company Y, two by Company Z, and one maintainer is an un-affiliated individual, a total of four "organization votes" are possible; one for X, one for Y, one for Z, and one for the un-affiliated individual.
19
+
20
+ Any maintainer from an organization may cast the vote for that organization.
21
+
22
+ For formal votes, a specific statement of what is being voted on should be added to the relevant github issue or PR, and a link to that issue or PR added to the maintainers meeting agenda document. Maintainers should indicate their yes/no vote on that issue or PR, and after a suitable period of time, the votes will be tallied and the outcome noted.
23
+
24
+ ## Changes in Maintainership
25
+
26
+ New maintainers are proposed by an existing maintainer and are elected by a 2/3 majority organization vote.
27
+
28
+ Maintainers can be removed by a 2/3 majority organization vote.
29
+
30
+ ## Github Project Administration
31
+
32
+ Maintainers will be added to the __fluent__ GitHub organization and added to the GitHub cni-maintainers team, and made a GitHub maintainer of that team.
33
+
34
+ After 6 months a maintainer will be made an "owner" of the GitHub organization.
35
+
36
+ ## Projects
37
+
38
+ The fluent organization is open to receive new projects under it umbrella. To apply a project as part of the __fluent__ organization, it have to met the following criteria:
39
+
40
+ - Licensed under the terms of the Apache License v2.0
41
+ - Project have been active for at least one year since it inception
42
+ - More than 2 contributors
43
+ - Related to one or more scopes of Fluentd ecosystem:
44
+ - Data collection
45
+ - Log management
46
+ - Metering
47
+ - Be supported by 2/3 majority of organization
48
+
49
+ The submission process starts as a Pull Request on Fluentd repository with the required information mentioned above.
50
+
51
+ ## Code of Conduct
52
+
53
+ Fluentd follows the CNCF Code of Conduct:
54
+
55
+ https://github.com/cncf/foundation/blob/master/code-of-conduct.md
@@ -137,32 +137,36 @@ BANNER
137
137
  end
138
138
 
139
139
  def gem_name
140
- "fluent-plugin-#{name}"
140
+ "fluent-plugin-#{dash_name}"
141
+ end
142
+
143
+ def plugin_name
144
+ underscore_name
141
145
  end
142
146
 
143
147
  def class_name
144
- "#{name.capitalize}#{type.capitalize}"
148
+ "#{capitalized_name}#{type.capitalize}"
145
149
  end
146
150
 
147
151
  def plugin_filename
148
152
  case type
149
153
  when "input"
150
- "in_#{name}.rb"
154
+ "in_#{underscore_name}.rb"
151
155
  when "output"
152
- "out_#{name}.rb"
156
+ "out_#{underscore_name}.rb"
153
157
  else
154
- "#{type}_#{name}.rb"
158
+ "#{type}_#{underscore_name}.rb"
155
159
  end
156
160
  end
157
161
 
158
162
  def test_filename
159
163
  case type
160
164
  when "input"
161
- "test_in_#{name}.rb"
165
+ "test_in_#{underscore_name}.rb"
162
166
  when "output"
163
- "test_out_#{name}.rb"
167
+ "test_out_#{underscore_name}.rb"
164
168
  else
165
- "test_#{type}_#{name}.rb"
169
+ "test_#{type}_#{underscore_name}.rb"
166
170
  end
167
171
  end
168
172
 
@@ -179,6 +183,18 @@ BANNER
179
183
  end
180
184
  end
181
185
 
186
+ def capitalized_name
187
+ @capitalized_name ||= name.split(/[-_]/).map(&:capitalize).join
188
+ end
189
+
190
+ def underscore_name
191
+ @underscore_name ||= name.tr("-", "_")
192
+ end
193
+
194
+ def dash_name
195
+ @dash_name ||= name.tr("_", "-")
196
+ end
197
+
182
198
  def preamble
183
199
  @license.preamble(user_name)
184
200
  end
@@ -34,6 +34,16 @@ module Fluent::Plugin
34
34
 
35
35
  helpers :timer, :event_loop, :parser, :compat_parameters
36
36
 
37
+ class WatcherSetupError < StandardError
38
+ def initialize(msg)
39
+ @message = msg
40
+ end
41
+
42
+ def to_s
43
+ @message
44
+ end
45
+ end
46
+
37
47
  FILE_PERMISSION = 0644
38
48
 
39
49
  def initialize
@@ -250,6 +260,12 @@ module Fluent::Plugin
250
260
  event_loop_attach(watcher.stat_trigger)
251
261
  end
252
262
  tw
263
+ rescue => e
264
+ if tw
265
+ tw.detach
266
+ tw.close
267
+ end
268
+ raise e
253
269
  end
254
270
 
255
271
  def start_watchers(paths)
@@ -266,7 +282,13 @@ module Fluent::Plugin
266
282
  end
267
283
  end
268
284
 
269
- @tails[path] = setup_watcher(path, pe)
285
+ begin
286
+ tw = setup_watcher(path, pe)
287
+ rescue WatcherSetupError => e
288
+ log.warn "Skip #{path} because unexpected setup error happens: #{e}"
289
+ next
290
+ end
291
+ @tails[path] = tw
270
292
  }
271
293
  end
272
294
 
@@ -480,8 +502,8 @@ module Fluent::Plugin
480
502
  end
481
503
 
482
504
  def detach
483
- @timer_trigger.detach if @enable_watch_timer && @timer_trigger.attached?
484
- @stat_trigger.detach if @stat_trigger.attached?
505
+ @timer_trigger.detach if @enable_watch_timer && @timer_trigger && @timer_trigger.attached?
506
+ @stat_trigger.detach if @stat_trigger && @stat_trigger.attached?
485
507
  @io_handler.on_notify if @io_handler
486
508
  end
487
509
 
@@ -698,6 +720,9 @@ module Fluent::Plugin
698
720
  io = Fluent::FileWrapper.open(@watcher.path)
699
721
  io.seek(@watcher.pe.read_pos + @fifo.bytesize)
700
722
  io
723
+ rescue RangeError
724
+ io.close if io
725
+ raise WatcherSetupError, "seek error with #{@watcher.path}: file position = #{@watcher.pe.read_pos.to_s(16)}, reading bytesize = #{@fifo.bytesize.to_s(16)}"
701
726
  rescue Errno::ENOENT
702
727
  nil
703
728
  end
@@ -715,6 +740,9 @@ module Fluent::Plugin
715
740
  @io ||= open
716
741
  yield @io
717
742
  end
743
+ rescue WatcherSetupError => e
744
+ close
745
+ raise e
718
746
  rescue
719
747
  @watcher.log.error $!.to_s
720
748
  @watcher.log.error_backtrace
@@ -38,6 +38,8 @@ module Fluent::Plugin
38
38
  config_param :body_size_limit, :size, default: nil, deprecated: "use message_length_limit instead."
39
39
  desc "The max bytes of message"
40
40
  config_param :message_length_limit, :size, default: 4096
41
+ desc "Remove newline from the end of incoming payload"
42
+ config_param :remove_newline, :bool, default: true
41
43
 
42
44
  config_param :blocking_timeout, :time, default: 0.5
43
45
 
@@ -60,7 +62,7 @@ module Fluent::Plugin
60
62
 
61
63
  log.info "listening udp socket", bind: @bind, port: @port
62
64
  server_create(:in_udp_server, @port, proto: :udp, bind: @bind, max_bytes: @message_length_limit) do |data, sock|
63
- data.chomp!
65
+ data.chomp! if @remove_newline
64
66
  begin
65
67
  @parser.parse(data) do |time, record|
66
68
  unless time && record
@@ -395,9 +395,6 @@ module Fluent::Plugin
395
395
 
396
396
  def on_timer
397
397
  @nodes.each {|n|
398
- if n.tick
399
- rebuild_weight_array
400
- end
401
398
  begin
402
399
  log.trace "sending heartbeat", host: n.host, port: n.port, heartbeat_type: @heartbeat_type
403
400
  n.usock = @usock if @usock
@@ -407,6 +404,9 @@ module Fluent::Plugin
407
404
  rescue => e
408
405
  log.debug "unexpected error happen during heartbeat", host: n.host, port: n.port, heartbeat_type: @heartbeat_type, error: e
409
406
  end
407
+ if n.tick
408
+ rebuild_weight_array
409
+ end
410
410
  }
411
411
  end
412
412
 
@@ -292,7 +292,7 @@ module Fluent
292
292
  end
293
293
 
294
294
  def emit_error_event(tag, time, record, error)
295
- error_info = {error: error, tag: tag, time: time}
295
+ error_info = {error: error, location: (error.backtrace ? error.backtrace.first : nil), tag: tag, time: time}
296
296
  if @error_collector
297
297
  # A record is not included in the logs because <@ERROR> handles it. This warn is for the notification
298
298
  log.warn "send an error event to @ERROR:", error_info
@@ -304,7 +304,7 @@ module Fluent
304
304
  end
305
305
 
306
306
  def handle_emits_error(tag, es, error)
307
- error_info = {error: error, tag: tag}
307
+ error_info = {error: error, location: (error.backtrace ? error.backtrace.first : nil), tag: tag}
308
308
  if @error_collector
309
309
  log.warn "send an error event stream to @ERROR:", error_info
310
310
  @error_collector.emit_stream(tag, es)
@@ -333,7 +333,7 @@ module Fluent
333
333
  end
334
334
 
335
335
  def emit_error_event(tag, time, record, error)
336
- error_info = {error: error, tag: tag, time: time, record: record}
336
+ error_info = {error: error, location: (error.backtrace ? error.backtrace.first : nil), tag: tag, time: time, record: record}
337
337
  log.warn "dump an error event in @ERROR:", error_info
338
338
  end
339
339
 
@@ -164,7 +164,7 @@ module Fluent
164
164
  end
165
165
 
166
166
  if config[:worker_pid]
167
- config[:worker_pid].each do |pid|
167
+ config[:worker_pid].each_value do |pid|
168
168
  Process.kill(:USR1, pid)
169
169
  # don't rescue Erro::ESRSH here (invalid status)
170
170
  end
@@ -175,7 +175,7 @@ module Fluent
175
175
  if config[:worker_pid]
176
176
  pids = config[:worker_pid].clone
177
177
  config[:worker_pid].clear
178
- pids.each do |pid|
178
+ pids.each_value do |pid|
179
179
  if Fluent.windows?
180
180
  Process.kill :KILL, pid
181
181
  else
@@ -204,7 +204,7 @@ module Fluent
204
204
  end
205
205
 
206
206
  def after_start
207
- (config[:worker_pid] ||= []).push(@pm.pid)
207
+ (config[:worker_pid] ||= {})[@worker_id] = @pm.pid
208
208
  end
209
209
  end
210
210
 
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '0.14.23.rc1'
19
+ VERSION = '0.14.23'
20
20
 
21
21
  end
@@ -5,7 +5,7 @@ require "fluent/plugin/filter"
5
5
  module Fluent
6
6
  module Plugin
7
7
  class <%= class_name %> < Fluent::Plugin::Filter
8
- Fluent::Plugin.register_filter("<%= name %>", self)
8
+ Fluent::Plugin.register_filter("<%= plugin_name %>", self)
9
9
 
10
10
  def filter(tag, time, record)
11
11
  end
@@ -5,7 +5,7 @@ require "fluent/plugin/input"
5
5
  module Fluent
6
6
  module Plugin
7
7
  class <%= class_name %> < Fluent::Plugin::Input
8
- Fluent::Plugin.register_input("<%= name %>", self)
8
+ Fluent::Plugin.register_input("<%= plugin_name %>", self)
9
9
  end
10
10
  end
11
11
  end
@@ -5,7 +5,7 @@ require "fluent/plugin/output"
5
5
  module Fluent
6
6
  module Plugin
7
7
  class <%= class_name %> < Fluent::Plugin::Output
8
- Fluent::Plugin.register_output("<%= name %>", self)
8
+ Fluent::Plugin.register_output("<%= plugin_name %>", self)
9
9
  end
10
10
  end
11
11
  end
@@ -5,7 +5,7 @@ require "fluent/plugin/parser"
5
5
  module Fluent
6
6
  module Plugin
7
7
  class <%= class_name %> < Fluent::Plugin::Parser
8
- Fluent::Plugin.register_parser("<%= name %>", self)
8
+ Fluent::Plugin.register_parser("<%= plugin_name %>", self)
9
9
  end
10
10
 
11
11
  def parse(text)
@@ -16,51 +16,77 @@ class TestFluentPluginGenerator < Test::Unit::TestCase
16
16
  FileUtils.rm_rf(TEMP_DIR)
17
17
  end
18
18
 
19
- data(input: ["input", "in"],
20
- output: ["output", "out"],
21
- filter: ["filter", "filter"],
22
- parser: ["parser", "parser"],
23
- formatter: ["formatter", "formatter"])
24
- test "generate plugin" do |(type, part)|
25
- capture_stdout do
26
- FluentPluginGenerator.new([type, "fake"]).call
19
+ sub_test_case "generate plugin" do
20
+ data(input: ["input", "in"],
21
+ output: ["output", "out"],
22
+ filter: ["filter", "filter"],
23
+ parser: ["parser", "parser"],
24
+ formatter: ["formatter", "formatter"])
25
+ test "generate plugin" do |(type, part)|
26
+ capture_stdout do
27
+ FluentPluginGenerator.new([type, "fake"]).call
28
+ end
29
+ plugin_base_dir = Pathname("fluent-plugin-fake")
30
+ assert { plugin_base_dir.directory? }
31
+ expected = [
32
+ "fluent-plugin-fake",
33
+ "fluent-plugin-fake/Gemfile",
34
+ "fluent-plugin-fake/LICENSE",
35
+ "fluent-plugin-fake/README.md",
36
+ "fluent-plugin-fake/Rakefile",
37
+ "fluent-plugin-fake/fluent-plugin-fake.gemspec",
38
+ "fluent-plugin-fake/lib",
39
+ "fluent-plugin-fake/lib/fluent",
40
+ "fluent-plugin-fake/lib/fluent/plugin",
41
+ "fluent-plugin-fake/lib/fluent/plugin/#{part}_fake.rb",
42
+ "fluent-plugin-fake/test",
43
+ "fluent-plugin-fake/test/helper.rb",
44
+ "fluent-plugin-fake/test/plugin",
45
+ "fluent-plugin-fake/test/plugin/test_#{part}_fake.rb",
46
+ ]
47
+ actual = plugin_base_dir.find.reject {|f| f.fnmatch("*/.git*") }.map(&:to_s).sort
48
+ assert_equal(expected, actual)
27
49
  end
28
- plugin_base_dir = Pathname("fluent-plugin-fake")
29
- assert { plugin_base_dir.directory? }
30
- expected = [
31
- "fluent-plugin-fake",
32
- "fluent-plugin-fake/Gemfile",
33
- "fluent-plugin-fake/LICENSE",
34
- "fluent-plugin-fake/README.md",
35
- "fluent-plugin-fake/Rakefile",
36
- "fluent-plugin-fake/fluent-plugin-fake.gemspec",
37
- "fluent-plugin-fake/lib",
38
- "fluent-plugin-fake/lib/fluent",
39
- "fluent-plugin-fake/lib/fluent/plugin",
40
- "fluent-plugin-fake/lib/fluent/plugin/#{part}_fake.rb",
41
- "fluent-plugin-fake/test",
42
- "fluent-plugin-fake/test/helper.rb",
43
- "fluent-plugin-fake/test/plugin",
44
- "fluent-plugin-fake/test/plugin/test_#{part}_fake.rb",
45
- ]
46
- actual = plugin_base_dir.find.reject {|f| f.fnmatch("*/.git*") }.map(&:to_s).sort
47
- assert_equal(expected, actual)
48
- end
49
50
 
50
- test "no license" do
51
- capture_stdout do
52
- FluentPluginGenerator.new(["--no-license", "filter", "fake"]).call
51
+ test "no license" do
52
+ capture_stdout do
53
+ FluentPluginGenerator.new(["--no-license", "filter", "fake"]).call
54
+ end
55
+ assert { !Pathname("fluent-plugin-fake/LICENSE").exist? }
56
+ assert { Pathname("fluent-plugin-fake/Gemfile").exist? }
57
+ end
58
+
59
+ test "unknown license" do
60
+ out = capture_stdout do
61
+ assert_raise(SystemExit) do
62
+ FluentPluginGenerator.new(["--license=unknown", "filter", "fake"]).call
63
+ end
64
+ end
65
+ assert { out.lines.include?("License: unknown\n") }
53
66
  end
54
- assert { !Pathname("fluent-plugin-fake/LICENSE").exist? }
55
- assert { Pathname("fluent-plugin-fake/Gemfile").exist? }
56
67
  end
57
68
 
58
- test "unknown license" do
59
- out = capture_stdout do
60
- assert_raise(SystemExit) do
61
- FluentPluginGenerator.new(["--license=unknown", "filter", "fake"]).call
69
+ sub_test_case "unify plugin name" do
70
+ data("word" => ["fake", "fake"],
71
+ "underscore" => ["rewrite_tag_filter", "rewrite_tag_filter"],
72
+ "dash" => ["rewrite-tag-filter", "rewrite_tag_filter"])
73
+ test "plugin_name" do |(name, plugin_name)|
74
+ generator = FluentPluginGenerator.new(["filter", name])
75
+ capture_stdout do
76
+ generator.call
77
+ end
78
+ assert_equal(plugin_name, generator.__send__(:plugin_name))
79
+ end
80
+
81
+ data("word" => ["fake", "fluent-plugin-fake"],
82
+ "underscore" => ["rewrite_tag_filter", "fluent-plugin-rewrite-tag-filter"],
83
+ "dash" => ["rewrite-tag-filter", "fluent-plugin-rewrite-tag-filter"])
84
+ test "gem_name" do |(name, gem_name)|
85
+ generator = FluentPluginGenerator.new(["output", name])
86
+ capture_stdout do
87
+ generator.call
62
88
  end
89
+ assert_equal(gem_name, generator.__send__(:gem_name))
63
90
  end
64
- assert { out.lines.include?("License: unknown\n") }
65
91
  end
66
92
  end
@@ -149,4 +149,27 @@ class UdpInputTest < Test::Unit::TestCase
149
149
  assert_equal expected_record, d.events[i][2]
150
150
  end
151
151
  end
152
+
153
+ test 'remove_newline' do
154
+ d = create_driver(BASE_CONFIG + %!
155
+ format none
156
+ remove_newline false
157
+ !)
158
+ payloads = ["test1\n", "test2\n"]
159
+ d.run(expect_records: 2) do
160
+ create_udp_socket('127.0.0.1', PORT) do |u|
161
+ payloads.each do |payload|
162
+ u.send(payload, 0)
163
+ end
164
+ end
165
+ end
166
+
167
+ expecteds = payloads.map { |payload| {'message' => payload} }
168
+ assert_equal 2, d.events.size
169
+ expecteds.each_with_index do |expected_record, i|
170
+ assert_equal "udp", d.events[i][0]
171
+ assert d.events[i][1].is_a?(Fluent::EventTime)
172
+ assert_equal expected_record, d.events[i][2]
173
+ end
174
+ end
152
175
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluentd
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.23.rc1
4
+ version: 0.14.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-07 00:00:00.000000000 Z
11
+ date: 2017-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -324,6 +324,7 @@ files:
324
324
  - CONTRIBUTING.md
325
325
  - COPYING
326
326
  - ENTERPRISE_PROVIDERS.md
327
+ - GOVERNANCE.md
327
328
  - Gemfile
328
329
  - MAINTAINERS.md
329
330
  - README.md
@@ -736,9 +737,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
736
737
  version: '2.1'
737
738
  required_rubygems_version: !ruby/object:Gem::Requirement
738
739
  requirements:
739
- - - ">"
740
+ - - ">="
740
741
  - !ruby/object:Gem::Version
741
- version: 1.3.1
742
+ version: '0'
742
743
  requirements: []
743
744
  rubyforge_project:
744
745
  rubygems_version: 2.6.13