chef-dk 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +192 -0
  3. data/LICENSE +201 -0
  4. data/README.md +198 -0
  5. data/Rakefile +18 -0
  6. data/bin/chef +25 -0
  7. data/lib/chef-dk.rb +19 -0
  8. data/lib/chef-dk/builtin_commands.rb +31 -0
  9. data/lib/chef-dk/chef_runner.rb +83 -0
  10. data/lib/chef-dk/cli.rb +135 -0
  11. data/lib/chef-dk/command/base.rb +71 -0
  12. data/lib/chef-dk/command/exec.rb +33 -0
  13. data/lib/chef-dk/command/gem.rb +47 -0
  14. data/lib/chef-dk/command/generate.rb +97 -0
  15. data/lib/chef-dk/command/generator_commands.rb +417 -0
  16. data/lib/chef-dk/command/shell_init.rb +80 -0
  17. data/lib/chef-dk/command/verify.rb +226 -0
  18. data/lib/chef-dk/commands_map.rb +115 -0
  19. data/lib/chef-dk/component_test.rb +142 -0
  20. data/lib/chef-dk/cookbook_metadata.rb +36 -0
  21. data/lib/chef-dk/cookbook_omnifetch.rb +29 -0
  22. data/lib/chef-dk/cookbook_profiler/git.rb +95 -0
  23. data/lib/chef-dk/cookbook_profiler/identifiers.rb +79 -0
  24. data/lib/chef-dk/cookbook_profiler/null_scm.rb +32 -0
  25. data/lib/chef-dk/exceptions.rb +46 -0
  26. data/lib/chef-dk/generator.rb +70 -0
  27. data/lib/chef-dk/helpers.rb +95 -0
  28. data/lib/chef-dk/policyfile/chef_server_cookbook_source.rb +46 -0
  29. data/lib/chef-dk/policyfile/community_cookbook_source.rb +84 -0
  30. data/lib/chef-dk/policyfile/cookbook_sources.rb +20 -0
  31. data/lib/chef-dk/policyfile/cookbook_spec.rb +96 -0
  32. data/lib/chef-dk/policyfile/dsl.rb +148 -0
  33. data/lib/chef-dk/policyfile/null_cookbook_source.rb +37 -0
  34. data/lib/chef-dk/policyfile_compiler.rb +217 -0
  35. data/lib/chef-dk/policyfile_lock.rb +243 -0
  36. data/lib/chef-dk/shell_out.rb +36 -0
  37. data/lib/chef-dk/skeletons/code_generator/files/default/Berksfile +3 -0
  38. data/lib/chef-dk/skeletons/code_generator/files/default/chefignore +96 -0
  39. data/lib/chef-dk/skeletons/code_generator/files/default/converge_spec.rb +9 -0
  40. data/lib/chef-dk/skeletons/code_generator/files/default/gitignore +16 -0
  41. data/lib/chef-dk/skeletons/code_generator/files/default/spec_helper.rb +8 -0
  42. data/lib/chef-dk/skeletons/code_generator/metadata.rb +8 -0
  43. data/lib/chef-dk/skeletons/code_generator/recipes/app.rb +65 -0
  44. data/lib/chef-dk/skeletons/code_generator/recipes/attribute.rb +12 -0
  45. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +50 -0
  46. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook_file.rb +24 -0
  47. data/lib/chef-dk/skeletons/code_generator/recipes/lwrp.rb +23 -0
  48. data/lib/chef-dk/skeletons/code_generator/recipes/recipe.rb +9 -0
  49. data/lib/chef-dk/skeletons/code_generator/recipes/template.rb +32 -0
  50. data/lib/chef-dk/skeletons/code_generator/templates/default/README.md.erb +4 -0
  51. data/lib/chef-dk/skeletons/code_generator/templates/default/attribute.rb.erb +0 -0
  52. data/lib/chef-dk/skeletons/code_generator/templates/default/cookbook_file.erb +0 -0
  53. data/lib/chef-dk/skeletons/code_generator/templates/default/default_recipe.rb.erb +8 -0
  54. data/lib/chef-dk/skeletons/code_generator/templates/default/kitchen.yml.erb +16 -0
  55. data/lib/chef-dk/skeletons/code_generator/templates/default/metadata.rb.erb +8 -0
  56. data/lib/chef-dk/skeletons/code_generator/templates/default/provider.rb.erb +0 -0
  57. data/lib/chef-dk/skeletons/code_generator/templates/default/recipe.rb.erb +0 -0
  58. data/lib/chef-dk/skeletons/code_generator/templates/default/resource.rb.erb +0 -0
  59. data/lib/chef-dk/skeletons/code_generator/templates/default/template.erb +0 -0
  60. data/lib/chef-dk/version.rb +20 -0
  61. data/spec/shared/setup_git_cookbooks.rb +53 -0
  62. data/spec/spec_helper.rb +32 -0
  63. data/spec/test_helpers.rb +59 -0
  64. data/spec/unit/chef_runner_spec.rb +70 -0
  65. data/spec/unit/cli_spec.rb +151 -0
  66. data/spec/unit/command/base_spec.rb +88 -0
  67. data/spec/unit/command/exec_spec.rb +123 -0
  68. data/spec/unit/command/generate_spec.rb +102 -0
  69. data/spec/unit/command/generator_commands_spec.rb +504 -0
  70. data/spec/unit/command/shell_init_spec.rb +109 -0
  71. data/spec/unit/command/verify_spec.rb +311 -0
  72. data/spec/unit/commands_map_spec.rb +57 -0
  73. data/spec/unit/component_test_spec.rb +126 -0
  74. data/spec/unit/cookbook_metadata_spec.rb +62 -0
  75. data/spec/unit/cookbook_profiler/git_spec.rb +127 -0
  76. data/spec/unit/cookbook_profiler/identifiers_spec.rb +79 -0
  77. data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_one.rb +9 -0
  78. data/spec/unit/fixtures/chef-runner-cookbooks/test_cookbook/recipes/recipe_two.rb +9 -0
  79. data/spec/unit/fixtures/command/cli_test_command.rb +26 -0
  80. data/spec/unit/fixtures/command/explicit_path_example.rb +7 -0
  81. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/.kitchen.yml +16 -0
  82. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/Berksfile +3 -0
  83. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/README.md +4 -0
  84. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/chefignore +96 -0
  85. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/metadata.rb +8 -0
  86. data/spec/unit/fixtures/cookbook_cache/baz-f59ee7a5bca6a4e606b67f7f856b768d847c39bb/recipes/default.rb +8 -0
  87. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/.kitchen.yml +16 -0
  88. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/Berksfile +3 -0
  89. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/README.md +4 -0
  90. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/chefignore +96 -0
  91. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/metadata.rb +8 -0
  92. data/spec/unit/fixtures/cookbook_cache/dep_of_bar-1.2.3/recipes/default.rb +8 -0
  93. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/.kitchen.yml +16 -0
  94. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/Berksfile +3 -0
  95. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/README.md +4 -0
  96. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/chefignore +96 -0
  97. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/metadata.rb +8 -0
  98. data/spec/unit/fixtures/cookbook_cache/foo-1.0.0/recipes/default.rb +8 -0
  99. data/spec/unit/fixtures/cookbooks_api/pruned_small_universe.json +1322 -0
  100. data/spec/unit/fixtures/cookbooks_api/small_universe.json +2987 -0
  101. data/spec/unit/fixtures/cookbooks_api/universe.json +1 -0
  102. data/spec/unit/fixtures/cookbooks_api/update_fixtures.rb +36 -0
  103. data/spec/unit/fixtures/dev_cookbooks/README.md +16 -0
  104. data/spec/unit/fixtures/dev_cookbooks/bar-cookbook.gitbundle +0 -0
  105. data/spec/unit/fixtures/eg_omnibus_dir/missing_apps/bin/.keep +0 -0
  106. data/spec/unit/fixtures/eg_omnibus_dir/missing_apps/embedded/.keep +0 -0
  107. data/spec/unit/fixtures/eg_omnibus_dir/missing_apps/embedded/bin/.keep +0 -0
  108. data/spec/unit/fixtures/eg_omnibus_dir/missing_component/bin/.keep +0 -0
  109. data/spec/unit/fixtures/eg_omnibus_dir/missing_component/embedded/apps/berkshelf/.keep +0 -0
  110. data/spec/unit/fixtures/eg_omnibus_dir/missing_component/embedded/apps/test-kitchen/.keep +0 -0
  111. data/spec/unit/fixtures/eg_omnibus_dir/missing_component/embedded/bin/.keep +0 -0
  112. data/spec/unit/fixtures/eg_omnibus_dir/valid/bin/.keep +0 -0
  113. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/integration_test +2 -0
  114. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/berkshelf/verify_me +5 -0
  115. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/chef-dk/.keep +0 -0
  116. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/chef/verify_me +3 -0
  117. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/apps/test-kitchen/verify_me +2 -0
  118. data/spec/unit/fixtures/eg_omnibus_dir/valid/embedded/bin/.keep +0 -0
  119. data/spec/unit/fixtures/example_app/Policyfile.rb +0 -0
  120. data/spec/unit/fixtures/example_cookbook/.gitignore +17 -0
  121. data/spec/unit/fixtures/example_cookbook/.kitchen.yml +16 -0
  122. data/spec/unit/fixtures/example_cookbook/Berksfile +3 -0
  123. data/spec/unit/fixtures/example_cookbook/README.md +4 -0
  124. data/spec/unit/fixtures/example_cookbook/chefignore +96 -0
  125. data/spec/unit/fixtures/example_cookbook/metadata.rb +8 -0
  126. data/spec/unit/fixtures/example_cookbook/recipes/default.rb +8 -0
  127. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/.kitchen.yml +16 -0
  128. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/Berksfile +3 -0
  129. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/README.md +4 -0
  130. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/chefignore +96 -0
  131. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/metadata.rb +8 -0
  132. data/spec/unit/fixtures/local_path_cookbooks/local-cookbook/recipes/default.rb +8 -0
  133. data/spec/unit/fixtures/local_path_cookbooks/metadata-missing/README.md +2 -0
  134. data/spec/unit/policyfile/chef_server_cookbook_source_spec.rb +34 -0
  135. data/spec/unit/policyfile/community_cookbook_source_spec.rb +51 -0
  136. data/spec/unit/policyfile/cookbook_spec_spec.rb +200 -0
  137. data/spec/unit/policyfile/null_cookbook_source_spec.rb +35 -0
  138. data/spec/unit/policyfile_builder_spec.rb +489 -0
  139. data/spec/unit/policyfile_demands_spec.rb +484 -0
  140. data/spec/unit/policyfile_evaluation_spec.rb +284 -0
  141. data/spec/unit/shell_out_spec.rb +34 -0
  142. metadata +422 -0
@@ -0,0 +1,80 @@
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 'chef-dk/command/base'
19
+ require 'mixlib/shellout'
20
+
21
+ module ChefDK
22
+ module Command
23
+ class ShellInit < ChefDK::Command::Base
24
+
25
+ SUPPORTED_SHELLS = %w[ bash zsh sh ].map(&:freeze).freeze
26
+
27
+ banner(<<-HELP)
28
+ Usage: chef shell-init
29
+
30
+ `chef shell-init` modifies your shell environment to make ChefDK your default
31
+ ruby.
32
+
33
+ To enable for just the current shell session:
34
+
35
+ eval "$(chef shell-init SHELL_NAME)"
36
+
37
+ To permanently enable:
38
+
39
+ echo 'eval "$(chef shell-init SHELL_NAME)"' >> ~/.YOUR_SHELL_RC_FILE
40
+
41
+ OPTIONS:
42
+
43
+ HELP
44
+
45
+ option :omnibus_dir,
46
+ :long => "--omnibus-dir OMNIBUS_DIR",
47
+ :description => "Alternate path to omnibus install (used for testing)"
48
+
49
+ def omnibus_root
50
+ config[:omnibus_dir] || super
51
+ end
52
+
53
+ def run(argv)
54
+ # Currently we don't have any shell-specific features, so we ignore the
55
+ # shell name. We'll need it if we add completion.
56
+ remaining_args = parse_options(argv)
57
+ shell_name = remaining_args.first
58
+ if shell_name.nil?
59
+ err("Please specify what shell you are using\n")
60
+ err(opt_parser.to_s)
61
+ return 1
62
+ elsif !SUPPORTED_SHELLS.include?(shell_name)
63
+ err("Shell `#{shell_name}' is not currently supported")
64
+ err("Supported shells are: #{SUPPORTED_SHELLS.join(' ')}")
65
+ return 1
66
+ end
67
+
68
+ env = omnibus_env.dup
69
+ path = env.delete("PATH")
70
+ msg("export PATH=#{path}")
71
+ env.each do |var_name, value|
72
+ msg("export #{var_name}=#{value}")
73
+ end
74
+ 0
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+
@@ -0,0 +1,226 @@
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 'chef-dk/command/base'
19
+ require 'chef-dk/exceptions'
20
+ require 'chef-dk/component_test'
21
+
22
+ module ChefDK
23
+ module Command
24
+ class Verify < ChefDK::Command::Base
25
+
26
+
27
+ banner "Usage: chef verify [component, ...] [options]"
28
+
29
+ option :omnibus_dir,
30
+ :long => "--omnibus-dir OMNIBUS_DIR",
31
+ :description => "Alternate path to omnibus install (used for testing)"
32
+
33
+ option :unit,
34
+ :long => "--unit",
35
+ :description => "Run bundled app unit tests (only smoke tests run by default)"
36
+
37
+ option :integration,
38
+ :long => "--integration",
39
+ :description => "Run integration tests. Possibly dangerous, for development systems only"
40
+
41
+ option :verbose,
42
+ :long => "--verbose",
43
+ :description => "Display all test output, not just failing tests"
44
+
45
+ class << self
46
+ def add_component(name, _delete_me=nil)
47
+ component = ComponentTest.new(name)
48
+ yield component if block_given? #delete this conditional
49
+ component_map[name] = component
50
+ end
51
+
52
+ def component(name)
53
+ component_map[name]
54
+ end
55
+
56
+ def components
57
+ component_map.values
58
+ end
59
+
60
+ def component_map
61
+ @component_map ||= {}
62
+ end
63
+ end
64
+
65
+ def components
66
+ self.class.components
67
+ end
68
+
69
+ #
70
+ # Components included in Chef Development kit:
71
+ # :base_dir => Relative path of the component w.r.t. omnibus_apps_dir
72
+ # :test_cmd => Test command to be launched for the component
73
+ #
74
+ add_component "berkshelf" do |c|
75
+ c.base_dir = "berkshelf"
76
+ # For berks the real command to run is "bundle exec thor spec:ci"
77
+ # We can't run it right now since graphviz specs are included in the
78
+ # test suite by default. We will be able to switch to that command when/if
79
+ # Graphviz is added to omnibus.
80
+ c.unit_test { sh("bundle exec rspec --color --format progress spec/unit --tag ~graphviz") }
81
+ c.integration_test { sh("bundle exec cucumber --color --format progress --tags ~@no_run --tags ~@spawn --tags ~@graphviz --strict") }
82
+
83
+ c.smoke_test do
84
+ tmpdir do |cwd|
85
+ FileUtils.touch(File.join(cwd,"Berksfile"))
86
+ sh("berks install", cwd: cwd)
87
+ end
88
+ end
89
+ end
90
+
91
+ add_component "test-kitchen" do |c|
92
+ c.base_dir = "test-kitchen"
93
+ c.unit_test { sh("bundle exec rake unit") }
94
+ c.integration_test { sh("bundle exec rake features") }
95
+ c.smoke_test { run_in_tmpdir("kitchen init") }
96
+ end
97
+
98
+ add_component "chef-client" do |c|
99
+ c.base_dir = "chef"
100
+ c.unit_test { sh("bundle exec rspec -fp spec/unit") }
101
+ c.integration_test { sh("bundle exec rspec -fp spec/integration spec/functional") }
102
+
103
+ c.smoke_test do
104
+ tmpdir do |cwd|
105
+ FileUtils.touch(File.join(cwd, "apply.rb"))
106
+ sh("chef-apply apply.rb", cwd: cwd)
107
+ end
108
+ end
109
+ end
110
+
111
+ add_component "chef-dk" do |c|
112
+ c.base_dir = "chef-dk"
113
+ c.unit_test { sh("bundle exec rspec") }
114
+ c.smoke_test { run_in_tmpdir("chef generate cookbook example") }
115
+ end
116
+
117
+ attr_reader :verification_threads
118
+ attr_reader :verification_results
119
+ attr_reader :verification_status
120
+
121
+ def initialize
122
+ super
123
+ @verification_threads = [ ]
124
+ @verification_results = [ ]
125
+ @verification_status = 0
126
+ end
127
+
128
+ def run(params = [ ])
129
+ @components_filter = parse_options(params)
130
+
131
+ validate_components!
132
+ invoke_tests
133
+ wait_for_tests
134
+ report_results
135
+
136
+ verification_status
137
+ end
138
+
139
+ def omnibus_root
140
+ config[:omnibus_dir] || super
141
+ end
142
+
143
+ def validate_components!
144
+ components.each do |component|
145
+ component.omnibus_root = omnibus_root
146
+ component.assert_present!
147
+ end
148
+ end
149
+
150
+ def components_to_test
151
+ if @components_filter.empty?
152
+ components
153
+ else
154
+ components.select do |component|
155
+ @components_filter.include?(component.name.to_s)
156
+ end
157
+ end
158
+ end
159
+
160
+ def invoke_tests
161
+ components_to_test.each do |component|
162
+ # Run the component specs in parallel
163
+ verification_threads << Thread.new do
164
+
165
+ results = []
166
+
167
+ results << component.run_smoke_test
168
+
169
+ if config[:unit]
170
+ results << component.run_unit_test
171
+ end
172
+
173
+ if config[:integration]
174
+ results << component.run_integration_test
175
+ end
176
+
177
+ if results.any? {|r| r.exitstatus != 0 }
178
+ component_status = 1
179
+ @verification_status = 1
180
+ else
181
+ component_status = 0
182
+ end
183
+
184
+ {
185
+ :component => component,
186
+ :results => results,
187
+ :component_status => component_status
188
+ }
189
+ end
190
+
191
+ msg("Running verification for component '#{component.name}'")
192
+ end
193
+ end
194
+
195
+ def wait_for_tests
196
+ while !verification_threads.empty?
197
+ verification_threads.each do |t|
198
+ if t.join(1)
199
+ verification_threads.delete t
200
+ verification_results << t.value
201
+ t.value[:results].each do |result|
202
+ if config[:verbose] || t.value[:component_status] != 0
203
+ msg("")
204
+ msg(result.stdout)
205
+ msg(result.stderr) if result.stderr
206
+ end
207
+ end
208
+ else
209
+ $stdout.write "."
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ def report_results
216
+ msg("")
217
+ msg("---------------------------------------------")
218
+ verification_results.each do |result|
219
+ message = result[:component_status] == 0 ? "succeeded" : "failed"
220
+ msg("Verification of component '#{result[:component].name}' #{message}.")
221
+ end
222
+ end
223
+
224
+ end
225
+ end
226
+ end
@@ -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
+ module ChefDK
19
+
20
+ # CommandsMap maintains a mapping of subcommand names to the files where
21
+ # those commands are defined and the classes that implement the commands.
22
+ #
23
+ # In ruby it's more typical to handle this sort of thing using conventions
24
+ # and metaprogramming. We've implemented this approach in the past and
25
+ # decided against it here:
26
+ # 1. Performance. As the CLI suite grows, you have to load more and more
27
+ # code, including dependencies that are installed by rubygems, etc. This gets
28
+ # slow, and CLI apps need to be fast.
29
+ # 2. You can workaround the above by having a convention mapping filename to
30
+ # command name, but then you have to do a lot of work to list all of the
31
+ # commands, which is actually a common thing to do.
32
+ # 3. Other ways to mitigate the performance issue (loading deps lazily) have
33
+ # their own complications and tradeoffs and don't fully solve the problem.
34
+ # 4. It's not actually that much work to maintain the mapping.
35
+ #
36
+ # ## Adding new commands globally:
37
+ #
38
+ # A "singleton-ish" instance of this class is stored as ChefDK.commands_map.
39
+ # You can configure a multiple commands at once in a block using
40
+ # ChefDK.commands, like so:
41
+ #
42
+ # ChefDK.commands do |c|
43
+ # # assigns `chef my-command` to the class ChefDK::Command::MyCommand.
44
+ # # The "require path" is inferred to be "chef-dk/command/my_command"
45
+ # c.builtin("my-command", :MyCommand)
46
+ #
47
+ # # Set the require path explicitly:
48
+ # c.builtin("weird-command", :WeirdoClass, require_path: "chef-dk/command/this_is_cray")
49
+ #
50
+ # # You can add a description that will show up in `chef -h` output (recommended):
51
+ # c.builtin("documented-cmd", :DocumentedCmd, desc: "A short description")
52
+ # end
53
+ #
54
+ class CommandsMap
55
+ NULL_ARG = Object.new
56
+
57
+ CommandSpec = Struct.new(:name, :constant_name, :require_path, :description)
58
+
59
+ class CommandSpec
60
+
61
+ def instantiate
62
+ require require_path
63
+ command_class = ChefDK::Command.const_get(constant_name)
64
+ command_class.new
65
+ end
66
+
67
+ end
68
+
69
+ attr_reader :command_specs
70
+
71
+ def initialize
72
+ @command_specs = {}
73
+ end
74
+
75
+ def builtin(name, constant_name, require_path: NULL_ARG, desc: "")
76
+ if null?(require_path)
77
+ snake_case_path = name.gsub("-", "_")
78
+ require_path = "chef-dk/command/#{snake_case_path}"
79
+ end
80
+ command_specs[name] = CommandSpec.new(name, constant_name, require_path, desc)
81
+ end
82
+
83
+ def instantiate(name)
84
+ spec_for(name).instantiate
85
+ end
86
+
87
+ def have_command?(name)
88
+ command_specs.key?(name)
89
+ end
90
+
91
+ def command_names
92
+ command_specs.keys
93
+ end
94
+
95
+ def spec_for(name)
96
+ command_specs[name]
97
+ end
98
+
99
+ private
100
+
101
+ def null?(argument)
102
+ argument.equal?(NULL_ARG)
103
+ end
104
+ end
105
+
106
+ def self.commands_map
107
+ @commands_map ||= CommandsMap.new
108
+ end
109
+
110
+ def self.commands
111
+ yield commands_map
112
+ end
113
+ end
114
+
115
+
@@ -0,0 +1,142 @@
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 'chef-dk/exceptions'
19
+ require 'chef-dk/helpers'
20
+
21
+ module ChefDK
22
+ class ComponentTest
23
+
24
+ class NullTestResult
25
+ def exitstatus
26
+ 0
27
+ end
28
+
29
+ def stdout
30
+ ""
31
+ end
32
+
33
+ def stderr
34
+ ""
35
+ end
36
+ end
37
+
38
+ DEFAULT_TEST = lambda { |context| NullTestResult.new }
39
+
40
+ include Helpers
41
+
42
+ attr_accessor :base_dir
43
+
44
+ attr_writer :omnibus_root
45
+
46
+ attr_reader :name
47
+
48
+ def initialize(name)
49
+ @name = name
50
+ @unit_test = DEFAULT_TEST
51
+ @integration_test = DEFAULT_TEST
52
+ @smoke_test = DEFAULT_TEST
53
+ end
54
+
55
+ def unit_test(&test_block)
56
+ @unit_test = test_block
57
+ end
58
+
59
+ def run_unit_test
60
+ instance_eval(&@unit_test)
61
+ end
62
+
63
+ def integration_test(&test_block)
64
+ @integration_test = test_block
65
+ end
66
+
67
+ def run_integration_test
68
+ instance_eval(&@integration_test)
69
+ end
70
+
71
+ def smoke_test(&test_block)
72
+ @smoke_test = test_block
73
+ end
74
+
75
+ def run_smoke_test
76
+ instance_eval(&@smoke_test)
77
+ end
78
+
79
+ def sh(command, options={})
80
+ combined_opts = default_command_options.merge(options)
81
+
82
+ # Env is a hash, so it needs to be merged separately
83
+ if options.key?(:env)
84
+ combined_opts[:env] = default_command_options[:env].merge(options[:env])
85
+ end
86
+ system_command(command, combined_opts)
87
+ end
88
+
89
+ def run_in_tmpdir(command, options={})
90
+ tmpdir do |dir|
91
+ options[:cwd] = dir
92
+ sh(command, options)
93
+ end
94
+ end
95
+
96
+ def tmpdir
97
+ Dir.mktmpdir do |tmpdir|
98
+ yield tmpdir
99
+ end
100
+ end
101
+
102
+ def assert_present!
103
+ unless File.exists?( component_path )
104
+ raise MissingComponentError.new(name)
105
+ end
106
+ end
107
+
108
+ def default_command_options
109
+ {
110
+ :cwd => component_path,
111
+ :env => {
112
+ # Add the embedded/bin to the PATH so that bundle executable can
113
+ # be found while running the tests.
114
+ path_variable_key => omnibus_path
115
+ },
116
+ :timeout => 3600
117
+ }
118
+ end
119
+
120
+ def component_path
121
+ File.join(omnibus_apps_dir, base_dir)
122
+ end
123
+
124
+ def base_dir
125
+ @base_dir or raise "`base_dir` must be defined for component `#{name}`"
126
+ end
127
+
128
+ def omnibus_root
129
+ @omnibus_root or raise "`omnibus_root` must be set before running tests"
130
+ end
131
+
132
+ def omnibus_path
133
+ [omnibus_bin_dir, omnibus_embedded_bin_dir, ENV['PATH']].join(File::PATH_SEPARATOR)
134
+ end
135
+
136
+ def path_variable_key
137
+ ENV.keys.grep(/\Apath\Z/i).first
138
+ end
139
+
140
+ end
141
+ end
142
+