chef 12.1.0.rc.0 → 12.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e9c7d72a1bb22b0477282799c72de62ea5f2a81d
4
- data.tar.gz: f80c1c36bac01861d0b216c1df5f17762c28849a
3
+ metadata.gz: 1c03a42f5cdc6d6db6b15583d95b6e865828e0fc
4
+ data.tar.gz: eb9eeb4f03d56ed71fcea101d015eb86e41211ce
5
5
  SHA512:
6
- metadata.gz: 8807e256d51b7e5738d9be8262423ee32f014fcceb0e37dc1830697ffa45934d4f6d343c54a73444cd826d433edd22aa325234eb8189f872d63f2810b6365838
7
- data.tar.gz: 45f84064ef58c0b536e06ee948dda070d5636d389323dc611efd25cd7176c17c82703c0adfe310c52feb3105548bdfbe9d97041c79525fa27bf1da548ae4dc6b
6
+ metadata.gz: b5b1f35e77c6413fdb63a72709994ebd0871c359ac8ecf38d0f01a284c84ed5e96c3aca1f59d01846aa49a1f3b2fbc9a1ece7462b9a2882c70ab27f534c867d7
7
+ data.tar.gz: 7fc10d7fe903d5efdd098cf077004b38fde87de69d8c04c77fcc4d110ec5b649b61c12594de70c6e1d0f6bb0ebfdf42ebefcd7fe894698cb16c972168cf29bb1
@@ -189,9 +189,15 @@ class Chef
189
189
  config_params += " -c #{Chef::Config[:config_file]}" unless Chef::Config[:config_file].nil?
190
190
  config_params += " -L #{Chef::Config[:log_location]}" unless Chef::Config[:log_location] == STDOUT
191
191
  # Starts a new process and waits till the process exits
192
- result = shell_out("chef-client #{config_params}")
192
+ result = shell_out("chef-client #{config_params}", :timeout => Chef::Config[:windows_service][:watchdog_timeout])
193
193
  Chef::Log.debug "#{result.stdout}"
194
194
  Chef::Log.debug "#{result.stderr}"
195
+ rescue Mixlib::ShellOut::CommandTimeout => e
196
+ Chef::Log.error "chef-client timed out\n(#{e})"
197
+ Chef::Log.error(<<-EOF)
198
+ Your chef-client run timed out. You can increase the time chef-client is given
199
+ to complete by configuring windows_service.watchdog_timeout in your client.rb.
200
+ EOF
195
201
  rescue Mixlib::ShellOut::ShellCommandFailed => e
196
202
  Chef::Log.warn "Not able to start chef-client in new process (#{e})"
197
203
  rescue => e
@@ -36,11 +36,11 @@ class Chef
36
36
  # We need the canonical cookbook name if we are using versioned cookbooks, but we don't
37
37
  # want to spend a lot of time adding code to the main Chef libraries
38
38
  if root.versioned_cookbooks
39
- _canonical_name = canonical_cookbook_name(File.basename(file_path))
40
- fail "When versioned_cookbooks mode is on, cookbook #{file_path} must match format <cookbook_name>-x.y.z" unless _canonical_name
39
+ canonical_name = canonical_cookbook_name(File.basename(file_path))
40
+ fail "When versioned_cookbooks mode is on, cookbook #{file_path} must match format <cookbook_name>-x.y.z" unless canonical_name
41
41
 
42
42
  # KLUDGE: We shouldn't have to use instance_variable_set
43
- loader.instance_variable_set(:@cookbook_name, _canonical_name)
43
+ loader.instance_variable_set(:@cookbook_name, canonical_name)
44
44
  end
45
45
 
46
46
  loader.load_cookbooks
@@ -643,6 +643,12 @@ class Chef
643
643
  default :normal_attribute_whitelist, nil
644
644
  default :override_attribute_whitelist, nil
645
645
 
646
+ config_context :windows_service do
647
+ # Set `watchdog_timeout` to the number of seconds to wait for a chef-client run
648
+ # to finish
649
+ default :watchdog_timeout, 2 * (60 * 60) # 2 hours
650
+ end
651
+
646
652
  # Chef requires an English-language UTF-8 locale to function properly. We attempt
647
653
  # to use the 'locale -a' command and search through a list of preferences until we
648
654
  # find one that we can use. On Ubuntu systems we should find 'C.UTF-8' and be
@@ -20,6 +20,7 @@
20
20
  require 'chef/mixin/convert_to_class_name'
21
21
  require 'chef/exceptions'
22
22
  require 'chef/resource_builder'
23
+ require 'chef/mixin/shell_out'
23
24
 
24
25
  class Chef
25
26
  module DSL
@@ -313,7 +313,8 @@ class Chef
313
313
 
314
314
  # chef-vault integration must use the new client-side hawtness, otherwise to use the
315
315
  # new client-side hawtness, just delete your validation key.
316
- if chef_vault_handler.doing_chef_vault? || !File.exist?(File.expand_path(Chef::Config[:validation_key]))
316
+ if chef_vault_handler.doing_chef_vault? ||
317
+ (Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key])))
317
318
  client_builder.run
318
319
 
319
320
  chef_vault_handler.run(node_name: config[:chef_node_name])
@@ -73,14 +73,6 @@ class Chef
73
73
  begin
74
74
  Chef::Log.debug("Temp cookbook directory is #{tmp_cookbook_dir.inspect}")
75
75
  ui.info("Making tarball #{cookbook_name}.tgz")
76
- tar_cmd = "tar"
77
- begin
78
- # Unix and Mac only - prefer gnutar
79
- if shell_out("which gnutar").exitstatus.equal?(0)
80
- tar_cmd = "gnutar"
81
- end
82
- rescue Errno::ENOENT
83
- end
84
76
  shell_out!("#{tar_cmd} -czf #{cookbook_name}.tgz #{cookbook_name}", :cwd => tmp_cookbook_dir)
85
77
  rescue => e
86
78
  ui.error("Error making tarball #{cookbook_name}.tgz: #{e.message}. Increase log verbosity (-VV) for more information.")
@@ -90,7 +82,7 @@ class Chef
90
82
 
91
83
  if config[:dry_run]
92
84
  ui.info("Not uploading #{cookbook_name}.tgz due to --dry-run flag.")
93
- result = shell_out!("tar -tzf #{cookbook_name}.tgz", :cwd => tmp_cookbook_dir)
85
+ result = shell_out!("#{tar_cmd} -tzf #{cookbook_name}.tgz", :cwd => tmp_cookbook_dir)
94
86
  ui.info(result.stdout)
95
87
  FileUtils.rm_rf tmp_cookbook_dir
96
88
  return
@@ -158,6 +150,20 @@ class Chef
158
150
  end
159
151
  res
160
152
  end
153
+
154
+ def tar_cmd
155
+ if !@tar_cmd
156
+ @tar_cmd = "tar"
157
+ begin
158
+ # Unix and Mac only - prefer gnutar
159
+ if shell_out("which gnutar").exitstatus.equal?(0)
160
+ @tar_cmd = "gnutar"
161
+ end
162
+ rescue Errno::ENOENT
163
+ end
164
+ end
165
+ @tar_cmd
166
+ end
161
167
  end
162
168
 
163
169
  end
@@ -123,8 +123,8 @@ class Chef
123
123
  if ui.interchange?
124
124
  output({:results => result_count, :rows => result_items})
125
125
  else
126
- ui.msg "#{result_count} items found"
127
- ui.msg("\n")
126
+ ui.log "#{result_count} items found"
127
+ ui.log("\n")
128
128
  result_items.each do |item|
129
129
  output(item)
130
130
  unless config[:id_only]
@@ -76,17 +76,17 @@ class Chef
76
76
  def run_command_compatible_options(command_args)
77
77
  return command_args unless command_args.last.is_a?(Hash)
78
78
 
79
- _command_args = command_args.dup
80
- _options = _command_args.last
79
+ my_command_args = command_args.dup
80
+ my_options = my_command_args.last
81
81
 
82
82
  DEPRECATED_OPTIONS.each do |old_option, new_option|
83
83
  # Edge case: someone specifies :command_log_level and 'command_log_level' in the option hash
84
- next unless value = _options.delete(old_option) || _options.delete(old_option.to_s)
84
+ next unless value = my_options.delete(old_option) || my_options.delete(old_option.to_s)
85
85
  deprecate_option old_option, new_option
86
- _options[new_option] = value
86
+ my_options[new_option] = value
87
87
  end
88
88
 
89
- return _command_args
89
+ return my_command_args
90
90
  end
91
91
 
92
92
  private
@@ -48,10 +48,10 @@ class Chef
48
48
  # Otherwise look up the path to the ports directory using 'whereis'
49
49
  else
50
50
  whereis = shell_out!("whereis -s #{port}", :env => nil)
51
- unless _path = whereis.stdout[/^#{Regexp.escape(port)}:\s+(.+)$/, 1]
51
+ unless path = whereis.stdout[/^#{Regexp.escape(port)}:\s+(.+)$/, 1]
52
52
  raise Chef::Exceptions::Package, "Could not find port with the name #{port}"
53
53
  end
54
- _path
54
+ path
55
55
  end
56
56
  end
57
57
 
@@ -18,7 +18,6 @@
18
18
 
19
19
  require 'chef/config'
20
20
  require 'chef/provider/package'
21
- require 'chef/mixin/command' # handle_command_failures
22
21
  require 'chef/mixin/shell_out'
23
22
  require 'chef/resource/package'
24
23
  require 'singleton'
@@ -984,7 +983,7 @@ class Chef
984
983
  end
985
984
 
986
985
  def yum_command(command)
987
- status, stdout, stderr = output_of_command(command, {:timeout => Chef::Config[:yum_timeout]})
986
+ status = shell_out(command, {:timeout => Chef::Config[:yum_timeout]})
988
987
 
989
988
  # This is fun: rpm can encounter errors in the %post/%postun scripts which aren't
990
989
  # considered fatal - meaning the rpm is still successfully installed. These issue
@@ -996,21 +995,20 @@ class Chef
996
995
  # A cleaner solution would have to be done in python and better hook into
997
996
  # yum/rpm to handle exceptions as we see fit.
998
997
  if status.exitstatus == 1
999
- stdout.each_line do |l|
998
+ status.stdout.each_line do |l|
1000
999
  # rpm-4.4.2.3 lib/psm.c line 2182
1001
1000
  if l =~ %r{^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$}
1002
1001
  Chef::Log.warn("#{@new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " +
1003
1002
  "so running install again to verify.")
1004
- status, stdout, stderr = output_of_command(command, {:timeout => Chef::Config[:yum_timeout]})
1003
+ status = shell_out(command, {:timeout => Chef::Config[:yum_timeout]})
1005
1004
  break
1006
1005
  end
1007
1006
  end
1008
1007
  end
1009
1008
 
1010
1009
  if status.exitstatus > 0
1011
- command_output = "STDOUT: #{stdout}"
1012
- command_output << "STDERR: #{stderr}"
1013
- Chef::Mixin::Command.handle_command_failures(status, command_output, {})
1010
+ command_output = "STDOUT: #{status.stdout}\nSTDERR: #{status.stderr}"
1011
+ raise Chef::Exceptions::Exec, "#{command} returned #{status.exitstatus}:\n#{command_output}"
1014
1012
  end
1015
1013
  end
1016
1014
 
@@ -34,8 +34,6 @@ class Chef
34
34
  )
35
35
  end
36
36
 
37
- protected
38
-
39
37
  # Allow callers evaluating guards to request default
40
38
  # attribute values. This is needed to allow
41
39
  # convert_boolean_return to be true in guard context by default,
@@ -165,8 +165,6 @@ class Chef
165
165
  Chef::User.from_hash(response)
166
166
  end
167
167
 
168
- private
169
-
170
168
  # Gross. Transforms an API response in the form of:
171
169
  # [ { "user" => { "username" => USERNAME }}, ...]
172
170
  # into the form
@@ -179,5 +177,7 @@ class Chef
179
177
  end
180
178
  new_response
181
179
  end
180
+
181
+ private_class_method :transform_ohc_list_response
182
182
  end
183
183
  end
@@ -17,7 +17,7 @@
17
17
 
18
18
  class Chef
19
19
  CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
20
- VERSION = '12.1.0.rc.0'
20
+ VERSION = '12.1.0'
21
21
  end
22
22
 
23
23
  #
@@ -32,17 +32,15 @@ class Chef
32
32
 
33
33
  new_data = {}
34
34
  whitelist.each do |item|
35
- self.add_data(data, new_data, item)
35
+ add_data(data, new_data, item)
36
36
  end
37
37
  new_data
38
38
  end
39
39
 
40
- private
41
-
42
40
  # Walk the data has according to the keys provided by the whitelisted item
43
41
  # and add the data to the whitelisting result.
44
42
  def self.add_data(data, new_data, item)
45
- parts = self.to_array(item)
43
+ parts = to_array(item)
46
44
 
47
45
  all_data = data
48
46
  filtered_data = new_data
@@ -68,6 +66,8 @@ class Chef
68
66
  new_data
69
67
  end
70
68
 
69
+ private_class_method :add_data
70
+
71
71
  # Accepts a String or an Array, and returns an Array of String keys that
72
72
  # are used to traverse the data hash. Strings are split on "/", Arrays are
73
73
  # assumed to contain exact keys (that is, Array elements will not be split
@@ -80,5 +80,7 @@ class Chef
80
80
  parts
81
81
  end
82
82
 
83
+ private_class_method :to_array
84
+
83
85
  end
84
86
  end
@@ -106,8 +106,6 @@ class Chef
106
106
  struct[:AceType]
107
107
  end
108
108
 
109
- private
110
-
111
109
  def self.create_ace_with_mask_and_sid(type, flags, mask, sid)
112
110
  size_needed = size_with_sid(sid)
113
111
  pointer = FFI::MemoryPointer.new size_needed
@@ -90,11 +90,13 @@ class Chef
90
90
  def to_s
91
91
  "[#{self.collect { |ace| ace.to_s }.join(", ")}]"
92
92
  end
93
- private
94
93
 
95
94
  def self.align_dword(size)
96
95
  (size + 4 - 1) & 0xfffffffc
97
96
  end
97
+
98
+ private_class_method :align_dword
99
+
98
100
  end
99
101
  end
100
102
  end
@@ -34,18 +34,18 @@ class Chef
34
34
  # http://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx
35
35
  # http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx
36
36
 
37
- private
38
-
39
37
  def self.get_system_metrics(n_index)
40
38
  GetSystemMetrics(n_index)
41
39
  end
42
40
 
41
+ private_class_method :get_system_metrics
42
+
43
43
  def self.method_name_from_marketing_name(marketing_name)
44
44
  "#{marketing_name.gsub(/\s/, '_').gsub(/\./, '_').downcase}?"
45
45
  # "#{marketing_name.gsub(/\s/, '_').gsub(//, '_').downcase}?"
46
46
  end
47
47
 
48
- public
48
+ private_class_method :method_name_from_marketing_name
49
49
 
50
50
  WIN_VERSIONS = {
51
51
  "Windows 10" => {:major => 6, :minor => 4, :callable => lambda{ |product_type, suite_mask| product_type == VER_NT_WORKSTATION }},
@@ -593,6 +593,20 @@ describe Chef::Knife::Bootstrap do
593
593
  knife.run
594
594
  end
595
595
  end
596
+
597
+ context "when the validation_key is nil" do
598
+ before do
599
+ # this tests runs the old code path where we have a validation key, so we need to pass that check for some plugins
600
+ Chef::Config[:validation_key] = nil
601
+ end
602
+
603
+ it "creates the client and does not run client_builder or the chef_vault_handler" do
604
+ expect(knife_ssh).to receive(:run)
605
+ expect(knife.client_builder).not_to receive(:run)
606
+ expect(knife.chef_vault_handler).not_to receive(:run)
607
+ knife.run
608
+ end
609
+ end
596
610
  end
597
611
 
598
612
  describe "specifying ssl verification" do
@@ -144,8 +144,9 @@ describe Chef::Knife::CookbookSiteShare do
144
144
  end
145
145
 
146
146
  it "should list files in the tarball" do
147
- expect(@knife).to receive(:shell_out!).with("tar -czf #{@cookbook.name}.tgz #{@cookbook.name}", {:cwd => "/var/tmp/dummy"})
148
- expect(@knife).to receive(:shell_out!).with("tar -tzf #{@cookbook.name}.tgz", {:cwd => "/var/tmp/dummy"})
147
+ allow(@knife).to receive(:tar_cmd).and_return("footar")
148
+ expect(@knife).to receive(:shell_out!).with("footar -czf #{@cookbook.name}.tgz #{@cookbook.name}", {:cwd => "/var/tmp/dummy"})
149
+ expect(@knife).to receive(:shell_out!).with("footar -tzf #{@cookbook.name}.tgz", {:cwd => "/var/tmp/dummy"})
149
150
  @knife.run
150
151
  end
151
152
 
@@ -696,9 +696,9 @@ describe Chef::Provider::Package::Yum do
696
696
 
697
697
  describe "when running yum" do
698
698
  it "should run yum once if it exits with a return code of 0" do
699
- @status = double("Status", :exitstatus => 0)
700
- allow(@provider).to receive(:output_of_command).and_return([@status, "", ""])
701
- expect(@provider).to receive(:output_of_command).once.with(
699
+ @status = double("Status", :exitstatus => 0, :stdout => "", :stderr => "")
700
+ allow(@provider).to receive(:shell_out).and_return(@status)
701
+ expect(@provider).to receive(:shell_out).once.with(
702
702
  "yum -d0 -e0 -y install emacs-1.0",
703
703
  {:timeout => Chef::Config[:yum_timeout]}
704
704
  )
@@ -706,9 +706,9 @@ describe Chef::Provider::Package::Yum do
706
706
  end
707
707
 
708
708
  it "should run yum once if it exits with a return code > 0 and no scriptlet failures" do
709
- @status = double("Status", :exitstatus => 2)
710
- allow(@provider).to receive(:output_of_command).and_return([@status, "failure failure", "problem problem"])
711
- expect(@provider).to receive(:output_of_command).once.with(
709
+ @status = double("Status", :exitstatus => 2, :stdout => "failure failure", :stderr => "problem problem")
710
+ allow(@provider).to receive(:shell_out).and_return(@status)
711
+ expect(@provider).to receive(:shell_out).once.with(
712
712
  "yum -d0 -e0 -y install emacs-1.0",
713
713
  {:timeout => Chef::Config[:yum_timeout]}
714
714
  )
@@ -716,9 +716,10 @@ describe Chef::Provider::Package::Yum do
716
716
  end
717
717
 
718
718
  it "should run yum once if it exits with a return code of 1 and %pre scriptlet failures" do
719
- @status = double("Status", :exitstatus => 1)
720
- allow(@provider).to receive(:output_of_command).and_return([@status, "error: %pre(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2", ""])
721
- expect(@provider).to receive(:output_of_command).once.with(
719
+ @status = double("Status", :exitstatus => 1, :stdout => "error: %pre(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2",
720
+ :stderr => "")
721
+ allow(@provider).to receive(:shell_out).and_return(@status)
722
+ expect(@provider).to receive(:shell_out).once.with(
722
723
  "yum -d0 -e0 -y install emacs-1.0",
723
724
  {:timeout => Chef::Config[:yum_timeout]}
724
725
  )
@@ -727,9 +728,10 @@ describe Chef::Provider::Package::Yum do
727
728
  end
728
729
 
729
730
  it "should run yum twice if it exits with a return code of 1 and %post scriptlet failures" do
730
- @status = double("Status", :exitstatus => 1)
731
- allow(@provider).to receive(:output_of_command).and_return([@status, "error: %post(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2", ""])
732
- expect(@provider).to receive(:output_of_command).twice.with(
731
+ @status = double("Status", :exitstatus => 1, :stdout => "error: %post(demo-1-1.el5.centos.x86_64) scriptlet failed, exit status 2",
732
+ :stderr => "")
733
+ allow(@provider).to receive(:shell_out).and_return(@status)
734
+ expect(@provider).to receive(:shell_out).twice.with(
733
735
  "yum -d0 -e0 -y install emacs-1.0",
734
736
  {:timeout => Chef::Config[:yum_timeout]}
735
737
  )
@@ -2061,4 +2063,4 @@ describe "Chef::Provider::Package::Yum - Multi" do
2061
2063
  @provider.install_package(["cups", "vim"], ["1.2.4-11.19.el5", '1.0'])
2062
2064
  end
2063
2065
  end
2064
- end
2066
+ end
@@ -39,16 +39,33 @@ describe "Chef::Application::WindowsService", :windows_only do
39
39
  allow(instance).to receive(:state).and_return(4)
40
40
  instance.service_main
41
41
  end
42
- it "passes config params to new process" do
43
- Chef::Config.merge!({:log_location => tempfile.path, :config_file => "test_config_file", :log_level => :info})
44
- expect(instance).to receive(:configure_chef).twice
45
- instance.service_init
46
- allow(instance).to receive(:running?).and_return(true, false)
47
- allow(instance.instance_variable_get(:@service_signal)).to receive(:wait)
48
- allow(instance).to receive(:state).and_return(4)
49
- expect(instance).to receive(:run_chef_client).and_call_original
50
- expect(instance).to receive(:shell_out).with("chef-client --no-fork -c test_config_file -L #{tempfile.path}").and_return(shell_out_result)
51
- instance.service_main
52
- tempfile.unlink
42
+
43
+ context 'when running chef-client' do
44
+ it "passes config params to new process with a default timeout of 2 hours (7200 seconds)" do
45
+ Chef::Config.merge!({:log_location => tempfile.path, :config_file => "test_config_file", :log_level => :info})
46
+ expect(instance).to receive(:configure_chef).twice
47
+ instance.service_init
48
+ allow(instance).to receive(:running?).and_return(true, false)
49
+ allow(instance.instance_variable_get(:@service_signal)).to receive(:wait)
50
+ allow(instance).to receive(:state).and_return(4)
51
+ expect(instance).to receive(:run_chef_client).and_call_original
52
+ expect(instance).to receive(:shell_out).with("chef-client --no-fork -c test_config_file -L #{tempfile.path}", {:timeout => 7200}).and_return(shell_out_result)
53
+ instance.service_main
54
+ tempfile.unlink
55
+ end
56
+
57
+ it "passes config params to new process with a the timeout specified in the config" do
58
+ Chef::Config.merge!({:log_location => tempfile.path, :config_file => "test_config_file", :log_level => :info})
59
+ Chef::Config[:windows_service][:watchdog_timeout] = 10
60
+ expect(instance).to receive(:configure_chef).twice
61
+ instance.service_init
62
+ allow(instance).to receive(:running?).and_return(true, false)
63
+ allow(instance.instance_variable_get(:@service_signal)).to receive(:wait)
64
+ allow(instance).to receive(:state).and_return(4)
65
+ expect(instance).to receive(:run_chef_client).and_call_original
66
+ expect(instance).to receive(:shell_out).with("chef-client --no-fork -c test_config_file -L #{tempfile.path}", {:timeout => 10}).and_return(shell_out_result)
67
+ instance.service_main
68
+ tempfile.unlink
69
+ end
53
70
  end
54
71
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.1.0.rc.0
4
+ version: 12.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Jacob
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-21 00:00:00.000000000 Z
11
+ date: 2015-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-config
@@ -2012,9 +2012,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
2012
2012
  version: 2.0.0
2013
2013
  required_rubygems_version: !ruby/object:Gem::Requirement
2014
2014
  requirements:
2015
- - - ">"
2015
+ - - ">="
2016
2016
  - !ruby/object:Gem::Version
2017
- version: 1.3.1
2017
+ version: '0'
2018
2018
  requirements: []
2019
2019
  rubyforge_project:
2020
2020
  rubygems_version: 2.4.4