dockerspec 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +13 -0
- data/LICENSE +190 -0
- data/README.md +202 -0
- data/Rakefile +57 -0
- data/TESTING.md +30 -0
- data/TODO.md +6 -0
- data/lib/dockerspec.rb +21 -0
- data/lib/dockerspec/builder.rb +408 -0
- data/lib/dockerspec/builder/config_helpers.rb +425 -0
- data/lib/dockerspec/builder/image_gc.rb +71 -0
- data/lib/dockerspec/builder/logger.rb +56 -0
- data/lib/dockerspec/builder/logger/ci.rb +69 -0
- data/lib/dockerspec/builder/logger/debug.rb +47 -0
- data/lib/dockerspec/builder/logger/info.rb +111 -0
- data/lib/dockerspec/builder/logger/silent.rb +51 -0
- data/lib/dockerspec/builder/matchers.rb +134 -0
- data/lib/dockerspec/builder/matchers/helpers.rb +88 -0
- data/lib/dockerspec/docker_gem.rb +25 -0
- data/lib/dockerspec/exceptions.rb +26 -0
- data/lib/dockerspec/helper/ci.rb +61 -0
- data/lib/dockerspec/helper/docker.rb +44 -0
- data/lib/dockerspec/helper/multiple_sources_description.rb +142 -0
- data/lib/dockerspec/helper/rspec_example_helpers.rb +48 -0
- data/lib/dockerspec/rspec_assertions.rb +54 -0
- data/lib/dockerspec/rspec_resources.rb +198 -0
- data/lib/dockerspec/rspec_settings.rb +29 -0
- data/lib/dockerspec/runner.rb +374 -0
- data/lib/dockerspec/serverspec.rb +20 -0
- data/lib/dockerspec/serverspec/rspec_resources.rb +174 -0
- data/lib/dockerspec/serverspec/rspec_settings.rb +27 -0
- data/lib/dockerspec/serverspec/runner.rb +302 -0
- data/lib/dockerspec/serverspec/specinfra_backend.rb +128 -0
- data/lib/dockerspec/serverspec/specinfra_hack.rb +43 -0
- data/lib/dockerspec/version.rb +29 -0
- data/spec/spec_helper.rb +44 -0
- 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) }
|