chef-dk 0.2.1 → 0.3.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +2 -2
  3. data/README.md +25 -0
  4. data/lib/chef-dk/builtin_commands.rb +4 -0
  5. data/lib/chef-dk/cli.rb +46 -0
  6. data/lib/chef-dk/command/base.rb +4 -0
  7. data/lib/chef-dk/command/generator_commands/template.rb +2 -1
  8. data/lib/chef-dk/command/install.rb +105 -0
  9. data/lib/chef-dk/command/push.rb +123 -0
  10. data/lib/chef-dk/cookbook_profiler/identifiers.rb +5 -0
  11. data/lib/chef-dk/exceptions.rb +38 -0
  12. data/lib/chef-dk/generator.rb +16 -1
  13. data/lib/chef-dk/helpers.rb +1 -1
  14. data/lib/chef-dk/policyfile/cookbook_location_specification.rb +4 -0
  15. data/lib/chef-dk/policyfile/cookbook_locks.rb +73 -0
  16. data/lib/chef-dk/policyfile/reports/install.rb +70 -0
  17. data/lib/chef-dk/policyfile/reports/table_printer.rb +58 -0
  18. data/lib/chef-dk/policyfile/reports/upload.rb +70 -0
  19. data/lib/chef-dk/policyfile/solution_dependencies.rb +102 -8
  20. data/lib/chef-dk/policyfile/uploader.rb +37 -6
  21. data/lib/chef-dk/policyfile_compiler.rb +19 -5
  22. data/lib/chef-dk/policyfile_lock.rb +122 -9
  23. data/lib/chef-dk/policyfile_services/install.rb +131 -0
  24. data/lib/chef-dk/policyfile_services/push.rb +121 -0
  25. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +6 -4
  26. data/lib/chef-dk/ui.rb +50 -0
  27. data/lib/chef-dk/version.rb +1 -1
  28. data/spec/shared/a_file_generator.rb +4 -1
  29. data/spec/test_helpers.rb +21 -0
  30. data/spec/unit/cli_spec.rb +100 -1
  31. data/spec/unit/command/base_spec.rb +23 -0
  32. data/spec/unit/command/exec_spec.rb +2 -2
  33. data/spec/unit/command/install_spec.rb +159 -0
  34. data/spec/unit/command/push_spec.rb +203 -0
  35. data/spec/unit/command/shell_init_spec.rb +1 -1
  36. data/spec/unit/policyfile/cookbook_location_specification_spec.rb +7 -0
  37. data/spec/unit/policyfile/cookbook_locks_spec.rb +13 -2
  38. data/spec/unit/policyfile/reports/install_spec.rb +115 -0
  39. data/spec/unit/policyfile/reports/upload_spec.rb +96 -0
  40. data/spec/unit/policyfile/solution_dependencies_spec.rb +1 -1
  41. data/spec/unit/policyfile/uploader_spec.rb +9 -12
  42. data/spec/unit/policyfile_lock_serialization_spec.rb +292 -0
  43. data/spec/unit/policyfile_services/install_spec.rb +170 -0
  44. data/spec/unit/policyfile_services/push_spec.rb +202 -0
  45. metadata +48 -6
@@ -0,0 +1,203 @@
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/command/push'
20
+
21
+ describe ChefDK::Command::Push do
22
+
23
+ let(:policy_group) { "dev" }
24
+
25
+ let(:params) { [policy_group] }
26
+
27
+ let(:command) do
28
+ described_class.new
29
+ end
30
+
31
+ let(:push_service) { instance_double(ChefDK::PolicyfileServices::Push) }
32
+
33
+ let(:chef_config_loader) { instance_double("Chef::WorkstationConfigLoader") }
34
+
35
+ let(:chef_config) { double("Chef::Config") }
36
+
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
+ context "after evaluating params" do
45
+
46
+ before do
47
+ command.apply_params!(params)
48
+ end
49
+
50
+ it "disables debug by default" do
51
+ expect(command.debug?).to be(false)
52
+ end
53
+
54
+ it "configures a default UI component" do
55
+ ui = command.ui
56
+ expect(ui.out_stream).to eq($stdout)
57
+ expect(ui.err_stream).to eq($stderr)
58
+ end
59
+
60
+ describe "when configuring components that depend on chef config" do
61
+
62
+ before do
63
+ expect(chef_config_loader).to receive(:load)
64
+ end
65
+
66
+ it "reads the chef/knife config" do
67
+ expect(command.chef_config).to eq(chef_config)
68
+ end
69
+
70
+ it "configures the Push service" do
71
+ expect(ChefDK::PolicyfileServices::Push).to receive(:new).
72
+ with(policyfile: nil, ui: command.ui, policy_group: policy_group, config: chef_config, root_dir: Dir.pwd).
73
+ and_return(push_service)
74
+ expect(command.push).to eq(push_service)
75
+ end
76
+
77
+ context "and an explicit Policyfile is given" do
78
+
79
+ let(:params) { [policy_group, "MyPolicy.rb"] }
80
+
81
+ it "configures the Push service with the given Policyfile" do
82
+ expect(ChefDK::PolicyfileServices::Push).to receive(:new).
83
+ with(policyfile: "MyPolicy.rb", ui: command.ui, policy_group: policy_group, config: chef_config, root_dir: Dir.pwd).
84
+ and_return(push_service)
85
+ expect(command.push).to eq(push_service)
86
+ end
87
+
88
+ end
89
+ end
90
+
91
+ context "when debug mode is set" do
92
+
93
+ let(:params) { [ policy_group, "-D" ] }
94
+
95
+ it "enables debug" do
96
+ expect(command.debug?).to be(true)
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+
103
+ describe "running the push operation" do
104
+
105
+ let(:ui) { TestHelpers::TestUI.new }
106
+
107
+ before do
108
+ command.ui = ui
109
+ end
110
+
111
+ context "when invoked without arguments" do
112
+
113
+ let(:params) { [] }
114
+
115
+ it "prints the banner and returns 1" do
116
+ expect(command.run).to eq(1)
117
+ end
118
+
119
+ end
120
+
121
+ context "with valid arguments" do
122
+
123
+ before do
124
+ expect(command).to receive(:push).and_return(push_service)
125
+ end
126
+
127
+ context "when the push is successful" do
128
+
129
+ before do
130
+ expect(push_service).to receive(:run)
131
+ end
132
+
133
+ it "returns 0" do
134
+ expect(command.run(params)).to eq(0)
135
+ end
136
+
137
+ end
138
+
139
+ context "when the push operation raises an exception" do
140
+
141
+ let(:backtrace) { caller[0...3] }
142
+
143
+ let(:cause) do
144
+ e = StandardError.new("some operation failed")
145
+ e.set_backtrace(backtrace)
146
+ e
147
+ end
148
+
149
+ let(:exception) do
150
+ ChefDK::PolicyfilePushError.new("install failed", cause)
151
+ end
152
+
153
+ before do
154
+ expect(push_service).to receive(:run).and_raise(exception)
155
+ end
156
+
157
+ it "exits 1" do
158
+ expect(command.run(params)).to eq(1)
159
+ end
160
+
161
+ it "describes the error" do
162
+ command.run(params)
163
+
164
+ expected_output=<<-E
165
+ Error: install failed
166
+ Reason: StandardError
167
+
168
+ some operation failed
169
+ E
170
+
171
+ expect(ui.output).to eq(expected_output)
172
+ end
173
+
174
+ context "when debug is enabled" do
175
+
176
+ before do
177
+ params << "-D"
178
+ end
179
+
180
+ it "includes the backtrace in the error" do
181
+
182
+ command.run(params)
183
+
184
+ expected_output=<<-E
185
+ Error: install failed
186
+ Reason: StandardError
187
+
188
+ some operation failed
189
+ E
190
+ expected_output << backtrace.join("\n") << "\n"
191
+
192
+ expect(ui.output).to eq(expected_output)
193
+ end
194
+
195
+ end
196
+
197
+ end
198
+ end
199
+
200
+ end
201
+
202
+ end
203
+
@@ -38,7 +38,7 @@ describe ChefDK::Command::ShellInit do
38
38
 
39
39
  let(:expected_gem_root) { Gem.default_dir.to_s }
40
40
 
41
- let(:expected_gem_home) { ENV['GEM_HOME'] }
41
+ let(:expected_gem_home) { Gem.user_dir }
42
42
 
43
43
  let(:expected_gem_path) { Gem.path.join(':') }
44
44
 
@@ -87,6 +87,13 @@ describe ChefDK::Policyfile::CookbookLocationSpecification do
87
87
  expect(cookbook_location_spec.installer).to eq(installer)
88
88
  end
89
89
 
90
+ it "delegates #installed? to the installer" do
91
+ expect(installer).to receive(:installed?).and_return(false)
92
+ expect(cookbook_location_spec).to_not be_installed
93
+ expect(installer).to receive(:installed?).and_return(true)
94
+ expect(cookbook_location_spec).to be_installed
95
+ end
96
+
90
97
  it "delegates installation to the installer" do
91
98
  expect(installer).to receive(:installed?).and_return(false)
92
99
  expect(installer).to receive(:install)
@@ -106,6 +106,14 @@ shared_examples_for "Cookbook Lock" do
106
106
  expect(cookbook_lock.dependencies).to eq(deps)
107
107
  end
108
108
 
109
+ it "delegates #installed? to the CookbookLocationSpecification" do
110
+ location_spec = cookbook_lock.cookbook_location_spec
111
+ expect(location_spec).to receive(:installed?).and_return(true)
112
+ expect(cookbook_lock).to be_installed
113
+ expect(location_spec).to receive(:installed?).and_return(false)
114
+ expect(cookbook_lock).to_not be_installed
115
+ end
116
+
109
117
  end
110
118
 
111
119
  context "when created from lock data" do
@@ -115,7 +123,9 @@ shared_examples_for "Cookbook Lock" do
115
123
  "identifier" => "my-opaque-id",
116
124
  "dotted_decimal_identifier" => "123.456.789",
117
125
  "version" => "1.2.3",
118
- "source_options" => { "sourcekey" => "location info" }
126
+ "source_options" => { "sourcekey" => "location info" },
127
+ "cache_key" => nil,
128
+ "source" => "cookbooks_local_path"
119
129
  }
120
130
  end
121
131
 
@@ -244,7 +254,8 @@ describe ChefDK::Policyfile::LocalCookbook do
244
254
  "source" => "../my_repo/nginx",
245
255
  "source_options" => {
246
256
  "path" => "../my_repo/nginx"
247
- }
257
+ },
258
+ "cache_key" => nil
248
259
  }
249
260
  end
250
261
 
@@ -0,0 +1,115 @@
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/reports/install'
20
+
21
+ # Used for verifying doubles
22
+ require 'chef-dk/policyfile_compiler'
23
+ require 'chef-dk/policyfile/cookbook_location_specification'
24
+
25
+ describe ChefDK::Policyfile::Reports::Install do
26
+
27
+ let(:ui) { TestHelpers::TestUI.new }
28
+
29
+ let(:policyfile_compiler) { instance_double("ChefDK::PolicyfileCompiler") }
30
+
31
+ subject(:install_report) { described_class.new(ui: ui, policyfile_compiler: policyfile_compiler ) }
32
+
33
+ it "has a UI object" do
34
+ expect(install_report.ui).to eq(ui)
35
+ end
36
+
37
+ it "has a policyfile compiler" do
38
+ expect(install_report.policyfile_compiler).to eq(policyfile_compiler)
39
+ end
40
+
41
+ describe "when printing an installation report for fixed version cookbooks" do
42
+
43
+ let(:fixed_version_cookbook_one) do
44
+ instance_double("ChefDK::Policyfile::CookbookLocationSpecification",
45
+ installed?: false,
46
+ name: "short-name",
47
+ version_constraint: ">= 0.0.0",
48
+ source_type: :git)
49
+ end
50
+
51
+ let(:fixed_version_cookbook_two) do
52
+ instance_double("ChefDK::Policyfile::CookbookLocationSpecification",
53
+ installed?: true,
54
+ name: "this-name-is-longer",
55
+ version_constraint: "~> 10.0.0",
56
+ source_type: :path)
57
+ end
58
+
59
+ let(:fixed_version_cookbooks) do
60
+ { "short-name" => fixed_version_cookbook_one, "this-name-is-longer" => fixed_version_cookbook_two }
61
+ end
62
+
63
+ before do
64
+ allow(policyfile_compiler).to receive(:fixed_version_cookbooks_specs).and_return(fixed_version_cookbooks)
65
+ end
66
+
67
+ it "prints a table-ized message for cookbooks being installed" do
68
+ install_report.installing_fixed_version_cookbook(fixed_version_cookbook_one)
69
+ expect(ui.output).to eq("Installing short-name >= 0.0.0 from git\n")
70
+ end
71
+
72
+ it "prints a table-ized message for cookbooks in the cache that are reused" do
73
+ install_report.installing_fixed_version_cookbook(fixed_version_cookbook_two)
74
+ expect(ui.output).to eq("Using this-name-is-longer ~> 10.0.0 from path\n")
75
+ end
76
+
77
+ end
78
+
79
+ describe "when printing an installation report for normal dependencies" do
80
+
81
+ let(:cookbook_one) do
82
+ instance_double("ChefDK::Policyfile::CookbookLocationSpecification",
83
+ installed?: false,
84
+ name: "short-name",
85
+ version_constraint: Semverse::Constraint.new("= 10.0.4"))
86
+ end
87
+
88
+ let(:cookbook_two) do
89
+ instance_double("ChefDK::Policyfile::CookbookLocationSpecification",
90
+ installed?: true,
91
+ name: "this-name-is-longer",
92
+ version_constraint: Semverse::Constraint.new("= 1.2.3"))
93
+ end
94
+
95
+ let(:graph_solution_cookbooks) do
96
+ { "short-name" => "10.0.4", "this-name-is-longer" => "1.2.3" }
97
+ end
98
+
99
+ before do
100
+ allow(policyfile_compiler).to receive(:graph_solution).and_return(graph_solution_cookbooks)
101
+ end
102
+
103
+ it "prints a table-ized message for cookbooks being installed" do
104
+ install_report.installing_cookbook(cookbook_one)
105
+ expect(ui.output).to eq("Installing short-name 10.0.4\n")
106
+ end
107
+
108
+ it "prints a table-ized message for cookbooks in the cache that are reused" do
109
+ install_report.installing_cookbook(cookbook_two)
110
+ expect(ui.output).to eq("Using this-name-is-longer 1.2.3\n")
111
+ end
112
+
113
+ end
114
+ end
115
+
@@ -0,0 +1,96 @@
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/reports/upload'
20
+
21
+ # For the LockedCookbookForUpload class:
22
+ require 'chef-dk/policyfile/uploader'
23
+
24
+ # Used for verifying doubles
25
+ require 'chef-dk/policyfile/cookbook_locks'
26
+
27
+ describe ChefDK::Policyfile::Reports::Upload do
28
+
29
+ let(:ui) { TestHelpers::TestUI.new }
30
+
31
+ let(:reused_cookbooks) { [] }
32
+
33
+ let(:uploaded_cookbooks) { [] }
34
+
35
+ subject(:upload_report) { described_class.new(ui: ui, reused_cbs: reused_cookbooks, uploaded_cbs: uploaded_cookbooks) }
36
+
37
+ it "has a ui object" do
38
+ expect(upload_report.ui).to eq(ui)
39
+ end
40
+
41
+ it "has a list of cookbooks that are being uploaded" do
42
+ expect(upload_report.uploaded_cbs).to equal(uploaded_cookbooks)
43
+ end
44
+
45
+ it "has a list of cookbooks that would be uploaded but are already on the server" do
46
+ expect(upload_report.reused_cbs).to equal(reused_cookbooks)
47
+ end
48
+
49
+ describe "reporting uploaded and reused cookbooks" do
50
+
51
+ def cb_with_lock(name, version, identifier)
52
+ lock = instance_double("ChefDK::Policyfile::CookbookLock",
53
+ name: name,
54
+ version: version,
55
+ identifier: identifier)
56
+
57
+ ChefDK::Policyfile::Uploader::LockedCookbookForUpload.new(nil, lock)
58
+ end
59
+
60
+ let(:cookbook_one) do
61
+ cb_with_lock("short-name", "10.11.12", "49582c3db4e3b54674ecfb57fe82157720350274")
62
+ end
63
+
64
+ let(:cookbook_two) do
65
+ cb_with_lock("a-longer-named-cookbook", "1.0.0", "e4ac353bebdc949cd2cd8ce69983a56b96917dfa")
66
+ end
67
+
68
+ let(:reused_cookbooks) { [ cookbook_one, cookbook_two ] }
69
+
70
+ let(:cookbook_three) do
71
+ cb_with_lock("foo", "1.2.42", "cb61daebfb0d255cae928ca1a92db29b055755cf")
72
+ end
73
+
74
+ let(:cookbook_four) do
75
+ cb_with_lock("barbazqux", "12.34.5678", "1241ea6f9866d0e61d11129bb32e5fc96cd2bac0")
76
+ end
77
+
78
+ let(:uploaded_cookbooks) { [ cookbook_three, cookbook_four ] }
79
+
80
+ it "prints a table showing the re-used and uploaded cookbooks" do
81
+ upload_report.show
82
+
83
+ expected_output = <<-E
84
+ Using short-name 10.11.12 (49582c3d)
85
+ Using a-longer-named-cookbook 1.0.0 (e4ac353b)
86
+ Uploaded foo 1.2.42 (cb61daeb)
87
+ Uploaded barbazqux 12.34.5678 (1241ea6f)
88
+ E
89
+ expect(ui.output).to eq(expected_output)
90
+ end
91
+
92
+ end
93
+
94
+ end
95
+
96
+