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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +2 -2
- data/README.md +25 -0
- data/lib/chef-dk/builtin_commands.rb +4 -0
- data/lib/chef-dk/cli.rb +46 -0
- data/lib/chef-dk/command/base.rb +4 -0
- data/lib/chef-dk/command/generator_commands/template.rb +2 -1
- data/lib/chef-dk/command/install.rb +105 -0
- data/lib/chef-dk/command/push.rb +123 -0
- data/lib/chef-dk/cookbook_profiler/identifiers.rb +5 -0
- data/lib/chef-dk/exceptions.rb +38 -0
- data/lib/chef-dk/generator.rb +16 -1
- data/lib/chef-dk/helpers.rb +1 -1
- data/lib/chef-dk/policyfile/cookbook_location_specification.rb +4 -0
- data/lib/chef-dk/policyfile/cookbook_locks.rb +73 -0
- data/lib/chef-dk/policyfile/reports/install.rb +70 -0
- data/lib/chef-dk/policyfile/reports/table_printer.rb +58 -0
- data/lib/chef-dk/policyfile/reports/upload.rb +70 -0
- data/lib/chef-dk/policyfile/solution_dependencies.rb +102 -8
- data/lib/chef-dk/policyfile/uploader.rb +37 -6
- data/lib/chef-dk/policyfile_compiler.rb +19 -5
- data/lib/chef-dk/policyfile_lock.rb +122 -9
- data/lib/chef-dk/policyfile_services/install.rb +131 -0
- data/lib/chef-dk/policyfile_services/push.rb +121 -0
- data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +6 -4
- data/lib/chef-dk/ui.rb +50 -0
- data/lib/chef-dk/version.rb +1 -1
- data/spec/shared/a_file_generator.rb +4 -1
- data/spec/test_helpers.rb +21 -0
- data/spec/unit/cli_spec.rb +100 -1
- data/spec/unit/command/base_spec.rb +23 -0
- data/spec/unit/command/exec_spec.rb +2 -2
- data/spec/unit/command/install_spec.rb +159 -0
- data/spec/unit/command/push_spec.rb +203 -0
- data/spec/unit/command/shell_init_spec.rb +1 -1
- data/spec/unit/policyfile/cookbook_location_specification_spec.rb +7 -0
- data/spec/unit/policyfile/cookbook_locks_spec.rb +13 -2
- data/spec/unit/policyfile/reports/install_spec.rb +115 -0
- data/spec/unit/policyfile/reports/upload_spec.rb +96 -0
- data/spec/unit/policyfile/solution_dependencies_spec.rb +1 -1
- data/spec/unit/policyfile/uploader_spec.rb +9 -12
- data/spec/unit/policyfile_lock_serialization_spec.rb +292 -0
- data/spec/unit/policyfile_services/install_spec.rb +170 -0
- data/spec/unit/policyfile_services/push_spec.rb +202 -0
- 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
|
+
|
@@ -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
|
+
|