chef-dk 0.5.0.rc.1 → 0.5.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.
- 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
|