dockerspec 0.1.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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +7 -0
  3. data/CHANGELOG.md +7 -0
  4. data/CONTRIBUTING.md +13 -0
  5. data/LICENSE +190 -0
  6. data/README.md +202 -0
  7. data/Rakefile +57 -0
  8. data/TESTING.md +30 -0
  9. data/TODO.md +6 -0
  10. data/lib/dockerspec.rb +21 -0
  11. data/lib/dockerspec/builder.rb +408 -0
  12. data/lib/dockerspec/builder/config_helpers.rb +425 -0
  13. data/lib/dockerspec/builder/image_gc.rb +71 -0
  14. data/lib/dockerspec/builder/logger.rb +56 -0
  15. data/lib/dockerspec/builder/logger/ci.rb +69 -0
  16. data/lib/dockerspec/builder/logger/debug.rb +47 -0
  17. data/lib/dockerspec/builder/logger/info.rb +111 -0
  18. data/lib/dockerspec/builder/logger/silent.rb +51 -0
  19. data/lib/dockerspec/builder/matchers.rb +134 -0
  20. data/lib/dockerspec/builder/matchers/helpers.rb +88 -0
  21. data/lib/dockerspec/docker_gem.rb +25 -0
  22. data/lib/dockerspec/exceptions.rb +26 -0
  23. data/lib/dockerspec/helper/ci.rb +61 -0
  24. data/lib/dockerspec/helper/docker.rb +44 -0
  25. data/lib/dockerspec/helper/multiple_sources_description.rb +142 -0
  26. data/lib/dockerspec/helper/rspec_example_helpers.rb +48 -0
  27. data/lib/dockerspec/rspec_assertions.rb +54 -0
  28. data/lib/dockerspec/rspec_resources.rb +198 -0
  29. data/lib/dockerspec/rspec_settings.rb +29 -0
  30. data/lib/dockerspec/runner.rb +374 -0
  31. data/lib/dockerspec/serverspec.rb +20 -0
  32. data/lib/dockerspec/serverspec/rspec_resources.rb +174 -0
  33. data/lib/dockerspec/serverspec/rspec_settings.rb +27 -0
  34. data/lib/dockerspec/serverspec/runner.rb +302 -0
  35. data/lib/dockerspec/serverspec/specinfra_backend.rb +128 -0
  36. data/lib/dockerspec/serverspec/specinfra_hack.rb +43 -0
  37. data/lib/dockerspec/version.rb +29 -0
  38. data/spec/spec_helper.rb +44 -0
  39. metadata +293 -0
@@ -0,0 +1,56 @@
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 'dockerspec/builder/logger/silent'
21
+ require 'dockerspec/builder/logger/ci'
22
+ require 'dockerspec/builder/logger/info'
23
+ require 'dockerspec/builder/logger/debug'
24
+
25
+ module Dockerspec
26
+ class Builder
27
+ #
28
+ # Creates an output logger for the {Dockerspec::Builder}.
29
+ #
30
+ class Logger
31
+ #
32
+ # Creates a logger object.
33
+ #
34
+ # @param type [Fixnum, Symbol] The logger to create. Possible values:
35
+ # `:silent` or `0` (no output),
36
+ # `:ci` or `1` (enables some outputs recommended for CI environments),
37
+ # `:info` or `2` (gives information about main build steps),
38
+ # `:debug` or `3` (outputs all the provided information in its raw
39
+ # original form).
40
+ #
41
+ # @return [Dockerspec::Builder::Logger] The logger.
42
+ #
43
+ # @api public
44
+ #
45
+ def self.instance(type)
46
+ case type.to_s.downcase
47
+ when '0', 'silent' then Silent.new
48
+ when '1', 'ci' then CI.new
49
+ when '2', 'info' then Info.new
50
+ else
51
+ Debug.new
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,69 @@
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 'dockerspec/builder/logger/info'
21
+
22
+ module Dockerspec
23
+ class Builder
24
+ class Logger
25
+ #
26
+ # A {Dockerspec::Builder} logger recommended for CI environments with
27
+ # output timeouts.
28
+ #
29
+ class CI < Info
30
+ #
31
+ # Creates a CI logger instance.
32
+ #
33
+ # @param output [IO] the output stream.
34
+ #
35
+ # @api public
36
+ #
37
+ def initialize(output = STDOUT)
38
+ super
39
+ @buffer = ''
40
+ @skip = false
41
+ end
42
+
43
+ protected
44
+
45
+ #
46
+ # Print a Docker build stream in the proper format.
47
+ #
48
+ # @param stream [String] The stream in raw.
49
+ #
50
+ # @return void
51
+ #
52
+ # @api private
53
+ #
54
+ def print_stream(stream)
55
+ if stream.match(/^Step /)
56
+ @buffer = stream
57
+ @skip = true
58
+ else
59
+ @buffer += stream
60
+ @skip = false if stream.match(/^ ---> (Running in|\[Warning\]) /)
61
+ end
62
+ return if @skip
63
+ @output.puts @buffer
64
+ @buffer = ''
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,47 @@
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 'dockerspec/builder/logger/info'
21
+
22
+ module Dockerspec
23
+ class Builder
24
+ class Logger
25
+ #
26
+ # A {Dockerspec::Builder} logger to output all the provided information in
27
+ # its raw original form.
28
+ #
29
+ class Debug < Info
30
+ #
31
+ # Prints the docker build chunk in raw.
32
+ #
33
+ # @param chunk [Hash] The docker build chunk.
34
+ #
35
+ # @return void
36
+ #
37
+ # @api public
38
+ #
39
+ def print_chunk(chunk)
40
+ chunk_json = parse_chunk(chunk)
41
+ print_status(chunk_json.delete('status'))
42
+ @output.puts chunk_json.inspect
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,111 @@
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
+ module Dockerspec
21
+ class Builder
22
+ class Logger
23
+ #
24
+ # A {Dockerspec::Builder} logger that gives information about main build
25
+ # steps.
26
+ #
27
+ class Info
28
+ #
29
+ # Creates a Info logger instance.
30
+ #
31
+ # @param output [IO] the output stream.
32
+ #
33
+ # @api public
34
+ #
35
+ def initialize(output = STDOUT)
36
+ @output = output
37
+ @status = nil
38
+ end
39
+
40
+ #
41
+ # Prints the Docker build chunk.
42
+ #
43
+ # @param chunk [Hash] The docker build chunk.
44
+ #
45
+ # @return void
46
+ #
47
+ # @api public
48
+ #
49
+ def print_chunk(chunk)
50
+ chunk_json = parse_chunk(chunk)
51
+ print_status(chunk_json['status'])
52
+ return unless chunk_json.key?('stream')
53
+ print_stream(chunk_json['stream'])
54
+ end
55
+
56
+ protected
57
+
58
+ #
59
+ # Parses the Docker build process chunk.
60
+ #
61
+ # @param chunk [String] The chunk in JSON.
62
+ #
63
+ # @return [Hash] The chunk parsed as a Hash.
64
+ #
65
+ # @api private
66
+ #
67
+ def parse_chunk(chunk)
68
+ return chunk if chunk.is_a?(Hash)
69
+ JSON.parse(chunk)
70
+ rescue JSON::ParserError
71
+ { 'stream' => chunk }
72
+ end
73
+
74
+ #
75
+ # Prints progress status in a shorter format.
76
+ #
77
+ # For example: `'Downloading.....\nExtracting..`'.
78
+ #
79
+ # @param status [String] The name of the current status.
80
+ #
81
+ # @return void
82
+ #
83
+ # @api private
84
+ #
85
+ def print_status(status)
86
+ if status != @status
87
+ @output.puts
88
+ @status = status
89
+ @output.print "#{status}." unless status.nil?
90
+ elsif !status.nil?
91
+ @output.print '.'
92
+ end
93
+ @output.flush
94
+ end
95
+
96
+ #
97
+ # Prints the stream.
98
+ #
99
+ # @param stream [String] The text to print.
100
+ #
101
+ # @return void
102
+ #
103
+ # @api private
104
+ #
105
+ def print_stream(stream)
106
+ @output.puts stream
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,51 @@
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
+ module Dockerspec
21
+ class Builder
22
+ class Logger
23
+ #
24
+ # A {Dockerspec::Builder} logger that outputs nothing.
25
+ #
26
+ class Silent
27
+ #
28
+ # Creates a Silent logger instance.
29
+ #
30
+ # @param _args [Mixed] ignored.
31
+ #
32
+ # @return void
33
+ #
34
+ # @api private
35
+ #
36
+ def initialize(*_args); end
37
+
38
+ #
39
+ # Prints nothing.
40
+ #
41
+ # @param _chunk [Mixed] ignored.
42
+ #
43
+ # @return void
44
+ #
45
+ # @api private
46
+ #
47
+ def print_chunk(_chunk); end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,134 @@
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 'rspec/expectations'
21
+ require 'dockerspec/builder/matchers/helpers'
22
+
23
+ module Dockerspec
24
+ class Builder
25
+ #
26
+ # Creates some RSpec *have_* matchers for Docker builds.
27
+ #
28
+ module Matchers
29
+ extend RSpec::Matchers::DSL
30
+
31
+ #
32
+ # The matcher list with the type it belongs to.
33
+ #
34
+ # This is based on [the official *Dockerfile* parser code]
35
+ # (https://github.com/docker/docker/tree/master/builder/dockerfile/parser)
36
+ # .
37
+ #
38
+ # The possible types are:
39
+ #
40
+ # - `:string`: A simple string. For example the `MAINTAINER` instruction.
41
+ # - `:json`: Can in JSON (a Ruby array) or in string format. For example
42
+ # the `CMD` or the `ENTRYPOINT` instructions.
43
+ # - `:hash`: A hash. For example the `ENV` or the `LABEL` instructions.
44
+ # - `:array`: A array of values. For example the `EXPOSE` instruction.
45
+ #
46
+ PREDICATE_TYPES = {
47
+ maintainer: :string,
48
+ cmd: :json,
49
+ label: :hash,
50
+ expose: :array,
51
+ env: :hash,
52
+ entrypoint: :json,
53
+ volume: :array,
54
+ user: :string,
55
+ workdir: :string,
56
+ onbuild: :array,
57
+ stopsignal: :string
58
+ }
59
+
60
+ PREDICATE_TYPES.each do |name, type|
61
+ matcher_name = "have_#{name}".to_sym
62
+
63
+ case type
64
+ when :string
65
+ matcher matcher_name do |expected|
66
+ match { |actual| !expected.match(actual.send(name)).nil? }
67
+
68
+ failure_message do |actual|
69
+ "expected `#{name.upcase}` to match `#{expected.inspect}`, "\
70
+ "got `#{actual.send(name)}`"
71
+ end
72
+
73
+ failure_message_when_negated do |actual|
74
+ "expected `#{name.upcase}` not to match `#{expected.inspect}`, "\
75
+ "got `#{actual.send(name)}`"
76
+ end
77
+ end
78
+ when :json
79
+ matcher matcher_name do |expected|
80
+ include MatcherHelpers
81
+
82
+ match { |actual| maybe_json?(actual.send(name), expected) }
83
+
84
+ failure_message do |actual|
85
+ "expected `#{name.upcase}` to be `#{expected.inspect}`, "\
86
+ "got `#{actual.send(name)}`"
87
+ end
88
+
89
+ failure_message_when_negated do |actual|
90
+ "expected `#{name.upcase}` not to be `#{expected.inspect}`, "\
91
+ "got `#{actual.send(name)}`"
92
+ end
93
+ end
94
+ when :array
95
+ matcher matcher_name do |expected|
96
+ match { |actual| !actual.send("#{name}s").grep(expected).empty? }
97
+
98
+ failure_message do |actual|
99
+ "expected `#{name.upcase}` to include `#{expected.inspect}`, "\
100
+ "got `#{actual.send("#{name}s").inspect}`"
101
+ end
102
+
103
+ failure_message_when_negated do |actual|
104
+ "expected `#{name.upcase}` not to include "\
105
+ "`#{expected.inspect}`, got `#{actual.send("#{name}s").inspect}`"
106
+ end
107
+ end
108
+ when :hash
109
+ matcher matcher_name do |expected|
110
+ include MatcherHelpers
111
+
112
+ match do |actual|
113
+ actual = actual.send("#{name}s")
114
+ break sub_hash?(actual, expected) if expected.is_a?(Hash)
115
+ !actual.keys.grep(expected).empty?
116
+ end
117
+
118
+ failure_message do |actual|
119
+ "expected `#{name.upcase}` to contain `#{expected.inspect}`, "\
120
+ "got `#{actual.send("#{name}s")}`"
121
+ end
122
+
123
+ failure_message_when_negated do |actual|
124
+ "expected `#{name.upcase}` not to contain "\
125
+ "`#{expected.inspect}`, got `#{actual.send("#{name}s")}`"
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ RSpec.configure { |c| c.include(Dockerspec::Builder::Matchers) }