chef-dk 0.5.0.rc.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +63 -24
- data/lib/chef-dk/builtin_commands.rb +2 -0
- data/lib/chef-dk/command/diff.rb +312 -0
- data/lib/chef-dk/command/push.rb +1 -1
- data/lib/chef-dk/command/shell_init.rb +21 -3
- data/lib/chef-dk/command/update.rb +28 -5
- data/lib/chef-dk/configurable.rb +1 -1
- data/lib/chef-dk/exceptions.rb +3 -0
- data/lib/chef-dk/pager.rb +106 -0
- data/lib/chef-dk/policyfile/chef_repo_cookbook_source.rb +114 -0
- data/lib/chef-dk/policyfile/comparison_base.rb +124 -0
- data/lib/chef-dk/policyfile/cookbook_sources.rb +1 -0
- data/lib/chef-dk/policyfile/differ.rb +266 -0
- data/lib/chef-dk/policyfile/dsl.rb +26 -3
- data/lib/chef-dk/policyfile/uploader.rb +4 -5
- data/lib/chef-dk/policyfile_compiler.rb +8 -0
- data/lib/chef-dk/policyfile_lock.rb +135 -3
- data/lib/chef-dk/policyfile_services/install.rb +1 -0
- data/lib/chef-dk/policyfile_services/update_attributes.rb +104 -0
- data/lib/chef-dk/service_exceptions.rb +12 -0
- data/lib/chef-dk/ui.rb +8 -0
- data/lib/chef-dk/version.rb +1 -1
- data/spec/spec_helper.rb +6 -0
- data/spec/test_helpers.rb +4 -0
- data/spec/unit/command/diff_spec.rb +283 -0
- data/spec/unit/command/shell_init_spec.rb +19 -2
- data/spec/unit/command/update_spec.rb +96 -0
- data/spec/unit/command/verify_spec.rb +0 -6
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/Berksfile +3 -0
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/README.md +4 -0
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/chefignore +96 -0
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/metadata.rb +9 -0
- data/spec/unit/fixtures/local_path_cookbooks/cookbook-with-a-dep/recipes/default.rb +8 -0
- data/spec/unit/pager_spec.rb +119 -0
- data/spec/unit/policyfile/chef_repo_cookbook_source_spec.rb +66 -0
- data/spec/unit/policyfile/comparison_base_spec.rb +343 -0
- data/spec/unit/policyfile/differ_spec.rb +687 -0
- data/spec/unit/policyfile_evaluation_spec.rb +87 -0
- data/spec/unit/policyfile_lock_build_spec.rb +247 -8
- data/spec/unit/policyfile_lock_serialization_spec.rb +47 -0
- data/spec/unit/policyfile_services/export_repo_spec.rb +2 -0
- data/spec/unit/policyfile_services/push_spec.rb +2 -0
- data/spec/unit/policyfile_services/update_attributes_spec.rb +217 -0
- metadata +62 -6
@@ -20,6 +20,7 @@ require 'chef-dk/command/shell_init'
|
|
20
20
|
|
21
21
|
describe ChefDK::Command::ShellInit do
|
22
22
|
|
23
|
+
let(:expected_path) { [omnibus_bin_dir, user_bin_dir, omnibus_embedded_bin_dir, ENV['PATH']].join(File::PATH_SEPARATOR) }
|
23
24
|
let(:stdout_io) { StringIO.new }
|
24
25
|
let(:stderr_io) { StringIO.new }
|
25
26
|
|
@@ -32,7 +33,6 @@ describe ChefDK::Command::ShellInit do
|
|
32
33
|
|
33
34
|
shared_context "shell init script" do |shell|
|
34
35
|
let(:user_bin_dir) { File.expand_path(File.join(Gem.user_dir, 'bin')) }
|
35
|
-
let(:expected_path) { [omnibus_bin_dir, user_bin_dir, omnibus_embedded_bin_dir, ENV['PATH']].join(File::PATH_SEPARATOR) }
|
36
36
|
let(:expected_gem_root) { Gem.default_dir.to_s }
|
37
37
|
let(:expected_gem_home) { Gem.user_dir }
|
38
38
|
let(:expected_gem_path) { Gem.path.join(File::PATH_SEPARATOR) }
|
@@ -107,6 +107,23 @@ EOH
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
context 'for fish' do
|
111
|
+
before do
|
112
|
+
stub_const('File::PATH_SEPARATOR', ':')
|
113
|
+
end
|
114
|
+
let(:expected_path) { [omnibus_bin_dir, user_bin_dir, omnibus_embedded_bin_dir, ENV['PATH']].join(':').split(':').join('" "') }
|
115
|
+
let(:expected_environment_commands) do
|
116
|
+
<<-EOH
|
117
|
+
set -gx PATH "#{expected_path}" 2>/dev/null;
|
118
|
+
set -gx GEM_ROOT "#{expected_gem_root}";
|
119
|
+
set -gx GEM_HOME "#{expected_gem_home}";
|
120
|
+
set -gx GEM_PATH "#{expected_gem_path}";
|
121
|
+
EOH
|
122
|
+
end
|
123
|
+
|
124
|
+
include_context 'shell init script', 'fish'
|
125
|
+
end
|
126
|
+
|
110
127
|
['powershell', 'posh'].each do |shell|
|
111
128
|
context "for #{shell}" do
|
112
129
|
it_behaves_like "a powershell script", shell
|
@@ -131,7 +148,7 @@ EOH
|
|
131
148
|
it "exits with an error message" do
|
132
149
|
expect(command_instance.run(argv)).to eq(1)
|
133
150
|
expect(stderr_io.string).to include("Shell `nosuchsh' is not currently supported")
|
134
|
-
expect(stderr_io.string).to include("Supported shells are: bash zsh sh powershell posh")
|
151
|
+
expect(stderr_io.string).to include("Supported shells are: bash fish zsh sh powershell posh")
|
135
152
|
end
|
136
153
|
|
137
154
|
end
|
@@ -33,6 +33,8 @@ describe ChefDK::Command::Update do
|
|
33
33
|
|
34
34
|
let(:install_service) { instance_double(ChefDK::PolicyfileServices::Install) }
|
35
35
|
|
36
|
+
let(:update_attrs_service) { instance_double(ChefDK::PolicyfileServices::UpdateAttributes) }
|
37
|
+
|
36
38
|
it "disables debug by default" do
|
37
39
|
expect(command.debug?).to be(false)
|
38
40
|
end
|
@@ -46,6 +48,22 @@ describe ChefDK::Command::Update do
|
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
51
|
+
context "when attributes update mode is set" do
|
52
|
+
|
53
|
+
let(:params) { ["-a"] }
|
54
|
+
|
55
|
+
it "enables attributes update mode" do
|
56
|
+
expect(command.update_attributes?).to be(true)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "creates an attributes update service object" do
|
60
|
+
expect(ChefDK::PolicyfileServices::UpdateAttributes).to receive(:new).
|
61
|
+
with(policyfile: nil, ui: command.ui, root_dir: Dir.pwd).
|
62
|
+
and_return(update_attrs_service)
|
63
|
+
expect(command.attributes_updater).to eq(update_attrs_service)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
49
67
|
context "with no arguments" do
|
50
68
|
|
51
69
|
it "does not specify a policyfile relative path" do
|
@@ -140,6 +158,84 @@ Error: install failed
|
|
140
158
|
Reason: (StandardError) some operation failed
|
141
159
|
|
142
160
|
|
161
|
+
E
|
162
|
+
|
163
|
+
expected_error_text << backtrace.join("\n") << "\n"
|
164
|
+
|
165
|
+
command.run
|
166
|
+
expect(ui.output).to eq(expected_error_text)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "running attributes update" do
|
175
|
+
|
176
|
+
let(:params) { ["-a"] }
|
177
|
+
|
178
|
+
let(:ui) { TestHelpers::TestUI.new }
|
179
|
+
|
180
|
+
before do
|
181
|
+
command.ui = ui
|
182
|
+
allow(command).to receive(:attributes_updater).and_return(update_attrs_service)
|
183
|
+
end
|
184
|
+
|
185
|
+
context "when the command runs successfully" do
|
186
|
+
|
187
|
+
before do
|
188
|
+
expect(update_attrs_service).to receive(:run)
|
189
|
+
end
|
190
|
+
|
191
|
+
it "exits with success" do
|
192
|
+
expect(command.run).to eq(0)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
context "when the command fails" do
|
197
|
+
|
198
|
+
let(:backtrace) { caller[0...3] }
|
199
|
+
|
200
|
+
let(:cause) do
|
201
|
+
e = StandardError.new("some operation failed")
|
202
|
+
e.set_backtrace(backtrace)
|
203
|
+
e
|
204
|
+
end
|
205
|
+
|
206
|
+
let(:exception) do
|
207
|
+
ChefDK::PolicyfileUpdateError.new("Failed to update Policyfile lock", cause)
|
208
|
+
end
|
209
|
+
|
210
|
+
before do
|
211
|
+
expect(update_attrs_service).to receive(:run).and_raise(exception)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "exits 1" do
|
215
|
+
expect(command.run).to eq(1)
|
216
|
+
end
|
217
|
+
|
218
|
+
it "displays the exception and cause" do
|
219
|
+
expected_error_text=<<-E
|
220
|
+
Error: Failed to update Policyfile lock
|
221
|
+
Reason: (StandardError) some operation failed
|
222
|
+
|
223
|
+
E
|
224
|
+
|
225
|
+
command.run
|
226
|
+
expect(ui.output).to eq(expected_error_text)
|
227
|
+
end
|
228
|
+
|
229
|
+
context "and debug is enabled" do
|
230
|
+
|
231
|
+
let(:params) { ["-a", "-D"] }
|
232
|
+
|
233
|
+
it "displays the exception and cause with backtrace" do
|
234
|
+
expected_error_text=<<-E
|
235
|
+
Error: Failed to update Policyfile lock
|
236
|
+
Reason: (StandardError) some operation failed
|
237
|
+
|
238
|
+
|
143
239
|
E
|
144
240
|
|
145
241
|
expected_error_text << backtrace.join("\n") << "\n"
|
@@ -280,12 +280,6 @@ describe ChefDK::Command::Verify do
|
|
280
280
|
expect(stdout).to include("my friend everything is good...")
|
281
281
|
end
|
282
282
|
|
283
|
-
it "should report the output of the first verification first" do
|
284
|
-
index_first = stdout.index("you are good to go...")
|
285
|
-
index_second = stdout.index("my friend everything is good...")
|
286
|
-
expect(index_second > index_first).to be true
|
287
|
-
end
|
288
|
-
|
289
283
|
context "and components are filtered by CLI args" do
|
290
284
|
|
291
285
|
let(:command_options) { [ "successful_comp_2" ] }
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# Put files/directories that should be ignored in this file when uploading
|
2
|
+
# or sharing to the community site.
|
3
|
+
# Lines that start with '# ' are comments.
|
4
|
+
|
5
|
+
# OS generated files #
|
6
|
+
######################
|
7
|
+
.DS_Store
|
8
|
+
Icon?
|
9
|
+
nohup.out
|
10
|
+
ehthumbs.db
|
11
|
+
Thumbs.db
|
12
|
+
|
13
|
+
# SASS #
|
14
|
+
########
|
15
|
+
.sass-cache
|
16
|
+
|
17
|
+
# EDITORS #
|
18
|
+
###########
|
19
|
+
\#*
|
20
|
+
.#*
|
21
|
+
*~
|
22
|
+
*.sw[a-z]
|
23
|
+
*.bak
|
24
|
+
REVISION
|
25
|
+
TAGS*
|
26
|
+
tmtags
|
27
|
+
*_flymake.*
|
28
|
+
*_flymake
|
29
|
+
*.tmproj
|
30
|
+
.project
|
31
|
+
.settings
|
32
|
+
mkmf.log
|
33
|
+
|
34
|
+
## COMPILED ##
|
35
|
+
##############
|
36
|
+
a.out
|
37
|
+
*.o
|
38
|
+
*.pyc
|
39
|
+
*.so
|
40
|
+
*.com
|
41
|
+
*.class
|
42
|
+
*.dll
|
43
|
+
*.exe
|
44
|
+
*/rdoc/
|
45
|
+
|
46
|
+
# Testing #
|
47
|
+
###########
|
48
|
+
.watchr
|
49
|
+
.rspec
|
50
|
+
spec/*
|
51
|
+
spec/fixtures/*
|
52
|
+
test/*
|
53
|
+
features/*
|
54
|
+
Guardfile
|
55
|
+
Procfile
|
56
|
+
|
57
|
+
# SCM #
|
58
|
+
#######
|
59
|
+
.git
|
60
|
+
*/.git
|
61
|
+
.gitignore
|
62
|
+
.gitmodules
|
63
|
+
.gitconfig
|
64
|
+
.gitattributes
|
65
|
+
.svn
|
66
|
+
*/.bzr/*
|
67
|
+
*/.hg/*
|
68
|
+
*/.svn/*
|
69
|
+
|
70
|
+
# Berkshelf #
|
71
|
+
#############
|
72
|
+
Berksfile
|
73
|
+
Berksfile.lock
|
74
|
+
cookbooks/*
|
75
|
+
tmp
|
76
|
+
|
77
|
+
# Cookbooks #
|
78
|
+
#############
|
79
|
+
CONTRIBUTING
|
80
|
+
CHANGELOG*
|
81
|
+
|
82
|
+
# Strainer #
|
83
|
+
############
|
84
|
+
Colanderfile
|
85
|
+
Strainerfile
|
86
|
+
.colander
|
87
|
+
.strainer
|
88
|
+
|
89
|
+
# Vagrant #
|
90
|
+
###########
|
91
|
+
.vagrant
|
92
|
+
Vagrantfile
|
93
|
+
|
94
|
+
# Travis #
|
95
|
+
##########
|
96
|
+
.travis.yml
|
@@ -0,0 +1,119 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2015 Chef Software Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'spec_helper'
|
19
|
+
require 'chef-dk/pager'
|
20
|
+
|
21
|
+
describe ChefDK::Pager do
|
22
|
+
|
23
|
+
context "with default options" do
|
24
|
+
|
25
|
+
subject(:pager) { ChefDK::Pager.new }
|
26
|
+
|
27
|
+
it "gives ENV for env" do
|
28
|
+
expect(pager.env).to eq(ENV)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "checks stdout for TTY" do
|
32
|
+
expect($stdout).to receive(:tty?).twice.and_call_original
|
33
|
+
expect(pager.have_tty?).to eq($stdout.tty?)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "enables paging" do
|
37
|
+
expect(pager).to receive(:env).and_return({"PAGER" => "less"})
|
38
|
+
expect(pager).to receive(:have_tty?).and_return(true)
|
39
|
+
expect(pager.pager_enabled?).to be(true)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with paging enabled" do
|
44
|
+
|
45
|
+
subject(:pager) do
|
46
|
+
ChefDK::Pager.new(enable_pager: true).tap do |p|
|
47
|
+
allow(p).to receive(:env).and_return({"PAGER" => "less"})
|
48
|
+
allow(p).to receive(:have_tty?).and_return(true)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:pipe_read) { instance_double("IO") }
|
53
|
+
let(:pipe_write) { instance_double("IO") }
|
54
|
+
|
55
|
+
let(:pager_env) { { "LESS" => "-FRX", "LV" => "-c" } }
|
56
|
+
|
57
|
+
before do
|
58
|
+
allow(IO).to receive(:pipe).and_return([pipe_read, pipe_write])
|
59
|
+
end
|
60
|
+
|
61
|
+
it "provides a UI object with stdout set to a pipe" do
|
62
|
+
expect(pager.ui.out_stream).to eq(pipe_write)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "starts the pager" do
|
66
|
+
expect(Kernel).to receive(:trap).with(:INT, "IGNORE")
|
67
|
+
expect(Process).to receive(:spawn).with(pager_env, "less", in: pipe_read).and_return(12345)
|
68
|
+
expect(pipe_read).to receive(:close)
|
69
|
+
pager.start
|
70
|
+
end
|
71
|
+
|
72
|
+
it "waits for the pager to exit" do
|
73
|
+
expect(Kernel).to receive(:trap).with(:INT, "IGNORE")
|
74
|
+
expect(Process).to receive(:spawn).with(pager_env, "less", in: pipe_read).and_return(12345)
|
75
|
+
expect(pipe_read).to receive(:close)
|
76
|
+
pager.start
|
77
|
+
|
78
|
+
expect(pipe_write).to receive(:close)
|
79
|
+
expect(Process).to receive(:waitpid).with(12345)
|
80
|
+
pager.wait
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with paging disabled" do
|
85
|
+
|
86
|
+
subject(:pager) do
|
87
|
+
ChefDK::Pager.new(enable_pager: false).tap do |p|
|
88
|
+
allow(p).to receive(:env).and_return({"PAGER" => "less"})
|
89
|
+
allow(p).to receive(:have_tty?).and_return(true)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
before do
|
94
|
+
expect(IO).to_not receive(:pipe)
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
it "provides a UI with stdout set to stdout" do
|
99
|
+
expect(pager.ui.out_stream).to eq($stdout)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "no-ops on pager start" do
|
103
|
+
expect(Kernel).to_not receive(:trap)
|
104
|
+
expect(Process).to_not receive(:spawn)
|
105
|
+
pager.start
|
106
|
+
end
|
107
|
+
|
108
|
+
it "no-ops on pager wait" do
|
109
|
+
expect(Kernel).to_not receive(:trap)
|
110
|
+
expect(Process).to_not receive(:spawn)
|
111
|
+
pager.start
|
112
|
+
|
113
|
+
expect(Process).to_not receive(:waitpid)
|
114
|
+
pager.wait
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
#
|
2
|
+
# Copyright:: Copyright (c) 2014 Chef Software Inc.
|
3
|
+
# License:: Apache License, Version 2.0
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
|
18
|
+
require 'spec_helper'
|
19
|
+
require 'chef-dk/policyfile/chef_repo_cookbook_source'
|
20
|
+
|
21
|
+
describe ChefDK::Policyfile::ChefRepoCookbookSource do
|
22
|
+
|
23
|
+
let(:repo_path) {
|
24
|
+
File.expand_path("spec/unit/fixtures/local_path_cookbooks", project_root)
|
25
|
+
}
|
26
|
+
|
27
|
+
let(:cookbook_source) { ChefDK::Policyfile::ChefRepoCookbookSource.new(repo_path) }
|
28
|
+
|
29
|
+
let(:local_repo_universe) {
|
30
|
+
{
|
31
|
+
"another-local-cookbook"=>{
|
32
|
+
"0.1.0"=>[],
|
33
|
+
},
|
34
|
+
"local-cookbook"=>{
|
35
|
+
"2.3.4"=>[],
|
36
|
+
},
|
37
|
+
"cookbook-with-a-dep"=>{
|
38
|
+
"9.9.9"=>[["another-local-cookbook", "~> 0.1"]],
|
39
|
+
},
|
40
|
+
"noignore"=>{
|
41
|
+
"0.1.0"=>[],
|
42
|
+
},
|
43
|
+
}
|
44
|
+
}
|
45
|
+
it "fetches the universe graph" do
|
46
|
+
actual_universe = cookbook_source.universe_graph
|
47
|
+
expect(actual_universe).to eql(local_repo_universe)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "generates location options for a cookbook from the given graph" do
|
51
|
+
expected_opts = { path: File.join(repo_path, "local-cookbook"), version: "2.3.4" }
|
52
|
+
expect(cookbook_source.source_options_for("local-cookbook", "2.3.4")).to eq(expected_opts)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "will append a cookbooks directory to the path if it finds it" do
|
56
|
+
expect(Dir).to receive(:exist?).with("#{repo_path}/cookbooks").and_return(true)
|
57
|
+
expect(cookbook_source.path).to eql("#{repo_path}/cookbooks")
|
58
|
+
end
|
59
|
+
|
60
|
+
it "the private setter will append a cookbooks directory to the path if finds it" do
|
61
|
+
expect(cookbook_source.path).to eql(repo_path)
|
62
|
+
expect(Dir).to receive(:exist?).with("#{repo_path}/cookbooks").and_return(true)
|
63
|
+
cookbook_source.send(:path=, repo_path)
|
64
|
+
expect(cookbook_source.path).to eql("#{repo_path}/cookbooks")
|
65
|
+
end
|
66
|
+
end
|