community-zero 1.1.1 → 2.0.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: 425f091c947d1971901f380570e80637eefce300
4
- data.tar.gz: ab73f8d4f6a36a647353824ad320cd64a8128389
3
+ metadata.gz: 1435c42a58a4f5e005069db3566ebbfcd0af71b7
4
+ data.tar.gz: 2a5bfe36688097ef44601460e0ba82f6c7f7a810
5
5
  SHA512:
6
- metadata.gz: 78643707d0c64818683db9508b6e32d4679fea4c44c127b0cdee6a1e32bbf2e64b722f3f00d6af6442defc6a0d1fd4847af18b099f6092290cebbb6d66cfb2a2
7
- data.tar.gz: 945958daab56f3ca57e5afe17408371ac977ebe9edb39d3a1deb52971488339e267794bdaff9d364fd9d5cb61c4083b02d7d3c5dae9dcea76419b6260eba3c12
6
+ metadata.gz: 0b9baa73abd7875e2faff8ab2b81f198a3d3cc16c06d1c168cdc4dce84fb1d18707eae7f7a9b63ec9db63da770ecbdb1f1c45906a56769199eb55ad016b676ce
7
+ data.tar.gz: 1abbdab93b9fc8025d1dbbc33803d8baf0e9ede3ddf56f7dbf5c96c903af12baaa0633ab211396f63ba05ae6ae5f9899a8a3e88aa6f8a7299d2cff4bf3cd4073
data/README.md CHANGED
@@ -38,41 +38,17 @@ Usage
38
38
  The primary use is an in-memory fake Community site for testing. Here's a simple example:
39
39
 
40
40
  ```ruby
41
- require 'community_zero/server'
42
- server = CommunityZero::Server.new(port: 3000)
43
- server.start
41
+ require 'community_zero/rspec'
44
42
  ```
45
43
 
46
- This will create a server instance in the foreground. To stop the server:
47
-
48
- ```ruby
49
- server.stop
50
- ```
51
-
52
- This is great for debugging and logging requests, but you'll probably want
53
- to run this in the background so you have full control of your thread.
54
-
55
- To run Community Zero in the background, simply issue the `start_background` command:
56
-
57
- ```ruby
58
- require 'community_zero/server'
59
- server = CommunityZero::Server.new(port: 4000)
60
- server.start_background
61
- ```
62
-
63
- You can stop the server the same way:
64
-
65
- ```ruby
66
- server.stop
67
- ```
44
+ This will create a server in the background and give you some nice hooks for accessing the data store to create and manipulate objects for testing. The best example tests are the cucumber tests packaged in the `features` directory.
68
45
 
69
46
  Valid Options
70
47
  -------------
71
48
  You may currently pass the following options to the initializer:
72
49
 
73
- - `host` - the host to run on (Default: 0.0.0.0)
74
- - `port` - the port to run on (Default: 3000)
75
- - `debug` - run in debug mode to see all requests and responses (Default: false)
50
+ - `host` - the host to run on
51
+ - `port` - the port to run on
76
52
 
77
53
  CLI (Command Line)
78
54
  ------------------
@@ -87,8 +63,7 @@ Run `community-zero --help` to see a list of the supported flags and options:
87
63
  ```text
88
64
  Usage: community-zero [ARGS]
89
65
  -H, --host HOST Host to bind to (default: 0.0.0.0)
90
- -p, --port PORT Port to listen on
91
- -d, --debug Show requests and debugging output
66
+ -p, --port PORT Port to listen on (default: 3389)
92
67
  -h, --help Show this message
93
68
  --version Show version
94
69
  ```
data/Rakefile CHANGED
@@ -1,18 +1,16 @@
1
- #
2
- # Copyright 2013, Seth Vargo <sethvargo@gmail.com>
3
- # Copyright 2013, Opscode, Inc.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
1
  require 'bundler/gem_tasks'
2
+
3
+ require 'cucumber/rake/task'
4
+ Cucumber::Rake::Task.new(:acceptance) do |t|
5
+ t.cucumber_opts = [].tap do |a|
6
+ a.push('--color')
7
+ a.push('--format progress')
8
+ a.push('--strict')
9
+ a.push('--tags ~@wip')
10
+ end.join(' ')
11
+ end
12
+
13
+ desc 'Run all tests'
14
+ task :test => [:acceptance]
15
+
16
+ task :default => [:test]
data/bin/community-zero CHANGED
@@ -1,25 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
- #
3
- # Copyright 2013, Seth Vargo <sethvargo@gmail.com>
4
- # Copyright 2013, Opscode, Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
20
-
21
- require 'community_zero/version'
22
- require 'community_zero/server'
2
+
3
+ # Load paths are hard
4
+ $:.unshift(File.dirname(__FILE__) + '../lib')
5
+
6
+ # Trap interrupts to quit cleanly.
7
+ Signal.trap('INT') { exit 1 }
8
+
9
+ require 'community_zero'
23
10
  require 'optparse'
24
11
 
25
12
  options = { :publish => true }
@@ -27,22 +14,14 @@ options = { :publish => true }
27
14
  OptionParser.new do |opts|
28
15
  opts.banner = 'Usage: community-zero [ARGS]'
29
16
 
30
- opts.on('-H', '--host HOST', 'Host to bind to (default: 0.0.0.0)') do |value|
17
+ opts.on('-H', '--host HOST', 'Host to bind to (default: 127.0.0.1)') do |value|
31
18
  options[:host] = value
32
19
  end
33
20
 
34
- opts.on('-p', '--port PORT', Integer, 'Port to listen on (default: 3000)') do |value|
21
+ opts.on('-p', '--port PORT', Integer, 'Port to listen on (default: 3389)') do |value|
35
22
  options[:port] = value
36
23
  end
37
24
 
38
- opts.on('-s', '--socket SOCK', String, 'Unix socket path to listen on') do |value|
39
- options[:socket] = value
40
- end
41
-
42
- opts.on('-l', '--log-level LEVEL', 'Set the output log level') do |value|
43
- options[:log_level] = value
44
- end
45
-
46
25
  opts.on_tail('-h', '--help', 'Show this message') do
47
26
  puts opts
48
27
  exit
@@ -16,13 +16,12 @@
16
16
  #
17
17
 
18
18
  require 'json'
19
- require 'puma'
20
19
  require 'timeout'
21
20
 
22
21
  module CommunityZero
23
22
  require_relative 'community_zero/chef'
24
23
  require_relative 'community_zero/endpoint'
25
- require_relative 'community_zero/error'
24
+ require_relative 'community_zero/errors'
26
25
  require_relative 'community_zero/object'
27
26
  require_relative 'community_zero/request'
28
27
  require_relative 'community_zero/router'
@@ -38,6 +38,13 @@ module CommunityZero
38
38
  @server = server
39
39
  end
40
40
 
41
+ # The data store for these endpoints
42
+ #
43
+ # @return [CommunityZero::Store]
44
+ def store
45
+ server.store
46
+ end
47
+
41
48
  # Generate the URL for the given cookbook.
42
49
  #
43
50
  # @param [CommunityZero::Cookbook] cookbook
@@ -79,15 +86,6 @@ module CommunityZero
79
86
  ]
80
87
  end
81
88
 
82
- # Must accept JSON
83
- unless request.env['HTTP_ACCEPT'].to_s.split(';').include?('application/json')
84
- return [
85
- 406,
86
- { 'Content-Type' => 'text/plain' },
87
- 'Must accept application/json'
88
- ]
89
- end
90
-
91
89
  begin
92
90
  send(m, request)
93
91
  rescue RestError => e
@@ -23,9 +23,9 @@ module CommunityZero
23
23
  # GET /cookbooks/:name
24
24
  def get(request)
25
25
  name = request.path.last
26
- cookbook = Store.find(name)
26
+ cookbook = store.find(name)
27
27
 
28
- if cookbook = Store.find(name)
28
+ if cookbook = store.find(name)
29
29
  respond({
30
30
  'name' => cookbook.name,
31
31
  'maintainer' => cookbook.maintainer,
@@ -33,8 +33,8 @@ module CommunityZero
33
33
  'external_url' => cookbook.external_url,
34
34
  'description' => cookbook.description,
35
35
  'average_rating' => cookbook.average_rating,
36
- 'versions' => cookbook.versions.map { |i| version_url_for(cookbook, i) },
37
- 'latest_version' => version_url_for(cookbook, cookbook.latest_version),
36
+ 'versions' => store.versions(cookbook).map { |i| version_url_for(cookbook, i) },
37
+ 'latest_version' => version_url_for(cookbook, store.latest_version(cookbook)),
38
38
  'created_at' => cookbook.created_at,
39
39
  'updated_at' => cookbook.upadated_at,
40
40
  })
@@ -52,8 +52,8 @@ module CommunityZero
52
52
  def delete(request)
53
53
  name = request.path.last
54
54
 
55
- if cookbook = Store.find(name)
56
- cookbook.destroy
55
+ if cookbook = store.find(name)
56
+ store.remove(cookbook)
57
57
  respond({})
58
58
  else
59
59
  respond(404,
@@ -23,7 +23,7 @@ module CommunityZero
23
23
  def get(request)
24
24
  name, version = request.path[1], request.path[-1].gsub('_', '.')
25
25
 
26
- unless cookbook = Store.find(name)
26
+ unless cookbook = store.find(name)
27
27
  return respond(404,
28
28
  {
29
29
  'error_code' => 'NOT_FOUND',
@@ -32,8 +32,8 @@ module CommunityZero
32
32
  )
33
33
  end
34
34
 
35
- version = cookbook.latest_version if version == 'latest'
36
- cookbook = Store.find(name, version)
35
+ version = store.latest_version(cookbook) if version == 'latest'
36
+ cookbook = store.find(name, version)
37
37
  respond(response_hash_for(cookbook))
38
38
  end
39
39
 
@@ -27,7 +27,7 @@ module CommunityZero
27
27
  def get(request)
28
28
  start = Integer(request.query_params['start'] || 0)
29
29
  items = Integer(request.query_params['items'] || 10)
30
- cookbooks = Store.cookbooks[start...items] || []
30
+ cookbooks = store.cookbooks[start...items] || []
31
31
 
32
32
  respond({
33
33
  'items' => cookbooks.collect { |cookbook|
@@ -38,7 +38,7 @@ module CommunityZero
38
38
  'cookbook_maintainer' => cookbook.maintainer
39
39
  }
40
40
  },
41
- 'total' => Store.size,
41
+ 'total' => store.size,
42
42
  'start' => start.to_i,
43
43
  })
44
44
  end
@@ -51,7 +51,7 @@ module CommunityZero
51
51
 
52
52
  metadata = Metadata.new(read_tarball(tarball))
53
53
 
54
- if Store.find(metadata.name, metadata.version)
54
+ if store.find(metadata.name, metadata.version)
55
55
  respond(401,
56
56
  {
57
57
  'error_code' => 'ALREADY_EXISTS',
@@ -69,13 +69,17 @@ module CommunityZero
69
69
  # @param [CommunityZero::Metadata] metadata
70
70
  # the metadata to create the cookbook from
71
71
  def create_cookbook(metadata, overrides = {})
72
- Cookbook.create({
73
- :name => metadata.name,
74
- :category => nil,
75
- :maintainer => metadata.maintainer,
72
+ cookbook = Cookbook.new({
73
+ :name => metadata.name,
74
+ :category => nil,
75
+ :maintainer => metadata.maintainer,
76
76
  :description => metadata.description,
77
- :version => metadata.version
77
+ :version => metadata.version
78
78
  }.merge(overrides))
79
+
80
+ store.add(cookbook)
81
+
82
+ cookbook
79
83
  end
80
84
 
81
85
  # Parse the metadata from the tarball.
@@ -25,7 +25,7 @@ module CommunityZero
25
25
  q = request.query_params['q'].to_s
26
26
  start = Integer(request.query_params['start'] || 0)
27
27
  items = Integer(request.query_params['items'] || 10)
28
- cookbooks = Store.search(q)[start...items] || []
28
+ cookbooks = store.search(q)[start...items] || []
29
29
 
30
30
  respond({
31
31
  'items' => cookbooks.collect { |cookbook|
@@ -16,9 +16,11 @@
16
16
  #
17
17
 
18
18
  module CommunityZero
19
- # A general error for failed communicate with a REST API.
19
+ # The base class for errors.
20
20
  #
21
21
  # @author Seth Vargo <sethvargo@gmail.com>
22
+ class Error < StandardError; end
23
+
22
24
  class RestError < Error
23
25
  attr_reader :response_code, :error
24
26
 
@@ -20,25 +20,6 @@ module CommunityZero
20
20
  #
21
21
  # @author Seth Vargo <sethvargo@gmail.com>
22
22
  class Cookbook
23
- class << self
24
- # Create a cookbook object from a hash.
25
- #
26
- # @param [Hash] hash
27
- # the hash from which to create the cookbook
28
- def from_hash(hash)
29
- new(hash)
30
- end
31
-
32
- # Create a cookbook object from a hash and commit that object
33
- # to memory.
34
- #
35
- # @param [Hash] hash
36
- # the hash from which to create the cookbook
37
- def create(hash)
38
- new(hash).save
39
- end
40
- end
41
-
42
23
  # Create a new cookbook from the given hash.
43
24
  #
44
25
  # @param [Hash] hash
@@ -48,32 +29,6 @@ module CommunityZero
48
29
  hash.each { |k,v| instance_variable_set(:"@#{k}",v) }
49
30
  end
50
31
 
51
- # Save this cookbook in the store.
52
- def save
53
- Store.update(self)
54
- end
55
-
56
- # Delete this cookbook from the store.
57
- def destroy
58
- Store.remove(self)
59
- end
60
-
61
- # A list of all other versions of this cookbook.
62
- #
63
- # @return [Array<String>]
64
- # the other verions
65
- def versions
66
- @versions ||= Store.versions(self)
67
- end
68
-
69
- # The latest (newest) version.
70
- #
71
- # @return [String]
72
- # the newest version
73
- def latest_version
74
- @latest_version ||= versions.last
75
- end
76
-
77
32
  # Dump this cookbook to a hash.
78
33
  #
79
34
  # @return [Hash]
@@ -20,8 +20,6 @@ module CommunityZero
20
20
  #
21
21
  # @author Seth Vargo <sethvargo@gmail.com>
22
22
  class Router
23
- require_relative 'endpoint'
24
-
25
23
  attr_reader :server, :routes
26
24
 
27
25
  def initialize(server, *routes)
@@ -0,0 +1,59 @@
1
+ require 'net/http'
2
+ require 'singleton'
3
+
4
+ require 'community_zero/server'
5
+
6
+ module CommunityZero
7
+ class RSpec
8
+ undef :to_s, :inspect
9
+
10
+ def self.method_missing(m, *args, &block)
11
+ instance.send(m, *args, &block)
12
+ end
13
+
14
+ include Singleton
15
+
16
+ extend Forwardable
17
+ def_delegators :@server, :url, :running?, :stop, :reset!, :store, :to_s, :inspect
18
+
19
+ attr_reader :server
20
+
21
+ def initialize
22
+ @server = Server.new(port: 3389)
23
+ end
24
+
25
+ def start
26
+ unless @server.running?
27
+ @server.start_background
28
+ end
29
+
30
+ @server
31
+ end
32
+
33
+ def uri
34
+ @uri ||= URI.parse(url)
35
+ end
36
+
37
+ def get(path)
38
+ request = Net::HTTP::Get.new(path)
39
+ http.request(request)
40
+ end
41
+
42
+ def post(path, body)
43
+ request = Net::HTTP::Post.new(path)
44
+ request.set_form_data(body)
45
+ http.request(request)
46
+ end
47
+
48
+ def delete(path)
49
+ request = Net::HTTP::Delete.new(path)
50
+ http.request(request)
51
+ end
52
+
53
+ private
54
+
55
+ def http
56
+ @http ||= Net::HTTP.new(uri.host, uri.port)
57
+ end
58
+ end
59
+ end
@@ -15,23 +15,34 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
+ require 'open-uri'
19
+ require 'rack'
20
+ require 'webrick'
21
+
22
+ require 'community_zero'
23
+
18
24
  module CommunityZero
19
25
  # A single instance of the Community Server.
20
26
  #
21
27
  # @author Seth Vargo <sethvargo@gmail.com>
22
28
  class Server
23
- require_relative '../community_zero'
24
29
 
30
+ #
31
+ # Default options to populate
32
+ #
25
33
  DEFAULT_OPTIONS = {
26
- :host => '0.0.0.0',
27
- :port => 3000
34
+ :host => '127.0.0.1',
35
+ :port => 3389,
28
36
  }.freeze
29
37
 
38
+ #
30
39
  # The list of options passed to the server.
31
40
  #
32
41
  # @return [Hash]
42
+ #
33
43
  attr_reader :options
34
44
 
45
+ #
35
46
  # Create a new Community site server.
36
47
  #
37
48
  # @param [Hash] options
@@ -40,145 +51,168 @@ module CommunityZero
40
51
  # @option options [String] :host
41
52
  # the host to listen on (default is 0.0.0.0)
42
53
  # @option options [String, Fixnum] :port
43
- # the port to listen on (default is 3000)
54
+ # the port to listen on (default is 3389)
55
+ #
44
56
  def initialize(options = {})
45
57
  @options = DEFAULT_OPTIONS.merge(options)
58
+ @options[:host] = "[#{@options[:host]}]" if @options[:host].include?(':')
59
+ @options.freeze
46
60
  end
47
61
 
48
- # Start the community server.
49
62
  #
50
- # @return [Thread]
51
- # the thread the server is running in
52
- def start
53
- if options[:publish]
54
- puts [
55
- ">> Starting Community Zero (v#{CommunityZero::VERSION})...",
56
- ">> Puma (v#{Puma::Const::PUMA_VERSION}) is listening at #{url}",
57
- ">> Press CTRL+C to stop",
58
- ].join("\n")
63
+ # The data store (by default, this is just a regular store)
64
+ #
65
+ def store
66
+ @store ||= Store.new
67
+ end
68
+
69
+ #
70
+ # The URL for this Community Zero server.
71
+ #
72
+ # @return [String]
73
+ #
74
+ def url
75
+ "http://#{@options[:host]}:#{@options[:port]}"
76
+ end
77
+
78
+ #
79
+ # Start a Community Zero server in the current thread. You can stop this
80
+ # server by canceling the current thread.
81
+ #
82
+ # @param [Boolean] publish
83
+ # publish the server information to STDOUT
84
+ #
85
+ # @return [nil]
86
+ # this method will block the main thread until interrupted
87
+ #
88
+ def start(publish = true)
89
+ if publish
90
+ puts <<-EOH.gsub(/^ {10}/, '')
91
+ >> Starting Community Zero (v#{CommunityZero::VERSION})...
92
+ >> WEBrick (v#{WEBrick::VERSION}) on Rack (v#{Rack.release}) is listening at #{url}
93
+ >> Press CTRL+C to stop
94
+
95
+ EOH
59
96
  end
60
97
 
61
- begin
62
- thread = server.run.join
63
- rescue Object, Interrupt
64
- puts "\n>> Stopping Puma..." if options[:publish]
65
- server.stop(true) if running?
98
+ thread = start_background
99
+
100
+ %w[INT TERM].each do |signal|
101
+ Signal.trap(signal) do
102
+ puts "\n>> Stopping Community Zero..."
103
+ @server.shutdown
104
+ end
66
105
  end
106
+
107
+ # Move the background process to the main thread
108
+ thread.join
67
109
  end
68
110
 
69
- # Start the community server as a background process in a Thread.
70
- # This is useful when using CommunityZero as a testing server with RSpec.
111
+ #
112
+ # Start a Community Zero server in a forked process. This method returns
113
+ # the PID to the forked process.
71
114
  #
72
115
  # @param [Fixnum] wait
73
116
  # the number of seconds to wait for the server to start
74
117
  #
75
118
  # @return [Thread]
76
- # the thread the server is running in
119
+ # the thread the background process is running in
120
+ #
77
121
  def start_background(wait = 5)
78
- @thread = Thread.new do
79
- begin
80
- start
81
- rescue
82
- @server_error = $!
83
- $stderr.puts "#{$!.message}\n#{$!.backtrace.join("\n")}"
84
- end
85
- end
86
-
87
- Timeout::timeout(wait) do
88
- sleep(0.01) until running? || @server_error
89
- raise @server_error if @server_error
90
- end
91
-
122
+ @server = WEBrick::HTTPServer.new(
123
+ :BindAddress => @options[:host],
124
+ :Port => @options[:port],
125
+ :AccessLog => [],
126
+ :Logger => WEBrick::Log.new(StringIO.new, 7)
127
+ )
128
+ @server.mount('/', Rack::Handler::WEBrick, app)
129
+
130
+ @thread = Thread.new { @server.start }
131
+ @thread.abort_on_exception = true
92
132
  @thread
93
133
  end
94
134
 
95
- # Determine if the server is currently running.
135
+ #
136
+ # Boolean method to determine if the server is currently ready to accept
137
+ # requests. This method will attempt to make an HTTP request against the
138
+ # server. If this method returns true, you are safe to make a request.
96
139
  #
97
140
  # @return [Boolean]
98
- # true if the server is currently running, false otherwise
141
+ # true if the server is accepting requests, false otherwise
142
+ #
99
143
  def running?
100
- # NOTE: we intentionally use the instance variable here, otherwise
101
- # there are race conditions because calling {server} would actually
102
- # start the server unintentionally.
103
- !!(@server && @server.running)
144
+ if @server.nil? || @server.status != :Running
145
+ return false
146
+ end
147
+
148
+ uri = URI.join(url, 'cookbooks')
149
+ headers = { 'Accept' => 'application/json' }
150
+
151
+ Timeout.timeout(0.1) { !open(uri, headers).nil? }
152
+ rescue SocketError, Errno::ECONNREFUSED, Timeout::Error
153
+ false
104
154
  end
105
155
 
106
- # Stop the running server.
156
+ #
157
+ # Gracefully stop the Community Zero server.
107
158
  #
108
159
  # @param [Fixnum] wait
109
- # the number of seconds to wait for the server to stop
160
+ # the number of seconds to wait before raising force-terminating the
161
+ # server
162
+ #
110
163
  def stop(wait = 5)
164
+ Timeout.timeout(wait) do
165
+ @server.shutdown
166
+ @thread.join(wait) if @thread
167
+ end
168
+ rescue Timeout::Error
111
169
  if @thread
112
- @thread.join(wait)
113
- else
114
- server.stop(true)
170
+ $stderr.puts("Community Zero did not stop within #{wait} seconds! Killing...")
171
+ @thread.kill
115
172
  end
116
- rescue
117
- $stderr.puts "Server did not stop within #{wait} seconds. Killing..."
118
- @thread.kill if @thread
119
173
  ensure
174
+ @server = nil
120
175
  @thread = nil
121
176
  end
122
177
 
123
178
  # Clear out any existing entires and reset the server's contents to a
124
179
  # clean state.
125
180
  def reset!
126
- CommunityZero::Store.destroy_all
181
+ store.destroy_all
127
182
  end
128
183
 
129
- # Returns the URL the server is listening on.
130
- #
131
- # @example
132
- # server = CommunityZero.new
133
- # server.url #=> http://0.0.0.0:3000
134
- #
135
- # @example
136
- # server = CommunityZero.new(host: 'example.com', port: 80)
137
- # server.url #=> http://example.com:80
138
- def url
139
- @url ||= "http://#{options[:host]}:#{options[:port]}"
184
+ def to_s
185
+ "#<#{self.class} #{url}>"
140
186
  end
141
187
 
142
- private
143
- # The Community Zero server.
144
- #
145
- # @return [Puma::Server]
146
- # the actual server object
147
- def server
148
- return @server if @server
149
-
150
- @server = Puma::Server.new(app, Puma::Events.new(STDERR, STDOUT))
151
-
152
- if options[:socket]
153
- @server.add_unix_listener(options[:socket])
154
- else
155
- @server.add_tcp_listener(options[:host], options[:port])
156
- end
157
-
158
- @server
159
- end
188
+ def inspect
189
+ "#<#{self.class} @url=#{url.inspect}>"
190
+ end
160
191
 
161
- # The actual application the server will respond to.
162
- #
163
- # @return []
164
- def app
165
- lambda do |env|
166
- request = Request.new(env)
167
- response = router.call(request)
192
+ private
168
193
 
169
- response[-1] = Array(response[-1])
170
- response
171
- end
172
- end
194
+ #
195
+ # The actual application the server will respond to.
196
+ #
197
+ # @return [RackApp]
198
+ #
199
+ def app
200
+ lambda do |env|
201
+ request = Request.new(env)
202
+ response = router.call(request)
173
203
 
174
- def router
175
- @router ||= Router.new(self,
176
- ['/search', SearchEndpoint],
177
- ['/cookbooks', CookbooksEndpoint],
178
- ['/cookbooks/:name', CookbookEndpoint],
179
- ['/cookbooks/:name/versions/:version', CookbookVersionsVersionEndpoint],
180
- )
204
+ response[-1] = Array(response[-1])
205
+ response
181
206
  end
207
+ end
182
208
 
209
+ def router
210
+ @router ||= Router.new(self,
211
+ ['/search', SearchEndpoint],
212
+ ['/cookbooks', CookbooksEndpoint],
213
+ ['/cookbooks/:name', CookbookEndpoint],
214
+ ['/cookbooks/:name/versions/:version', CookbookVersionsVersionEndpoint],
215
+ )
216
+ end
183
217
  end
184
218
  end
@@ -17,9 +17,7 @@
17
17
 
18
18
  module CommunityZero
19
19
  # @author Seth Vargo <sethvargo@gmail.com>
20
- module Store
21
- extend self
22
-
20
+ class Store
23
21
  # The number of cookbooks in the store.
24
22
  #
25
23
  # @return [Fixnum]
@@ -123,6 +121,14 @@ module CommunityZero
123
121
  (_cookbooks[name] && _cookbooks[name].keys.sort) || []
124
122
  end
125
123
 
124
+ # Return the latest version of the given cookbook.
125
+ #
126
+ # @param [String, CommunityZero::Cookbook] name
127
+ # the cookbook or name of the cookbook to get versions for
128
+ def latest_version(name)
129
+ versions(name).last
130
+ end
131
+
126
132
  private
127
133
  # All the cookbooks in the store.
128
134
  #
@@ -16,5 +16,5 @@
16
16
  #
17
17
 
18
18
  module CommunityZero
19
- VERSION = '1.1.1'
19
+ VERSION = '2.0.0'
20
20
  end
metadata CHANGED
@@ -1,85 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: community-zero
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seth Vargo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-27 00:00:00.000000000 Z
11
+ date: 2013-12-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: puma
14
+ name: cucumber
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
20
- type: :runtime
19
+ version: '0'
20
+ type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
- version: '2.0'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: cucumber
28
+ name: json_spec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - '>='
32
32
  - !ruby/object:Gem::Version
33
- version: '1.3'
33
+ version: '0'
34
34
  type: :development
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.3'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: json_spec
42
+ name: rack
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - '>='
46
46
  - !ruby/object:Gem::Version
47
- version: '1.1'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - '>='
53
53
  - !ruby/object:Gem::Version
54
- version: '1.1'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rack-test
56
+ name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - '>='
60
60
  - !ruby/object:Gem::Version
61
- version: '0.6'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - '>='
67
67
  - !ruby/object:Gem::Version
68
- version: '0.6'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - '>='
74
74
  - !ruby/object:Gem::Version
75
- version: '2.13'
75
+ version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - '>='
81
81
  - !ruby/object:Gem::Version
82
- version: '2.13'
82
+ version: '0'
83
83
  description: Self-contained, easy-setup, fast-start in-memory Chef Community Site
84
84
  for testing.
85
85
  email: sethvargo@gmail.com
@@ -91,27 +91,28 @@ files:
91
91
  - LICENSE
92
92
  - README.md
93
93
  - Rakefile
94
- - lib/community_zero/chef/metadata.rb
94
+ - bin/community-zero
95
+ - lib/community_zero.rb
95
96
  - lib/community_zero/chef.rb
97
+ - lib/community_zero/chef/metadata.rb
96
98
  - lib/community_zero/endpoint.rb
97
99
  - lib/community_zero/endpoints/cookbook_endpoint.rb
98
100
  - lib/community_zero/endpoints/cookbook_versions_version_endpoint.rb
99
101
  - lib/community_zero/endpoints/cookbooks_endpoint.rb
100
102
  - lib/community_zero/endpoints/not_found_endpoint.rb
101
103
  - lib/community_zero/endpoints/search_endpoint.rb
102
- - lib/community_zero/error.rb
103
- - lib/community_zero/errors/rest_error.rb
104
+ - lib/community_zero/errors.rb
104
105
  - lib/community_zero/object.rb
105
106
  - lib/community_zero/objects/cookbook.rb
106
107
  - lib/community_zero/request.rb
107
108
  - lib/community_zero/router.rb
109
+ - lib/community_zero/rspec.rb
108
110
  - lib/community_zero/server.rb
109
111
  - lib/community_zero/store.rb
110
112
  - lib/community_zero/version.rb
111
- - lib/community_zero.rb
112
- - bin/community-zero
113
113
  homepage: https://github.com/sethvargo/community-zero
114
- licenses: []
114
+ licenses:
115
+ - Apache 2.0
115
116
  metadata: {}
116
117
  post_install_message:
117
118
  rdoc_options: []
@@ -129,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
130
  version: '0'
130
131
  requirements: []
131
132
  rubyforge_project:
132
- rubygems_version: 2.0.3
133
+ rubygems_version: 2.2.0
133
134
  signing_key:
134
135
  specification_version: 4
135
136
  summary: Self-contained, easy-setup, fast-start in-memory Chef Community Site for
@@ -1,25 +0,0 @@
1
- #
2
- # Copyright 2013, Seth Vargo <sethvargo@gmail.com>
3
- # Copyright 2013, Opscode, Inc.
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
- #
17
-
18
- module CommunityZero
19
- # The base class for errors.
20
- #
21
- # @author Seth Vargo <sethvargo@gmail.com>
22
- class Error < StandardError; end
23
-
24
- require_relative 'errors/rest_error'
25
- end