chef-dk 0.7.0 → 0.8.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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/chef-dk/builtin_commands.rb +10 -0
  4. data/lib/chef-dk/command/base.rb +2 -2
  5. data/lib/chef-dk/command/clean_policy_cookbooks.rb +116 -0
  6. data/lib/chef-dk/command/clean_policy_revisions.rb +113 -0
  7. data/lib/chef-dk/command/delete_policy.rb +122 -0
  8. data/lib/chef-dk/command/delete_policy_group.rb +122 -0
  9. data/lib/chef-dk/command/export.rb +3 -3
  10. data/lib/chef-dk/command/generate.rb +8 -0
  11. data/lib/chef-dk/command/generator_commands/app.rb +1 -1
  12. data/lib/chef-dk/command/generator_commands/cookbook.rb +1 -1
  13. data/lib/chef-dk/command/generator_commands/policyfile.rb +1 -1
  14. data/lib/chef-dk/command/generator_commands/repo.rb +1 -1
  15. data/lib/chef-dk/command/install.rb +22 -5
  16. data/lib/chef-dk/command/provision.rb +0 -4
  17. data/lib/chef-dk/command/push.rb +1 -2
  18. data/lib/chef-dk/command/shell_init.rb +65 -6
  19. data/lib/chef-dk/command/show_policy.rb +1 -2
  20. data/lib/chef-dk/command/undelete.rb +155 -0
  21. data/lib/chef-dk/command/update.rb +5 -5
  22. data/lib/chef-dk/command/verify.rb +61 -17
  23. data/lib/chef-dk/completions/bash.sh.erb +5 -0
  24. data/lib/chef-dk/completions/chef.fish.erb +10 -0
  25. data/lib/chef-dk/completions/zsh.zsh.erb +21 -0
  26. data/lib/chef-dk/exceptions.rb +12 -0
  27. data/lib/chef-dk/helpers.rb +17 -0
  28. data/lib/chef-dk/policyfile/community_cookbook_source.rb +0 -3
  29. data/lib/chef-dk/policyfile/lister.rb +3 -1
  30. data/lib/chef-dk/policyfile/undo_record.rb +142 -0
  31. data/lib/chef-dk/policyfile/undo_stack.rb +130 -0
  32. data/lib/chef-dk/policyfile_lock.rb +30 -0
  33. data/lib/chef-dk/policyfile_services/clean_policies.rb +5 -4
  34. data/lib/chef-dk/policyfile_services/clean_policy_cookbooks.rb +125 -0
  35. data/lib/chef-dk/policyfile_services/rm_policy.rb +142 -0
  36. data/lib/chef-dk/policyfile_services/rm_policy_group.rb +86 -0
  37. data/lib/chef-dk/policyfile_services/show_policy.rb +1 -1
  38. data/lib/chef-dk/policyfile_services/undelete.rb +108 -0
  39. data/lib/chef-dk/service_exceptions.rb +11 -0
  40. data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +6 -2
  41. data/lib/chef-dk/skeletons/code_generator/files/default/repo/README.md +1 -1
  42. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/attributes/default.rb +1 -1
  43. data/lib/chef-dk/skeletons/code_generator/files/default/repo/cookbooks/example/recipes/default.rb +1 -1
  44. data/lib/chef-dk/version.rb +1 -1
  45. data/lib/kitchen/provisioner/policyfile_zero.rb +4 -1
  46. data/spec/unit/command/base_spec.rb +26 -1
  47. data/spec/unit/command/clean_policy_cookbooks_spec.rb +181 -0
  48. data/spec/unit/command/clean_policy_revisions_spec.rb +181 -0
  49. data/spec/unit/command/delete_policy_group_spec.rb +207 -0
  50. data/spec/unit/command/delete_policy_spec.rb +207 -0
  51. data/spec/unit/command/generate_spec.rb +41 -1
  52. data/spec/unit/command/generator_commands/cookbook_spec.rb +1 -1
  53. data/spec/unit/command/generator_commands/policyfile_spec.rb +1 -1
  54. data/spec/unit/command/install_spec.rb +24 -0
  55. data/spec/unit/command/shell_init_spec.rb +176 -5
  56. data/spec/unit/command/undelete_spec.rb +246 -0
  57. data/spec/unit/helpers_spec.rb +24 -0
  58. data/spec/unit/policyfile/lister_spec.rb +16 -0
  59. data/spec/unit/policyfile/undo_record_spec.rb +260 -0
  60. data/spec/unit/policyfile/undo_stack_spec.rb +266 -0
  61. data/spec/unit/policyfile_lock_serialization_spec.rb +41 -0
  62. data/spec/unit/policyfile_services/clean_policy_cookbooks_spec.rb +275 -0
  63. data/spec/unit/policyfile_services/rm_policy_group_spec.rb +241 -0
  64. data/spec/unit/policyfile_services/rm_policy_spec.rb +266 -0
  65. data/spec/unit/policyfile_services/show_policy_spec.rb +52 -2
  66. data/spec/unit/policyfile_services/undelete_spec.rb +304 -0
  67. metadata +43 -91
@@ -99,7 +99,7 @@ describe ChefDK::Command::GeneratorCommands::Cookbook do
99
99
 
100
100
  it "prints usage when args are empty" do
101
101
  with_argv([]).run
102
- expect(stdout_io.string).to eq(expected_help_message)
102
+ expect(stderr_io.string).to include(expected_help_message)
103
103
  end
104
104
 
105
105
  end
@@ -115,7 +115,7 @@ describe ChefDK::Command::GeneratorCommands::Policyfile do
115
115
  expected_stdout = "Usage: chef generate policyfile [NAME] [options]"
116
116
 
117
117
  expect(generator.run).to eq(1)
118
- expect(stdout).to include(expected_stdout)
118
+ expect(stderr).to include(expected_stdout)
119
119
  end
120
120
 
121
121
  end
@@ -37,6 +37,10 @@ describe ChefDK::Command::Install do
37
37
  expect(command.debug?).to be(false)
38
38
  end
39
39
 
40
+ it "doesn't set a config path by default" do
41
+ expect(command.config_path).to be_nil
42
+ end
43
+
40
44
  context "when debug mode is set" do
41
45
 
42
46
  let(:params) { [ "-D" ] }
@@ -46,6 +50,26 @@ describe ChefDK::Command::Install do
46
50
  end
47
51
  end
48
52
 
53
+ context "when an explicit config file path is given" do
54
+
55
+ let(:params) { %w[ -c ~/.chef/alternate_config.rb ] }
56
+
57
+ let(:chef_config_loader) { instance_double("Chef::WorkstationConfigLoader") }
58
+
59
+ it "sets the config file path to the given value" do
60
+ expect(command.config_path).to eq("~/.chef/alternate_config.rb")
61
+ end
62
+
63
+ it "loads the config from the given path" do
64
+ expect(Chef::WorkstationConfigLoader).to receive(:new).
65
+ with("~/.chef/alternate_config.rb").
66
+ and_return(chef_config_loader)
67
+ expect(chef_config_loader).to receive(:load)
68
+ expect(command.chef_config).to eq(Chef::Config)
69
+ end
70
+
71
+ end
72
+
49
73
  context "with no arguments" do
50
74
 
51
75
  it "does not specify a policyfile relative path" do
@@ -50,7 +50,14 @@ describe ChefDK::Command::ShellInit do
50
50
 
51
51
  it "emits a script to add ChefDK's ruby to the shell environment" do
52
52
  command_instance.run(argv)
53
- expect(stdout_io.string).to eq(expected_environment_commands)
53
+ expect(stdout_io.string).to include(expected_environment_commands)
54
+ end
55
+
56
+ it "does not emit any empty lines", :if => ["powershell", "posh"].include?(shell) do
57
+ command_instance.run(argv)
58
+ stdout_io.string.each_line do |s|
59
+ expect(s.strip).not_to be_empty
60
+ end
54
61
  end
55
62
  end
56
63
 
@@ -64,7 +71,14 @@ describe ChefDK::Command::ShellInit do
64
71
 
65
72
  it "emits a script to add ChefDK's ruby to the shell environment" do
66
73
  command_instance.run(argv)
67
- expect(stdout_io.string).to eq(expected_environment_commands)
74
+ expect(stdout_io.string).to include(expected_environment_commands)
75
+ end
76
+
77
+ it "does not emit any empty lines", :if => ["powershell", "posh"].include?(shell) do
78
+ command_instance.run(argv)
79
+ stdout_io.string.each_line do |s|
80
+ expect(s.strip).not_to be_empty
81
+ end
68
82
  end
69
83
  end
70
84
  end
@@ -101,9 +115,118 @@ EOH
101
115
  include_context "shell init script", shell
102
116
  end
103
117
 
104
- ['bash', 'sh', 'zsh'].each do |shell|
105
- context "for #{shell}" do
106
- it_behaves_like "a posix shell script", shell
118
+ context "for sh" do
119
+ it_behaves_like "a posix shell script", "sh"
120
+ end
121
+
122
+ context "for bash" do
123
+ it_behaves_like "a posix shell script", "bash"
124
+
125
+ describe "generating auto-complete" do
126
+
127
+ let(:command_descriptions) do
128
+ {
129
+ "exec" => "Runs the command in context of the embedded ruby",
130
+ "env" => "Prints environment variables used by ChefDK",
131
+ "gem" => "Runs the `gem` command in context of the embedded ruby",
132
+ "generate" => "Generate a new app, cookbook, or component"
133
+ }
134
+ end
135
+
136
+ let(:omnibus_bin_dir) { "/foo/bin" }
137
+ let(:omnibus_embedded_bin_dir) { "/foo/embedded/bin" }
138
+
139
+ let(:argv) { [ "bash" ] }
140
+
141
+ let(:expected_completion_function) do
142
+ <<-END_COMPLETION
143
+ _chef_comp() {
144
+ local COMMANDS="exec env gem generate"
145
+ COMPREPLY=($(compgen -W "$COMMANDS" -- ${COMP_WORDS[COMP_CWORD]} ))
146
+ }
147
+ complete -F _chef_comp chef
148
+ END_COMPLETION
149
+ end
150
+
151
+ before do
152
+ # Stub this or else we'd have to update the test every time a new command
153
+ # is added.
154
+ allow(command_instance.shell_completion_template_context).to receive(:commands).
155
+ and_return(command_descriptions)
156
+
157
+ allow(command_instance).to receive(:omnibus_embedded_bin_dir).and_return(omnibus_embedded_bin_dir)
158
+ allow(command_instance).to receive(:omnibus_bin_dir).and_return(omnibus_bin_dir)
159
+ end
160
+
161
+ it "generates a completion function for the chef command" do
162
+ command_instance.run(argv)
163
+ expect(stdout_io.string).to include(expected_completion_function)
164
+ end
165
+
166
+ end
167
+ end
168
+
169
+ context "for zsh" do
170
+
171
+ it_behaves_like "a posix shell script", "zsh"
172
+
173
+ describe "generating auto-complete" do
174
+
175
+ let(:command_descriptions) do
176
+ {
177
+ "exec" => "Runs the command in context of the embedded ruby",
178
+ "env" => "Prints environment variables used by ChefDK",
179
+ "gem" => "Runs the `gem` command in context of the embedded ruby",
180
+ "generate" => "Generate a new app, cookbook, or component"
181
+ }
182
+ end
183
+
184
+ let(:omnibus_bin_dir) { "/foo/bin" }
185
+ let(:omnibus_embedded_bin_dir) { "/foo/embedded/bin" }
186
+
187
+ let(:argv) { [ "zsh" ] }
188
+
189
+ let(:expected_completion_function) do
190
+ <<-END_COMPLETION
191
+ function _chef() {
192
+
193
+ local -a _1st_arguments
194
+ _1st_arguments=(
195
+ 'exec:Runs the command in context of the embedded ruby'
196
+ 'env:Prints environment variables used by ChefDK'
197
+ 'gem:Runs the `gem` command in context of the embedded ruby'
198
+ 'generate:Generate a new app, cookbook, or component'
199
+ )
200
+
201
+ _arguments \\
202
+ '(-v --version)'{-v,--version}'[version information]' \\
203
+ '*:: :->subcmds' && return 0
204
+
205
+ if (( CURRENT == 1 )); then
206
+ _describe -t commands "chef subcommand" _1st_arguments
207
+ return
208
+ fi
209
+ }
210
+
211
+ compdef _chef chef
212
+
213
+ END_COMPLETION
214
+ end
215
+
216
+ before do
217
+ # Stub this or else we'd have to update the test every time a new command
218
+ # is added.
219
+ allow(command_instance.shell_completion_template_context).to receive(:commands).
220
+ and_return(command_descriptions)
221
+
222
+ allow(command_instance).to receive(:omnibus_embedded_bin_dir).and_return(omnibus_embedded_bin_dir)
223
+ allow(command_instance).to receive(:omnibus_bin_dir).and_return(omnibus_bin_dir)
224
+ end
225
+
226
+ it "generates a completion function for the chef command" do
227
+ command_instance.run(argv)
228
+ expect(stdout_io.string).to include(expected_completion_function)
229
+ end
107
230
  end
108
231
  end
109
232
 
@@ -122,6 +245,54 @@ EOH
122
245
  end
123
246
 
124
247
  include_context 'shell init script', 'fish'
248
+
249
+ describe "generating auto-complete" do
250
+
251
+ let(:command_descriptions) do
252
+ {
253
+ "exec" => "Runs the command in context of the embedded ruby",
254
+ "env" => "Prints environment variables used by ChefDK",
255
+ "gem" => "Runs the `gem` command in context of the embedded ruby",
256
+ "generate" => "Generate a new app, cookbook, or component"
257
+ }
258
+ end
259
+
260
+ let(:omnibus_bin_dir) { "/foo/bin" }
261
+ let(:omnibus_embedded_bin_dir) { "/foo/embedded/bin" }
262
+
263
+ let(:argv) { [ "fish" ] }
264
+
265
+ let(:expected_completion_function) do
266
+ <<-END_COMPLETION
267
+ # Fish Shell command-line completions for ChefDK
268
+
269
+ function __fish_chef_no_command --description 'Test if chef has yet to be given the main command'
270
+ set -l cmd (commandline -opc)
271
+ test (count $cmd) -eq 1
272
+ end
273
+
274
+ complete -c chef -f -n '__fish_chef_no_command' -a exec -d "Runs the command in context of the embedded ruby"
275
+ complete -c chef -f -n '__fish_chef_no_command' -a env -d "Prints environment variables used by ChefDK"
276
+ complete -c chef -f -n '__fish_chef_no_command' -a gem -d "Runs the `gem` command in context of the embedded ruby"
277
+ complete -c chef -f -n '__fish_chef_no_command' -a generate -d "Generate a new app, cookbook, or component"
278
+ END_COMPLETION
279
+ end
280
+
281
+ before do
282
+ # Stub this or else we'd have to update the test every time a new command
283
+ # is added.
284
+ allow(command_instance.shell_completion_template_context).to receive(:commands).
285
+ and_return(command_descriptions)
286
+
287
+ allow(command_instance).to receive(:omnibus_embedded_bin_dir).and_return(omnibus_embedded_bin_dir)
288
+ allow(command_instance).to receive(:omnibus_bin_dir).and_return(omnibus_bin_dir)
289
+ end
290
+
291
+ it "generates a completion function for the chef command" do
292
+ command_instance.run(argv)
293
+ expect(stdout_io.string).to include(expected_completion_function)
294
+ end
295
+ end
125
296
  end
126
297
 
127
298
  ['powershell', 'posh'].each do |shell|
@@ -0,0 +1,246 @@
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 'shared/command_with_ui_object'
20
+ require 'chef-dk/command/undelete'
21
+
22
+ describe ChefDK::Command::Undelete do
23
+
24
+ it_behaves_like "a command with a UI object"
25
+
26
+ subject(:command) do
27
+ described_class.new
28
+ end
29
+
30
+ let(:undelete_service) { command.undelete_service }
31
+
32
+ let(:chef_config_loader) { instance_double("Chef::WorkstationConfigLoader") }
33
+
34
+ let(:chef_config) { double("Chef::Config") }
35
+
36
+ # nil means the config loader will do the default path lookup
37
+ let(:config_arg) { nil }
38
+
39
+ before do
40
+ stub_const("Chef::Config", chef_config)
41
+ allow(Chef::WorkstationConfigLoader).to receive(:new).with(config_arg).and_return(chef_config_loader)
42
+ end
43
+
44
+ describe "parsing args and options" do
45
+ let(:params) { [] }
46
+
47
+ let(:ui) { TestHelpers::TestUI.new }
48
+
49
+ before do
50
+ command.ui = ui
51
+ command.apply_params!(params)
52
+ end
53
+
54
+ context "when given a path to the config" do
55
+
56
+ let(:params) { %w[ -c ~/otherstuff/config.rb ] }
57
+
58
+ let(:config_arg) { "~/otherstuff/config.rb" }
59
+
60
+ before do
61
+ expect(chef_config_loader).to receive(:load)
62
+ end
63
+
64
+ it "reads the chef/knife config" do
65
+ expect(Chef::WorkstationConfigLoader).to receive(:new).with(config_arg).and_return(chef_config_loader)
66
+ expect(command.chef_config).to eq(chef_config)
67
+ expect(undelete_service.chef_config).to eq(chef_config)
68
+ end
69
+
70
+ end
71
+
72
+ describe "settings that require loading chef config" do
73
+
74
+ before do
75
+ allow(chef_config_loader).to receive(:load)
76
+ end
77
+
78
+ context "with no params" do
79
+
80
+ it "disables debug by default" do
81
+ expect(command.debug?).to be(false)
82
+ end
83
+
84
+ it "enables listing undo records" do
85
+ expect(command.list_undo_records?).to be(true)
86
+ end
87
+
88
+ end
89
+
90
+ context "when debug mode is set" do
91
+
92
+ let(:params) { [ "-D" ] }
93
+
94
+ it "enables debug" do
95
+ expect(command.debug?).to be(true)
96
+ end
97
+
98
+ end
99
+
100
+ context "when --last is given" do
101
+
102
+ let(:params) { %w[ -l ] }
103
+
104
+ it "disables list mode" do
105
+ expect(command.list_undo_records?).to be(false)
106
+ end
107
+
108
+ it "has no undo id" do
109
+ expect(command.undo_record_id).to be_nil
110
+ expect(command.undelete_service.undo_record_id).to be_nil
111
+ end
112
+
113
+ end
114
+
115
+ context "when given a undo record id via --id" do
116
+
117
+ let(:undo_id) { "20150827180422" }
118
+
119
+ let(:params) { [ "-i", undo_id ] }
120
+
121
+ it "disables list mode" do
122
+ expect(command.list_undo_records?).to be(false)
123
+ end
124
+
125
+ it "is configured to perform undo for the given undo id" do
126
+ expect(command.undo_record_id).to eq(undo_id)
127
+ expect(command.undelete_service.undo_record_id).to eq(undo_id)
128
+ end
129
+
130
+ end
131
+
132
+ context "when exclusive options --last and --id are given" do
133
+
134
+ let(:params) { %w[ --last --id foo ] }
135
+
136
+ it "emits an error message saying they are exclusive and exits" do
137
+ expect(ui.output).to include("Error: options --last and --id cannot both be given.")
138
+ expect(ui.output).to include(command.opt_parser.to_s)
139
+ end
140
+
141
+ end
142
+
143
+ end
144
+ end
145
+
146
+
147
+ describe "running the command" do
148
+
149
+ let(:ui) { TestHelpers::TestUI.new }
150
+
151
+ before do
152
+ allow(chef_config_loader).to receive(:load)
153
+ command.ui = ui
154
+ end
155
+
156
+ context "when given too many arguments" do
157
+
158
+ let(:params) { %w[ extra-thing ] }
159
+
160
+ it "shows usage and exits" do
161
+ expect(command.run(params)).to eq(1)
162
+ end
163
+
164
+ end
165
+
166
+ describe "running the command in list mode" do
167
+
168
+ let(:params) { [] }
169
+
170
+ it "lists the undo operations" do
171
+ expect(command.undelete_service).to receive(:list)
172
+ expect(command.run(params)).to eq(0)
173
+ end
174
+
175
+ end
176
+
177
+ context "when the undelete service raises an exception" do
178
+
179
+ let(:params) { %w[ --last ] }
180
+
181
+ let(:backtrace) { caller[0...3] }
182
+
183
+ let(:cause) do
184
+ e = StandardError.new("some operation failed")
185
+ e.set_backtrace(backtrace)
186
+ e
187
+ end
188
+
189
+ let(:exception) do
190
+ ChefDK::UndeleteError.new("Failed to undelete.", cause)
191
+ end
192
+
193
+ before do
194
+ allow(command.undelete_service).to receive(:run).and_raise(exception)
195
+ end
196
+
197
+ it "prints a debugging message and exits non-zero" do
198
+ expect(command.run(params)).to eq(1)
199
+
200
+ expected_output=<<-E
201
+ Error: Failed to undelete.
202
+ Reason: (StandardError) some operation failed
203
+
204
+ E
205
+
206
+ expect(ui.output).to eq(expected_output)
207
+ end
208
+
209
+ context "when debug is enabled" do
210
+
211
+ it "includes the backtrace in the error" do
212
+
213
+ command.run(params + %w[ -D ])
214
+
215
+ expected_output=<<-E
216
+ Error: Failed to undelete.
217
+ Reason: (StandardError) some operation failed
218
+
219
+
220
+ E
221
+ expected_output << backtrace.join("\n") << "\n"
222
+
223
+ expect(ui.output).to eq(expected_output)
224
+ end
225
+
226
+ end
227
+
228
+ end
229
+
230
+ context "when the undelete service executes successfully" do
231
+
232
+ let(:params) { %w[ --last ] }
233
+
234
+ before do
235
+ expect(command.undelete_service).to receive(:run)
236
+ end
237
+
238
+ it "exits 0" do
239
+ expect(command.run(params)).to eq(0)
240
+ end
241
+
242
+ end
243
+
244
+ end
245
+ end
246
+