dockerspec 0.1.0 → 0.2.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: 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