dockerspec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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) }