dockerspec 0.1.0 → 0.2.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
  SHA1:
3
- metadata.gz: a39571e9f5eb647131860a8950bce41592c9887c
4
- data.tar.gz: f61ee33d8d382ec51859aa15ea296cbf64acaf64
3
+ metadata.gz: 7694cecd69e554a6954f6b9db00f3fe2b768f15c
4
+ data.tar.gz: 1a2a4415286128639366c18f8ab4f6d303d416c0
5
5
  SHA512:
6
- metadata.gz: 9a4e57c561111f07730b533ff1e43514c19a6f6858be23acd1819203ad035aa4a425fba88a6dc718d7fde7b046055a6fd30afc1949b8a99f93c6414175eefb50
7
- data.tar.gz: 9c40fd10e8cef3e785bbcc83cde4de774ae1dcef53d8d029ce6a1e507c7954641ee868d81788378ecfa34ad6afbbf03da871ddb78107a45635dd72cb1cefa897
6
+ metadata.gz: 524a40d59079d2532db4817df108b08e78d964a1a4ec24f046a2f20c398d9121952fa1f9fd43211a02dfa2211e9bd45fb49b10c6c3dad3f693c5432e78cabe77
7
+ data.tar.gz: 1e60d573d88980f9c018dbed60012ee51e4fdfba50a181ec3a7389d1aa655038f67556ea95421089b4f1d2a1e1b933d75720c20d12f51654edca4afa2c42d982
@@ -2,6 +2,25 @@
2
2
 
3
3
  This file is used to list changes made in each version of `dockerspec` Ruby Gem.
4
4
 
5
+ ## 0.2.0 (2015-12-11)
6
+
7
+ ### New Features on 0.2.0
8
+
9
+ * Set some opinionated RSpec configurations.
10
+ * Print Docker errors in a more readable format.
11
+
12
+ ### Fixes on 0.2.0
13
+
14
+ * Fix *undefined method* error in the outermost examples.
15
+
16
+ ### Documentation Changes on 0.2.0
17
+
18
+ * Add examples for `#have_cmd` using string format.
19
+ * README:
20
+ * Improve Ruby documentation.
21
+ * Change gem badge to point to RubyGems.
22
+ * Add Real-world examples section.
23
+
5
24
  ## 0.1.0 (2015-12-09)
6
25
 
7
26
  * Initial release of `dockerspec`.
data/README.md CHANGED
@@ -3,12 +3,12 @@
3
3
  [![GitHub](http://img.shields.io/badge/github-zuazo/dockerspec-blue.svg?style=flat)](https://github.com/zuazo/dockerspec)
4
4
  [![License](https://img.shields.io/github/license/zuazo/dockerspec.svg?style=flat)](#license-and-author)
5
5
 
6
- [![Gem Version](https://badge.fury.io/rb/dockerspec.svg)](http://github.com/zuazo/dockerspec/releases)
6
+ [![Gem Version](https://badge.fury.io/rb/dockerspec.svg)](https://rubygems.org/gems/dockerspec)
7
7
  [![Dependency Status](http://img.shields.io/gemnasium/zuazo/dockerspec.svg?style=flat)](https://gemnasium.com/zuazo/dockerspec)
8
8
  [![Code Climate](http://img.shields.io/codeclimate/github/zuazo/dockerspec.svg?style=flat)](https://codeclimate.com/github/zuazo/dockerspec)
9
- [![Travis CI Build Status](http://img.shields.io/travis/zuazo/dockerspec/0.1.0.svg?style=flat)](https://travis-ci.org/zuazo/dockerspec)
9
+ [![Travis CI Build Status](http://img.shields.io/travis/zuazo/dockerspec/0.2.0.svg?style=flat)](https://travis-ci.org/zuazo/dockerspec)
10
10
  [![Circle CI Build Status](https://circleci.com/gh/zuazo/dockerspec/tree/master.svg?style=shield)](https://circleci.com/gh/zuazo/dockerspec/tree/master)
11
- [![Coverage Status](http://img.shields.io/coveralls/zuazo/dockerspec/0.1.0.svg?style=flat)](https://coveralls.io/r/zuazo/dockerspec?branch=0.1.0)
11
+ [![Coverage Status](http://img.shields.io/coveralls/zuazo/dockerspec/0.2.0.svg?style=flat)](https://coveralls.io/r/zuazo/dockerspec?branch=0.2.0)
12
12
  [![Inline docs](http://inch-ci.org/github/zuazo/dockerspec.svg?branch=master&style=flat)](http://inch-ci.org/github/zuazo/dockerspec)
13
13
 
14
14
  ## Description
@@ -20,7 +20,7 @@ This gem is designed to work out of the box on [Travis CI](https://travis-ci.org
20
20
  ## Requirements
21
21
 
22
22
  * Ruby `2` or higher.
23
- * Recommended Docker `1.7.0` or higher.
23
+ * Recommended Docker `1.7` or higher.
24
24
 
25
25
  ## Installation
26
26
 
@@ -33,9 +33,7 @@ $ gem install dockerspec
33
33
  Or you can add this line to the *Gemfile* of your application:
34
34
 
35
35
  ```ruby
36
- # Gemfile
37
-
38
- gem 'dockerspec', '~> 0.1.0'
36
+ gem 'dockerspec', '~> 0.2.0'
39
37
  ```
40
38
 
41
39
  And then execute:
@@ -86,23 +84,31 @@ end
86
84
 
87
85
  See the documentation above for more examples.
88
86
 
89
- ### Prepare the Ruby Environment
87
+ ### Real-world Examples
88
+
89
+ * [`alpine-tor`](https://github.com/zuazo/alpine-tor-docker) image ([*spec/*](https://github.com/zuazo/alpine-tor-docker/tree/master/spec), [*Gemfile*](https://github.com/zuazo/alpine-tor-docker/tree/master/Gemfile), [*.travis.yml*](https://github.com/zuazo/alpine-tor-docker/tree/master/.travis.yml)).
90
90
 
91
- 1. Create a **Gemfile**:
91
+ ### Prepare Your Ruby Environment
92
+
93
+ If you are new to Ruby, you can follow these steps:
94
+
95
+ #### 1. Create a **Gemfile**:
92
96
 
93
97
  ```ruby
94
98
  # Gemfile
95
99
 
96
- gem 'dockerspec', '~> 0.1.0'
100
+ source 'https://rubygems.org'
101
+
102
+ gem 'dockerspec', '~> 0.2.0'
97
103
  ```
98
104
 
99
- 2. Create the *spec/* directory:
105
+ #### 2. Create the *spec/* directory:
100
106
 
101
107
  ```
102
108
  $ mkdir spec
103
109
  ```
104
110
 
105
- 3. Add your tests to a file with the *spec/myapp_spec.rb* format:
111
+ #### 3. Add your tests to a file with the *spec/myapp_spec.rb* format:
106
112
 
107
113
  ```ruby
108
114
  # spec/myapp_spec.rb
@@ -120,13 +126,13 @@ describe 'My Dockerfile' do
120
126
  end
121
127
  ```
122
128
 
123
- 4. Install the gems:
129
+ #### 4. Install the gems:
124
130
 
125
131
  ```
126
132
  $ bundle
127
133
  ```
128
134
 
129
- 5. Run the tests:
135
+ #### 5. Run the tests:
130
136
 
131
137
  ```
132
138
  $ bundle exec rspec
@@ -19,3 +19,4 @@
19
19
 
20
20
  require 'dockerspec/version'
21
21
  require 'dockerspec/rspec_resources'
22
+ require 'dockerspec/rspec_configuration'
@@ -28,6 +28,7 @@ require 'dockerspec/builder/logger'
28
28
  require 'dockerspec/builder/image_gc'
29
29
  require 'dockerspec/helper/ci'
30
30
  require 'dockerspec/helper/multiple_sources_description'
31
+ require 'dockerspec/docker_exception_parser'
31
32
 
32
33
  module Dockerspec
33
34
  #
@@ -157,11 +158,7 @@ module Dockerspec
157
158
  #
158
159
  def source
159
160
  return @source unless @source.nil?
160
- %i(string template id path).any? do |from|
161
- next false unless @options.key?(from)
162
- @source = from # Used for description
163
- end
164
- @source
161
+ @source = %i(string template id path).find { |from| @options.key?(from) }
165
162
  end
166
163
 
167
164
  #
@@ -321,6 +318,8 @@ module Dockerspec
321
318
  def build_from_dir(dir)
322
319
  image(::Docker::Image.build_from_dir(dir, &build_block))
323
320
  add_respository_tag
321
+ rescue ::Docker::Error::DockerError => e
322
+ DockerExceptionParser.new(e)
324
323
  end
325
324
 
326
325
  #
@@ -356,11 +355,10 @@ module Dockerspec
356
355
  def build_from_template(file)
357
356
  context = @options[:context] || {}
358
357
 
359
- dir = File.dirname(file)
360
358
  template = IO.read(file)
361
359
  eruby = Erubis::Eruby.new(template)
362
360
  string = eruby.evaluate(context)
363
- build_from_string(string, dir)
361
+ build_from_string(string, File.dirname(file))
364
362
  end
365
363
 
366
364
  #
@@ -379,6 +377,8 @@ module Dockerspec
379
377
  add_respository_tag
380
378
  rescue ::Docker::Error::NotFoundError
381
379
  @image = ::Docker::Image.create('fromImage' => id)
380
+ rescue ::Docker::Error::DockerError => e
381
+ DockerExceptionParser.new(e)
382
382
  end
383
383
 
384
384
  #
@@ -127,6 +127,8 @@ module Dockerspec
127
127
  # @example RSpec Example Using *Have* Matchers
128
128
  # describe docker_build(path: '.') do
129
129
  # it { should have_cmd ['/usr/bin/supervisord'] }
130
+ # # Or in string format:
131
+ # it { should have_cmd '/usr/bin/supervisord' }
130
132
  # end
131
133
  #
132
134
  # @return [Array] The image command.
@@ -150,7 +152,7 @@ module Dockerspec
150
152
  # it { should have_label 'description' => 'My Container' }
151
153
  # end
152
154
  #
153
- # @example RSpec Example Checking Only the Existence of the label
155
+ # @example RSpec Example Checking Only the Existence of the Label
154
156
  # describe docker_build(path: '.') do
155
157
  # it { should have_label 'description' }
156
158
  # end
@@ -264,6 +266,8 @@ module Dockerspec
264
266
  # @example RSpec Example Using *Have* Matchers
265
267
  # describe docker_build(path: '.') do
266
268
  # it { should have_entrypoint ['/entrypoint.sh'] }
269
+ # # Or in string format:
270
+ # it { should have_entrypoint '/entrypoint.sh' }
267
271
  # end
268
272
  #
269
273
  # @return [Array] The image entrypoint.
@@ -0,0 +1,159 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Xabier de Zuazo (<xabier@zuazo.org>)
4
+ # Copyright:: Copyright (c) 2015 Xabier de Zuazo
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'json'
21
+ require 'dockerspec/exceptions'
22
+
23
+ module Dockerspec
24
+ #
25
+ # A class to parse `Docker::Error` exceptions.
26
+ #
27
+ class DockerExceptionParser
28
+ #
29
+ # Parses Docker exceptions.
30
+ #
31
+ # Raises the same exception if the format is unknown.
32
+ #
33
+ # @example
34
+ # rescue ::Docker::Error::DockerError => e
35
+ # DockerExceptionParser.new(e)
36
+ # end
37
+ #
38
+ # @param e [Exception] The exception object to parse.
39
+ #
40
+ # @raise [Dockerspec::DockerError] When the exception format is known.
41
+ # @raise [Exception] When the exception format is unknown.
42
+ #
43
+ # @api public
44
+ #
45
+ def initialize(e)
46
+ e_ary = parse_exception(e)
47
+ raise_docker_error_exception(e_ary)
48
+ fail e
49
+ end
50
+
51
+ protected
52
+
53
+ #
54
+ # Parses the exception JSON message.
55
+ #
56
+ # The message must be a list of JSON messages merged by a new line.
57
+ #
58
+ # A valid exception message example:
59
+ #
60
+ # ```
61
+ # {"stream":"Step 1 : FROM alpine:3.2\n"}
62
+ # {"stream":" ---\u003e d6ead20d5571\n"}
63
+ # {"stream":"Step 2 : RUN apk add --update wrong-package-name\n"}
64
+ # {"stream":" ---\u003e Running in 290a46fa8bf4\n"}
65
+ # {"stream":"fetch http://dl-4.alpinelinux.org/alpine/v3.2/main/...\n"}
66
+ # {"stream":"ERROR: unsatisfiable constraints:\n"}
67
+ # {"stream":" wrong-package-name (missing):\n required by: world...\n"}
68
+ # {"errorDetail":{"message":"The command ..."},"error":"The command ..."}
69
+ # ```
70
+ #
71
+ # @example
72
+ # self.parse_exception(e)
73
+ # #=> [{ "stream" => "Step 1 : FROM alpine:3.2\n" }, "errorDetail" => ...
74
+ #
75
+ # @param e [Exception] The exception object to parse.
76
+ #
77
+ # @return [Array<Hash>] The list of JSON messages parsed.
78
+ #
79
+ # @return
80
+ #
81
+ # @api private
82
+ #
83
+ def parse_exception(e)
84
+ msg = e.to_s
85
+ json = msg.to_s.sub(/^Couldn't find id: /, '').split("\n").map(&:chomp)
86
+ json.map { |str| JSON.parse(str) }
87
+ rescue JSON::ParserError
88
+ raise e
89
+ end
90
+
91
+ #
92
+ # Gets the error message from the *errorDetail* field.
93
+ #
94
+ # @param e_ary [Array<Hash>] The list of JSON messages already parsed.
95
+ #
96
+ # @return [String] The error message string.
97
+ #
98
+ # @api private
99
+ #
100
+ def parse_error_detail(e_ary)
101
+ e_detail = e_ary.select { |x| x.is_a?(Hash) && x.key?('errorDetail') }[0]
102
+ return nil unless e_detail.is_a?(Hash)
103
+ return e_detail['message'] if e_detail.key?('message')
104
+ return e_detail['error'] if e_detail.key?('error')
105
+ end
106
+
107
+ #
108
+ # Gets all the console output from the stream logs.
109
+ #
110
+ # @param e_ary [Array<Hash>] The list of JSON messages already parsed.
111
+ #
112
+ # @return [String] The generated stdout output.
113
+ #
114
+ # @api private
115
+ #
116
+ def parse_streams(e_ary)
117
+ e_ary.map { |x| x.is_a?(Hash) && x['stream'] }.compact.join
118
+ end
119
+
120
+ #
121
+ # Generates a formated error message.
122
+ #
123
+ # @param error [String] The error message.
124
+ # @param output [String] The generated stdout output.
125
+ #
126
+ # @return [String] The resulting error message.
127
+ #
128
+ # @api private
129
+ #
130
+ def generate_error_message(error, output)
131
+ [
132
+ "#{error}\n",
133
+ "OUTPUT: \n#{output.gsub(/^/, ' ' * 8)}",
134
+ "ERROR: #{error}\n\n"
135
+ ].join("\n")
136
+ end
137
+
138
+ #
139
+ # Raises the right {Dockerspec::DockerError} exception.
140
+ #
141
+ # Nothing is raised if the exception format is unknown.
142
+ #
143
+ # @param e_ary [Array<Hash>] The list of JSON messages already parsed.
144
+ #
145
+ # @return void
146
+ #
147
+ # @raise [Dockerspec::DockerError] When the exception format is known.
148
+ #
149
+ # @api private
150
+ #
151
+ def raise_docker_error_exception(e_ary)
152
+ e_ary.select { |x| x.is_a?(Hash) && x.key?('errorDetail') }[0]
153
+ output = parse_streams(e_ary)
154
+ error_msg = parse_error_detail(e_ary)
155
+ return if error_msg.nil?
156
+ fail DockerError, generate_error_message(error_msg, output)
157
+ end
158
+ end
159
+ end
@@ -23,4 +23,9 @@ module Dockerspec
23
23
  # wrong.
24
24
  #
25
25
  class DockerRunArgumentError < ArgumentError; end
26
+ #
27
+ # An exception message raised when there are errors running Docker or
28
+ # building Docker images.
29
+ #
30
+ class DockerError < ArgumentError; end
26
31
  end
@@ -0,0 +1,29 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Author:: Xabier de Zuazo (<xabier@zuazo.org>)
4
+ # Copyright:: Copyright (c) 2015 Xabier de Zuazo
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ #
21
+ # Some very opinionated RSpec configuration.
22
+ #
23
+ # This may change in the future.
24
+ #
25
+ RSpec.configure do |config|
26
+ config.color = true
27
+ config.formatter = :documentation
28
+ config.tty = true
29
+ end
@@ -133,7 +133,7 @@ module Dockerspec
133
133
  # # [...]
134
134
  # end
135
135
  #
136
- # @example Building from a Docker Image name
136
+ # @example Building from a Docker Image Name
137
137
  # describe docker_build(id: 'nginx:1.9') do
138
138
  # # [...]
139
139
  # end
@@ -196,3 +196,8 @@ RSpec::Core::ExampleGroup.class_eval do
196
196
  extend Dockerspec::RSpecResources
197
197
  include Dockerspec::RSpecResources
198
198
  end
199
+
200
+ #
201
+ # Allow using #docker_build in the outermost example
202
+ #
203
+ extend Dockerspec::RSpecResources
@@ -21,6 +21,7 @@ require 'docker'
21
21
  require 'dockerspec/docker_gem'
22
22
  require 'dockerspec/exceptions'
23
23
  require 'dockerspec/helper/multiple_sources_description'
24
+ require 'dockerspec/docker_exception_parser'
24
25
 
25
26
  module Dockerspec
26
27
  #
@@ -175,11 +176,7 @@ module Dockerspec
175
176
  #
176
177
  def source
177
178
  return @source unless @source.nil?
178
- %i(tag id).any? do |from|
179
- next false unless @options.key?(from)
180
- @source = from # Used for description
181
- end
182
- @source
179
+ @source = %i(tag id).find { |from| @options.key?(from) }
183
180
  end
184
181
 
185
182
  #
@@ -299,6 +296,8 @@ module Dockerspec
299
296
  #
300
297
  def setup_from_id(id)
301
298
  @container = ::Docker::Container.get(id)
299
+ rescue ::Docker::Error::DockerError => e
300
+ DockerExceptionParser.new(e)
302
301
  end
303
302
 
304
303
  #
@@ -358,6 +357,8 @@ module Dockerspec
358
357
  def create_container
359
358
  return @container unless @container.nil?
360
359
  @container = ::Docker::Container.create(container_options)
360
+ rescue ::Docker::Error::DockerError => e
361
+ DockerExceptionParser.new(e)
361
362
  end
362
363
 
363
364
  #
@@ -172,3 +172,8 @@ RSpec::Core::ExampleGroup.class_eval do
172
172
  extend Dockerspec::Serverspec::RSpecResources
173
173
  include Dockerspec::Serverspec::RSpecResources
174
174
  end
175
+
176
+ #
177
+ # Allow using #docker_run in the outermost example
178
+ #
179
+ extend Dockerspec::RSpecResources
@@ -23,6 +23,7 @@ require 'dockerspec/runner'
23
23
  require 'dockerspec/serverspec/specinfra_backend'
24
24
  require 'dockerspec/helper/rspec_example_helpers'
25
25
  require 'dockerspec/helper/docker'
26
+ require 'dockerspec/docker_exception_parser'
26
27
 
27
28
  #
28
29
  # Silence error: No backend type is specified. Fall back to :exec type.
@@ -100,6 +101,8 @@ module Dockerspec
100
101
  run_container
101
102
  specinfra_save
102
103
  self
104
+ rescue ::Docker::Error::DockerError => e
105
+ DockerExceptionParser.new(e)
103
106
  end
104
107
 
105
108
  #
@@ -25,5 +25,5 @@ module Dockerspec
25
25
  #
26
26
  # Dockerspec Ruby Gem version.
27
27
  #
28
- VERSION = '0.1.0'
28
+ VERSION = '0.2.0'
29
29
  end
@@ -28,6 +28,7 @@ end
28
28
 
29
29
  require 'dockerspec'
30
30
  require 'dockerspec/serverspec'
31
+ require 'support/dockerspec_tests'
31
32
 
32
33
  require 'should_not/rspec'
33
34
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dockerspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Xabier de Zuazo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-09 00:00:00.000000000 Z
11
+ date: 2015-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docker-api
@@ -246,6 +246,7 @@ files:
246
246
  - lib/dockerspec/builder/logger/silent.rb
247
247
  - lib/dockerspec/builder/matchers.rb
248
248
  - lib/dockerspec/builder/matchers/helpers.rb
249
+ - lib/dockerspec/docker_exception_parser.rb
249
250
  - lib/dockerspec/docker_gem.rb
250
251
  - lib/dockerspec/exceptions.rb
251
252
  - lib/dockerspec/helper/ci.rb
@@ -253,6 +254,7 @@ files:
253
254
  - lib/dockerspec/helper/multiple_sources_description.rb
254
255
  - lib/dockerspec/helper/rspec_example_helpers.rb
255
256
  - lib/dockerspec/rspec_assertions.rb
257
+ - lib/dockerspec/rspec_configuration.rb
256
258
  - lib/dockerspec/rspec_resources.rb
257
259
  - lib/dockerspec/rspec_settings.rb
258
260
  - lib/dockerspec/runner.rb