test-kitchen 1.0.0.alpha.0 → 1.0.0.alpha.1
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.
- data/.travis.yml +9 -0
- data/CHANGELOG.md +35 -0
- data/Rakefile +11 -8
- data/features/kitchen_command.feature +15 -0
- data/features/kitchen_driver_discover_command.feature +19 -0
- data/features/kitchen_init_command.feature +110 -0
- data/features/step_definitions/gem_steps.rb +26 -0
- data/features/support/env.rb +26 -1
- data/lib/kitchen/cli.rb +88 -313
- data/lib/kitchen/driver.rb +4 -2
- data/lib/kitchen/driver/base.rb +33 -9
- data/lib/kitchen/driver/ssh_base.rb +3 -3
- data/lib/kitchen/generator/init.rb +196 -0
- data/lib/kitchen/generator/new_plugin.rb +190 -0
- data/lib/kitchen/instance.rb +6 -3
- data/lib/kitchen/loader/yaml.rb +1 -1
- data/lib/kitchen/shell_out.rb +38 -8
- data/lib/kitchen/state_file.rb +1 -1
- data/lib/kitchen/version.rb +1 -1
- data/spec/kitchen/config_spec.rb +2 -1
- data/spec/kitchen/state_file_spec.rb +1 -1
- metadata +13 -6
- data/features/cli.feature +0 -17
- data/features/cli_init.feature +0 -156
data/.travis.yml
CHANGED
@@ -2,9 +2,18 @@ language: ruby
|
|
2
2
|
|
3
3
|
rvm:
|
4
4
|
- 1.9.3
|
5
|
+
- 2.0.0
|
5
6
|
- jruby-19mode
|
6
7
|
- ruby-head
|
7
8
|
|
9
|
+
env:
|
10
|
+
- RUBYGEMS_VERSION=2.0.3
|
11
|
+
- RUBYGEMS_VERSION=1.8.25
|
12
|
+
|
13
|
+
before_install:
|
14
|
+
- gem update --system $RUBYGEMS_VERSION
|
15
|
+
- gem --version
|
16
|
+
|
8
17
|
matrix:
|
9
18
|
allow_failures:
|
10
19
|
- rvm: ruby-head
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
## 1.0.0.alpha.1 / 2013-03-22
|
2
|
+
|
3
|
+
### Bug fixes
|
4
|
+
|
5
|
+
* Support (and test) for Rubygems 2.0.x and 1.8.x. ([@fnichol][])
|
6
|
+
|
7
|
+
### New features
|
8
|
+
|
9
|
+
* Pull request [#71][]: Updates to `kitchen init` to be non-interactive (add `--driver` flag), add subcommand support, and introduce `kitchen driver discover`. ([@fnichol][])
|
10
|
+
* Add `Driver#verify_dependencies` to be invoked once when Driver is loaded. ([@fnichol][])
|
11
|
+
|
12
|
+
### Improvements
|
13
|
+
|
14
|
+
* Pull request [#73][]: [Breaking] Modify `ShellOut#run_command` to take an options Hash. ([@fnichol][])
|
15
|
+
* Add :quiet option on `ShellOut#run_command`. ([@fnichol][])
|
16
|
+
* [Breaking] `Driver#login_command` returns a Driver::LoginCommand object. ([@fnichol][])
|
17
|
+
* Pull request [#74][]: Switch driver alias (-d) to (-D) in Init generator ([@reset][])
|
18
|
+
* Pull request [#64][]: Make `require_chef_omnibus: true` safe. ([@mattray][])
|
19
|
+
* Pull request [#65][]: Fix for line length and style (tailor). ([@ChrisLundquist][])
|
20
|
+
|
21
|
+
|
22
|
+
## 1.0.0.alpha.0 / 2013-03-02
|
23
|
+
|
24
|
+
The initial release.
|
25
|
+
|
26
|
+
<!--- The following link definition list is generated by PimpMyChangelog --->
|
27
|
+
[#64]: https://github.com/opscode/test/issues/64
|
28
|
+
[#65]: https://github.com/opscode/test/issues/65
|
29
|
+
[#71]: https://github.com/opscode/test/issues/71
|
30
|
+
[#73]: https://github.com/opscode/test/issues/73
|
31
|
+
[#74]: https://github.com/opscode/test/issues/74
|
32
|
+
[@ChrisLundquist]: https://github.com/ChrisLundquist
|
33
|
+
[@fnichol]: https://github.com/fnichol
|
34
|
+
[@mattray]: https://github.com/mattray
|
35
|
+
[@reset]: https://github.com/reset
|
data/Rakefile
CHANGED
@@ -1,19 +1,26 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
2
|
require 'rake/testtask'
|
3
|
+
require 'cucumber'
|
4
|
+
require 'cucumber/rake/task'
|
3
5
|
|
4
|
-
Rake::TestTask.new do |t|
|
6
|
+
Rake::TestTask.new(:unit) do |t|
|
5
7
|
t.libs.push "lib"
|
6
8
|
t.test_files = FileList['spec/**/*_spec.rb']
|
7
9
|
t.verbose = true
|
8
10
|
end
|
9
11
|
|
12
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
13
|
+
t.cucumber_opts = ['features', '-x', '--format progress']
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Run all test suites"
|
17
|
+
task :test => [:unit, :features]
|
18
|
+
|
10
19
|
task :default => [:test]
|
11
20
|
|
12
21
|
unless RUBY_ENGINE == 'jruby'
|
13
22
|
require 'cane/rake_task'
|
14
23
|
require 'tailor/rake_task'
|
15
|
-
require 'cucumber'
|
16
|
-
require 'cucumber/rake/task'
|
17
24
|
|
18
25
|
desc "Run cane to check quality metrics"
|
19
26
|
Cane::RakeTask.new do |cane|
|
@@ -51,11 +58,7 @@ unless RUBY_ENGINE == 'jruby'
|
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
54
|
-
|
55
|
-
t.cucumber_opts = ['features', '-x', '--format progress']
|
56
|
-
end
|
57
|
-
|
58
|
-
Rake::Task[:default].enhance [:cane, :features, :tailor]
|
61
|
+
Rake::Task[:default].enhance [:cane, :tailor]
|
59
62
|
end
|
60
63
|
|
61
64
|
desc "Display LOC stats"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Feature: A command line interface for Test Kitchen
|
2
|
+
In order to provide a quick and response development workflow
|
3
|
+
As a Test Kitchen user
|
4
|
+
I want a command line interface that has sane defaults and built in help
|
5
|
+
|
6
|
+
Scenario: Displaying help
|
7
|
+
When I run `kitchen help`
|
8
|
+
Then the exit status should be 0
|
9
|
+
And the output should contain "kitchen console"
|
10
|
+
And the output should contain "kitchen version"
|
11
|
+
|
12
|
+
Scenario: Displaying the version of Test Kitchen
|
13
|
+
When I run `kitchen version`
|
14
|
+
Then the exit status should be 0
|
15
|
+
And the output should contain "Test Kitchen version"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Feature: Search RubyGems to discover new Test Kitchen Driver gems
|
2
|
+
In order to periodically check for new/updated Kitchen drivers
|
3
|
+
As a Test Kitchen user
|
4
|
+
I want to run a command which returns candidate Kitchen drivers
|
5
|
+
|
6
|
+
Scenario: Displaying help
|
7
|
+
When I run `kitchen help driver discover`
|
8
|
+
Then the output should contain:
|
9
|
+
"""
|
10
|
+
Usage:
|
11
|
+
kitchen driver discover
|
12
|
+
"""
|
13
|
+
And the exit status should be 0
|
14
|
+
|
15
|
+
Scenario: Running driver discover returns live results
|
16
|
+
When I run `kitchen driver discover`
|
17
|
+
Then the exit status should be 0
|
18
|
+
And the output should contain "kitchen-vagrant"
|
19
|
+
And the output should contain "kitchen-bluebox"
|
@@ -0,0 +1,110 @@
|
|
1
|
+
Feature: Add Test Kitchen support to an existing project
|
2
|
+
In order to add Test Kitchen to a project with minimal effort
|
3
|
+
As an operator
|
4
|
+
I want to run a command to initialize my project
|
5
|
+
|
6
|
+
Scenario: Displaying help
|
7
|
+
When I run `kitchen help init`
|
8
|
+
Then the output should contain:
|
9
|
+
"""
|
10
|
+
Usage:
|
11
|
+
kitchen init
|
12
|
+
"""
|
13
|
+
And the exit status should be 0
|
14
|
+
|
15
|
+
# Scenario: Running init with default values
|
16
|
+
# Given a sandboxed GEM_HOME directory named "kitchen-init"
|
17
|
+
# When I run `kitchen init`
|
18
|
+
# Then the exit status should be 0
|
19
|
+
# And a directory named ".kitchen" should exist
|
20
|
+
# And a directory named "test/integration/default" should exist
|
21
|
+
# And the file ".gitignore" should contain ".kitchen/"
|
22
|
+
# And the file ".gitignore" should contain ".kitchen.local.yml"
|
23
|
+
# And the file ".kitchen.yml" should contain "driver_plugin: vagrant"
|
24
|
+
# And a file named "Gemfile" should not exist
|
25
|
+
# And a file named "Rakefile" should not exist
|
26
|
+
# And a file named "Thorfile" should not exist
|
27
|
+
# And a gem named "kitchen-vagrant" is installed
|
28
|
+
|
29
|
+
Scenario: Running init that creates a Gemfile
|
30
|
+
When I successfully run `kitchen init --create-gemfile`
|
31
|
+
Then the file "Gemfile" should contain "https://rubygems.org"
|
32
|
+
And the file "Gemfile" should contain "gem 'test-kitchen'"
|
33
|
+
And the file "Gemfile" should contain "gem 'kitchen-vagrant'"
|
34
|
+
And the output should contain "You must run `bundle install'"
|
35
|
+
|
36
|
+
Scenario: Running init with an existing Gemfile appends to the Gemfile
|
37
|
+
Given an empty file named "Gemfile"
|
38
|
+
When I successfully run `kitchen init`
|
39
|
+
And the file "Gemfile" should contain "gem 'test-kitchen'"
|
40
|
+
And the file "Gemfile" should contain "gem 'kitchen-vagrant'"
|
41
|
+
And the output should contain "You must run `bundle install'"
|
42
|
+
|
43
|
+
Scenario: Running init with multiple drivers appends to the Gemfile
|
44
|
+
Given an empty file named "Gemfile"
|
45
|
+
When I successfully run `kitchen init --driver=kitchen-bluebox kitchen-wakka`
|
46
|
+
Then the file "Gemfile" should contain "gem 'kitchen-bluebox'"
|
47
|
+
And the file "Gemfile" should contain "gem 'kitchen-wakka'"
|
48
|
+
And the output should contain "You must run `bundle install'"
|
49
|
+
|
50
|
+
Scenario: Running init with multiple driver sets the plugin_driver to the
|
51
|
+
first driver given
|
52
|
+
Given an empty file named "Gemfile"
|
53
|
+
When I successfully run `kitchen init --driver=kitchen-bluebox kitchen-wakka`
|
54
|
+
Then the file ".kitchen.yml" should contain "driver_plugin: bluebox"
|
55
|
+
|
56
|
+
Scenario: Running init with no drivers sets the plugin_driver to the
|
57
|
+
dummy driver
|
58
|
+
Given an empty file named "Gemfile"
|
59
|
+
When I successfully run `kitchen init --no-driver`
|
60
|
+
Then the file ".kitchen.yml" should contain "driver_plugin: dummy"
|
61
|
+
|
62
|
+
Scenario: Running with a Rakefile file appends Kitchen tasks
|
63
|
+
Given an empty file named "Gemfile"
|
64
|
+
And an empty file named "Rakefile"
|
65
|
+
When I successfully run `kitchen init`
|
66
|
+
Then the file "Rakefile" should contain:
|
67
|
+
"""
|
68
|
+
begin
|
69
|
+
require 'kitchen/rake_tasks'
|
70
|
+
Kitchen::RakeTasks.new
|
71
|
+
rescue LoadError
|
72
|
+
puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI']
|
73
|
+
end
|
74
|
+
"""
|
75
|
+
|
76
|
+
Scenario: Running with a Thorfile file appends Kitchen tasks
|
77
|
+
Given an empty file named "Gemfile"
|
78
|
+
Given an empty file named "Thorfile"
|
79
|
+
When I successfully run `kitchen init`
|
80
|
+
Then the file "Thorfile" should contain:
|
81
|
+
"""
|
82
|
+
begin
|
83
|
+
require 'kitchen/thor_tasks'
|
84
|
+
Kitchen::ThorTasks.new
|
85
|
+
rescue LoadError
|
86
|
+
puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI']
|
87
|
+
end
|
88
|
+
"""
|
89
|
+
|
90
|
+
Scenario: Running init with a the name attribute metadata.rb sets a run list
|
91
|
+
Given an empty file named "Gemfile"
|
92
|
+
Given a file named "metadata.rb" with:
|
93
|
+
"""
|
94
|
+
name "ntp"
|
95
|
+
license "Apache 2.0"
|
96
|
+
description "Installs and configures ntp as a client or server"
|
97
|
+
version "0.1.0"
|
98
|
+
|
99
|
+
support "ubuntu"
|
100
|
+
support "centos"
|
101
|
+
"""
|
102
|
+
When I successfully run `kitchen init`
|
103
|
+
Then the file ".kitchen.yml" should contain:
|
104
|
+
"""
|
105
|
+
suites:
|
106
|
+
- name: default
|
107
|
+
run_list:
|
108
|
+
- recipe[ntp]
|
109
|
+
attributes: {}
|
110
|
+
"""
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
Given(/^a sandboxed GEM_HOME directory named "(.*?)"$/) do |name|
|
5
|
+
backup_envvar('GEM_HOME')
|
6
|
+
backup_envvar('GEM_PATH')
|
7
|
+
|
8
|
+
@aruba_timeout_seconds = 30
|
9
|
+
|
10
|
+
gem_home = Pathname.new(Dir.mktmpdir(name))
|
11
|
+
ENV['GEM_HOME'] = gem_home.to_s
|
12
|
+
ENV['GEM_PATH'] = [gem_home.to_s, ENV['GEM_PATH']].join(':')
|
13
|
+
@cleanup_dirs << gem_home
|
14
|
+
end
|
15
|
+
|
16
|
+
Then(/^a gem named "(.*?)" is installed with version "(.*?)"$/) do |name, version|
|
17
|
+
unbundlerize do
|
18
|
+
run_simple(unescape("gem list #{name} --version #{version} -i"), true, nil)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Then(/^a gem named "(.*?)" is installed$/) do |name|
|
23
|
+
unbundlerize do
|
24
|
+
run_simple(unescape("gem list #{name} -i"), true, nil)
|
25
|
+
end
|
26
|
+
end
|
data/features/support/env.rb
CHANGED
@@ -4,11 +4,36 @@ require 'kitchen'
|
|
4
4
|
|
5
5
|
Before do
|
6
6
|
@aruba_timeout_seconds = 5
|
7
|
+
@cleanup_dirs = []
|
7
8
|
end
|
8
9
|
|
9
|
-
After do |s|
|
10
|
+
After do |s|
|
10
11
|
# Tell Cucumber to quit after this scenario is done - if it failed.
|
11
12
|
# This is useful to inspect the 'tmp/aruba' directory before any other
|
12
13
|
# steps are executed and clear it out.
|
13
14
|
Cucumber.wants_to_quit = true if s.failed?
|
15
|
+
|
16
|
+
# Restore environment variables to their original settings, if they have
|
17
|
+
# been saved off
|
18
|
+
ENV.keys.select { |key| key =~ /^_CUKE_/ }.each do |backup_key|
|
19
|
+
ENV[backup_key.sub(/^_CUKE_/, '')] = ENV.delete(backup_key)
|
20
|
+
end
|
21
|
+
|
22
|
+
@cleanup_dirs.each { |dir| FileUtils.rm_rf(dir) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def backup_envvar(key)
|
26
|
+
ENV["_CUKE_#{key}"] = ENV[key]
|
27
|
+
end
|
28
|
+
|
29
|
+
def restore_envvar(key)
|
30
|
+
ENV[key] = ENV.delete("_CUKE_#{key}")
|
31
|
+
end
|
32
|
+
|
33
|
+
def unbundlerize
|
34
|
+
keys = %w[BUNDLER_EDITOR BUNDLE_BIN_PATH BUNDLE_GEMFILE RUBYOPT]
|
35
|
+
|
36
|
+
keys.each { |key| backup_envvar(key) ; ENV.delete(key) }
|
37
|
+
yield
|
38
|
+
keys.each { |key| restore_envvar(key) }
|
14
39
|
end
|
data/lib/kitchen/cli.rb
CHANGED
@@ -22,6 +22,8 @@ require 'ostruct'
|
|
22
22
|
require 'thor'
|
23
23
|
|
24
24
|
require 'kitchen'
|
25
|
+
require 'kitchen/generator/init'
|
26
|
+
require 'kitchen/generator/new_plugin'
|
25
27
|
|
26
28
|
module Kitchen
|
27
29
|
|
@@ -120,7 +122,7 @@ module Kitchen
|
|
120
122
|
|
121
123
|
desc "version", "Print Kitchen's version information"
|
122
124
|
def version
|
123
|
-
say "Kitchen version #{Kitchen::VERSION}"
|
125
|
+
say "Test Kitchen version #{Kitchen::VERSION}"
|
124
126
|
end
|
125
127
|
map %w(-v --version) => :version
|
126
128
|
|
@@ -134,18 +136,91 @@ module Kitchen
|
|
134
136
|
exit 1
|
135
137
|
end
|
136
138
|
|
137
|
-
|
138
|
-
|
139
|
-
|
139
|
+
register Kitchen::Generator::Init, "init",
|
140
|
+
"init", "Adds some configuration to your cookbook so Kitchen can rock"
|
141
|
+
long_desc <<-D, :for => "init"
|
142
|
+
Init will add Test Kitchen support to an existing project for
|
143
|
+
convergence integration testing. A default .kitchen.yml file (which is
|
144
|
+
intended to be customized) is created in the project's root directory
|
145
|
+
and one or more gems will be added to the project's Gemfile.
|
146
|
+
D
|
147
|
+
tasks["init"].options = Kitchen::Generator::Init.class_options
|
148
|
+
|
149
|
+
# Thor class for kitchen driver commands.
|
150
|
+
#
|
151
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
152
|
+
class Driver < Thor
|
153
|
+
|
154
|
+
register Kitchen::Generator::NewPlugin, "create",
|
155
|
+
"create [NAME]", "Create a new Kitchen Driver gem project"
|
156
|
+
long_desc <<-D, :for => "create"
|
157
|
+
Create will generate a project scaffold for a brand new Test Kitchen
|
158
|
+
Driver RubyGem. For example:
|
159
|
+
|
160
|
+
> kitchen driver create foobar
|
161
|
+
|
162
|
+
will create a project scaffold for a RubyGem called `kitchen-foobar'.
|
163
|
+
D
|
164
|
+
tasks["create"].options = Kitchen::Generator::NewPlugin.class_options
|
165
|
+
|
166
|
+
desc "discover", "Discover Test Kitchen drivers published on RubyGems"
|
167
|
+
long_desc <<-D
|
168
|
+
Discover will perform a search aginst the RubyGems service for any
|
169
|
+
published gems of the form: "kitchen-*". Note that it it cannot be
|
170
|
+
guarenteed that every result is a driver, but chances are good most
|
171
|
+
relevant drivers will be returned.
|
172
|
+
D
|
173
|
+
def discover
|
174
|
+
specs = fetch_gem_specs.sort { |x, y| x[0] <=> y[0] }
|
175
|
+
specs = specs[0, 49].push(["...", "..."]) if specs.size > 49
|
176
|
+
specs = specs.unshift(["Gem Name", "Latest Stable Release"])
|
177
|
+
print_table(specs, :indent => 4)
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.basename
|
181
|
+
super + " driver"
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
def fetch_gem_specs
|
187
|
+
require 'rubygems/spec_fetcher'
|
188
|
+
SafeYAML::OPTIONS[:suppress_warnings] = true
|
189
|
+
req = Gem::Requirement.default
|
190
|
+
dep = Gem::Deprecate.skip_during do
|
191
|
+
Gem::Dependency.new(/kitchen-/i, req)
|
192
|
+
end
|
193
|
+
fetcher = Gem::SpecFetcher.fetcher
|
194
|
+
|
195
|
+
specs = if fetcher.respond_to?(:find_matching)
|
196
|
+
fetch_gem_specs_pre_rubygems_2(fetcher, dep)
|
197
|
+
else
|
198
|
+
fetch_gem_specs_post_rubygems_2(fetcher, dep)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def fetch_gem_specs_pre_rubygems_2(fetcher, dep)
|
203
|
+
specs = fetcher.find_matching(dep, false, false, false)
|
204
|
+
specs.map { |t| t.first }.map { |t| t[0, 2] }
|
205
|
+
end
|
206
|
+
|
207
|
+
def fetch_gem_specs_post_rubygems_2(fetcher, dep)
|
208
|
+
specs = fetcher.spec_for_dependency(dep, false)
|
209
|
+
specs.first.map { |t| [t.first.name, t.first.version] }
|
210
|
+
end
|
140
211
|
end
|
141
212
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
213
|
+
register Kitchen::CLI::Driver, "driver",
|
214
|
+
"driver", "Driver subcommands"
|
215
|
+
|
216
|
+
no_tasks do
|
217
|
+
def invoke_task(task, *args)
|
218
|
+
if task.name == "help" && args.first.first == "driver"
|
219
|
+
Kitchen::CLI::Driver.task_help(shell, args.first.last)
|
220
|
+
else
|
221
|
+
super
|
222
|
+
end
|
223
|
+
end
|
149
224
|
end
|
150
225
|
|
151
226
|
private
|
@@ -224,317 +299,17 @@ module Kitchen
|
|
224
299
|
[
|
225
300
|
proc { |target_self, nest_level, pry|
|
226
301
|
["[#{pry.input_array.size}] ",
|
227
|
-
"
|
302
|
+
"kc(#{Pry.view_clip(target_self.class)})",
|
228
303
|
"#{":#{nest_level}" unless nest_level.zero?}> "
|
229
304
|
].join
|
230
305
|
},
|
231
306
|
proc { |target_self, nest_level, pry|
|
232
307
|
["[#{pry.input_array.size}] ",
|
233
|
-
"
|
308
|
+
"kc(#{Pry.view_clip(target_self.class)})",
|
234
309
|
"#{":#{nest_level}" unless nest_level.zero?}* "
|
235
310
|
].join
|
236
311
|
},
|
237
312
|
]
|
238
313
|
end
|
239
314
|
end
|
240
|
-
|
241
|
-
# A project initialization generator, to help prepare a cookbook project for
|
242
|
-
# testing with Kitchen.
|
243
|
-
#
|
244
|
-
# @author Fletcher Nichol <fnichol@nichol.ca>
|
245
|
-
class InitGenerator < Thor
|
246
|
-
|
247
|
-
include Thor::Actions
|
248
|
-
|
249
|
-
desc "init", "Adds some configuration to your cookbook so Kitchen can rock"
|
250
|
-
def init
|
251
|
-
create_file ".kitchen.yml", default_yaml
|
252
|
-
|
253
|
-
rakedoc = <<-RAKE.gsub(/^ {8}/, '')
|
254
|
-
|
255
|
-
begin
|
256
|
-
require 'kitchen/rake_tasks'
|
257
|
-
Kitchen::RakeTasks.new
|
258
|
-
rescue LoadError
|
259
|
-
puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI']
|
260
|
-
end
|
261
|
-
RAKE
|
262
|
-
append_to_file("Rakefile", rakedoc) if init_rakefile?
|
263
|
-
|
264
|
-
thordoc = <<-THOR.gsub(/^ {8}/, '')
|
265
|
-
|
266
|
-
begin
|
267
|
-
require 'kitchen/thor_tasks'
|
268
|
-
Kitchen::ThorTasks.new
|
269
|
-
rescue LoadError
|
270
|
-
puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI']
|
271
|
-
end
|
272
|
-
THOR
|
273
|
-
append_to_file("Thorfile", thordoc) if init_thorfile?
|
274
|
-
|
275
|
-
empty_directory "test/integration/default" if init_test_dir?
|
276
|
-
append_to_gitignore(".kitchen/")
|
277
|
-
append_to_gitignore(".kitchen.local.yml")
|
278
|
-
add_plugins
|
279
|
-
end
|
280
|
-
|
281
|
-
private
|
282
|
-
|
283
|
-
def default_yaml
|
284
|
-
url_base = "https://opscode-vm.s3.amazonaws.com/vagrant/boxes"
|
285
|
-
platforms = [
|
286
|
-
{ :n => 'ubuntu', :vers => %w(12.04 10.04), :rl => "recipe[apt]" },
|
287
|
-
{ :n => 'centos', :vers => %w(6.3 5.8), :rl => "recipe[yum::epel]" },
|
288
|
-
]
|
289
|
-
platforms = platforms.map do |p|
|
290
|
-
p[:vers].map do |v|
|
291
|
-
{ 'name' => "#{p[:n]}-#{v}",
|
292
|
-
'driver_config' => {
|
293
|
-
'box' => "opscode-#{p[:n]}-#{v}",
|
294
|
-
'box_url' => "#{url_base}/opscode-#{p[:n]}-#{v}.box"
|
295
|
-
},
|
296
|
-
'run_list' => Array(p[:rl])
|
297
|
-
}
|
298
|
-
end
|
299
|
-
end.flatten
|
300
|
-
cookbook_name = if File.exists?(File.expand_path('metadata.rb'))
|
301
|
-
MetadataChopper.extract('metadata.rb').first
|
302
|
-
else
|
303
|
-
nil
|
304
|
-
end
|
305
|
-
run_list = cookbook_name ? "recipe[#{cookbook_name}]" : nil
|
306
|
-
|
307
|
-
{ 'driver_plugin' => 'vagrant',
|
308
|
-
'platforms' => platforms,
|
309
|
-
'suites' => [
|
310
|
-
{ 'name' => 'default',
|
311
|
-
'run_list' => Array(run_list),
|
312
|
-
'attributes' => Hash.new
|
313
|
-
},
|
314
|
-
]
|
315
|
-
}.to_yaml
|
316
|
-
end
|
317
|
-
|
318
|
-
def init_rakefile?
|
319
|
-
File.exists?("Rakefile") &&
|
320
|
-
IO.readlines("Rakefile").grep(%r{require 'kitchen/rake_tasks'}).empty?
|
321
|
-
end
|
322
|
-
|
323
|
-
def init_thorfile?
|
324
|
-
File.exists?("Thorfile") &&
|
325
|
-
IO.readlines("Thorfile").grep(%r{require 'kitchen/thor_tasks'}).empty?
|
326
|
-
end
|
327
|
-
|
328
|
-
def init_test_dir?
|
329
|
-
Dir.glob("test/integration/*").select { |d| File.directory?(d) }.empty?
|
330
|
-
end
|
331
|
-
|
332
|
-
def append_to_gitignore(line)
|
333
|
-
create_file(".gitignore") unless File.exists?(".gitignore")
|
334
|
-
|
335
|
-
if IO.readlines(".gitignore").grep(%r{^#{line}}).empty?
|
336
|
-
append_to_file(".gitignore", "#{line}\n")
|
337
|
-
end
|
338
|
-
end
|
339
|
-
|
340
|
-
def add_plugins
|
341
|
-
prompt_add = "Add a Driver plugin to your Gemfile? (y/n)>"
|
342
|
-
prompt_name = "Enter gem name, `list', or `skip'>"
|
343
|
-
|
344
|
-
if yes?(prompt_add, :green)
|
345
|
-
list_plugins while (plugin = ask(prompt_name, :green)) == "list"
|
346
|
-
return if plugin == "skip"
|
347
|
-
begin
|
348
|
-
append_to_file(
|
349
|
-
"Gemfile", %{gem '#{plugin}', :group => :integration\n}
|
350
|
-
)
|
351
|
-
say "You must run `bundle install' to fetch any new gems.", :red
|
352
|
-
rescue Errno::ENOENT
|
353
|
-
warn %{You do not have an existing Gemfile}
|
354
|
-
warn %{Exiting...}
|
355
|
-
exit 1
|
356
|
-
end
|
357
|
-
end
|
358
|
-
end
|
359
|
-
|
360
|
-
def list_plugins
|
361
|
-
specs = fetch_gem_specs.map { |t| t.first }.map { |t| t[0, 2] }.
|
362
|
-
sort { |x, y| x[0] <=> y[0] }
|
363
|
-
specs = specs[0, 49].push(["...", "..."]) if specs.size > 49
|
364
|
-
specs = specs.unshift(["Gem Name", "Latest Stable Release"])
|
365
|
-
print_table(specs, :indent => 4)
|
366
|
-
end
|
367
|
-
|
368
|
-
def fetch_gem_specs
|
369
|
-
require 'rubygems/spec_fetcher'
|
370
|
-
req = Gem::Requirement.default
|
371
|
-
dep = Gem::Deprecate.skip_during { Gem::Dependency.new(/kitchen-/i, req) }
|
372
|
-
fetcher = Gem::SpecFetcher.fetcher
|
373
|
-
|
374
|
-
specs = fetcher.find_matching(dep, false, false, false)
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
|
-
# A generator to create a new Kitchen driver plugin.
|
379
|
-
#
|
380
|
-
# @author Fletcher Nichol <fnichol@nichol.ca>
|
381
|
-
class NewPluginGenerator < Thor
|
382
|
-
|
383
|
-
include Thor::Actions
|
384
|
-
|
385
|
-
desc "new_plugin [NAME]", "Generate a new Kitchen Driver plugin gem project"
|
386
|
-
method_option :license, :aliases => "-l", :default => "apachev2",
|
387
|
-
:desc => "Type of license for gem (apachev2, mit, gplv3, gplv2, reserved)"
|
388
|
-
def new_plugin(plugin_name)
|
389
|
-
if ! run("command -v bundle", :verbose => false)
|
390
|
-
die "Bundler must be installed and on your PATH: `gem install bundler'"
|
391
|
-
end
|
392
|
-
|
393
|
-
@plugin_name = plugin_name
|
394
|
-
@gem_name = "kitchen-#{plugin_name}"
|
395
|
-
@gemspec = "#{gem_name}.gemspec"
|
396
|
-
@klass_name = Util.to_camel_case(plugin_name)
|
397
|
-
@constant = Util.to_snake_case(plugin_name).upcase
|
398
|
-
@license = options[:license]
|
399
|
-
@author = %x{git config user.name}.chomp
|
400
|
-
@email = %x{git config user.email}.chomp
|
401
|
-
@year = Time.now.year
|
402
|
-
|
403
|
-
create_plugin
|
404
|
-
end
|
405
|
-
|
406
|
-
private
|
407
|
-
|
408
|
-
attr_reader :plugin_name, :gem_name, :gemspec, :klass_name,
|
409
|
-
:constant, :license, :author, :email, :year
|
410
|
-
|
411
|
-
def create_plugin
|
412
|
-
run("bundle gem #{gem_name}") unless File.directory?(gem_name)
|
413
|
-
|
414
|
-
inside(gem_name) do
|
415
|
-
update_gemspec
|
416
|
-
update_gemfile
|
417
|
-
update_rakefile
|
418
|
-
create_src_files
|
419
|
-
cleanup
|
420
|
-
create_license
|
421
|
-
add_git_files
|
422
|
-
end
|
423
|
-
end
|
424
|
-
|
425
|
-
def update_gemspec
|
426
|
-
gsub_file(gemspec, %r{require '#{gem_name}/version'},
|
427
|
-
%{require 'kitchen/driver/#{plugin_name}_version.rb'})
|
428
|
-
gsub_file(gemspec, %r{Kitchen::#{klass_name}::VERSION},
|
429
|
-
%{Kitchen::Driver::#{constant}_VERSION})
|
430
|
-
gsub_file(gemspec, %r{(gem\.executables\s*) =.*$},
|
431
|
-
'\1 = []')
|
432
|
-
gsub_file(gemspec, %r{(gem\.description\s*) =.*$},
|
433
|
-
'\1 = "' + "Kitchen::Driver::#{klass_name} - " +
|
434
|
-
"A Kitchen Driver for #{klass_name}\"")
|
435
|
-
gsub_file(gemspec, %r{(gem\.summary\s*) =.*$},
|
436
|
-
'\1 = gem.description')
|
437
|
-
gsub_file(gemspec, %r{(gem\.homepage\s*) =.*$},
|
438
|
-
'\1 = "https://github.com/opscode/' +
|
439
|
-
"#{gem_name}/\"")
|
440
|
-
insert_into_file(gemspec,
|
441
|
-
"\n gem.add_dependency 'test-kitchen'\n", :before => "end\n")
|
442
|
-
insert_into_file(gemspec,
|
443
|
-
"\n gem.add_development_dependency 'cane'\n", :before => "end\n")
|
444
|
-
insert_into_file(gemspec,
|
445
|
-
" gem.add_development_dependency 'tailor'\n", :before => "end\n")
|
446
|
-
end
|
447
|
-
|
448
|
-
def update_gemfile
|
449
|
-
append_to_file("Gemfile", "\ngroup :test do\n gem 'rake'\nend\n")
|
450
|
-
end
|
451
|
-
|
452
|
-
def update_rakefile
|
453
|
-
append_to_file("Rakefile", <<-RAKEFILE.gsub(/^ {8}/, ''))
|
454
|
-
require 'cane/rake_task'
|
455
|
-
require 'tailor/rake_task'
|
456
|
-
|
457
|
-
desc "Run cane to check quality metrics"
|
458
|
-
Cane::RakeTask.new
|
459
|
-
|
460
|
-
Tailor::RakeTask.new
|
461
|
-
|
462
|
-
task :default => [ :cane, :tailor ]
|
463
|
-
RAKEFILE
|
464
|
-
end
|
465
|
-
|
466
|
-
def create_src_files
|
467
|
-
license_comments = rendered_license.gsub(/^/, '# ').gsub(/\s+$/, '')
|
468
|
-
|
469
|
-
empty_directory("lib/kitchen/driver")
|
470
|
-
create_template("plugin/version.rb",
|
471
|
-
"lib/kitchen/driver/#{plugin_name}_version.rb",
|
472
|
-
:klass_name => klass_name, :constant => constant,
|
473
|
-
:license => license_comments)
|
474
|
-
create_template("plugin/driver.rb",
|
475
|
-
"lib/kitchen/driver/#{plugin_name}.rb",
|
476
|
-
:klass_name => klass_name, :license => license_comments,
|
477
|
-
:author => author, :email => email)
|
478
|
-
end
|
479
|
-
|
480
|
-
def rendered_license
|
481
|
-
TemplateRenderer.render("plugin/license_#{license}",
|
482
|
-
:author => author, :email => email, :year => year)
|
483
|
-
end
|
484
|
-
|
485
|
-
def create_license
|
486
|
-
dest_file = case license
|
487
|
-
when "mit" then "LICENSE.txt"
|
488
|
-
when "apachev2", "reserved" then "LICENSE"
|
489
|
-
when "gplv2", "gplv3" then "COPYING"
|
490
|
-
else
|
491
|
-
raise ArgumentError, "No such license #{license}"
|
492
|
-
end
|
493
|
-
|
494
|
-
create_file(dest_file, rendered_license)
|
495
|
-
end
|
496
|
-
|
497
|
-
def cleanup
|
498
|
-
%W(LICENSE.txt lib/#{gem_name}/version.rb lib/#{gem_name}.rb).each do |f|
|
499
|
-
run("git rm -f #{f}") if File.exists?(f)
|
500
|
-
end
|
501
|
-
remove_dir("lib/#{gem_name}")
|
502
|
-
end
|
503
|
-
|
504
|
-
def add_git_files
|
505
|
-
run("git add .")
|
506
|
-
end
|
507
|
-
|
508
|
-
def create_template(template, destination, data = {})
|
509
|
-
create_file(destination, TemplateRenderer.render(template, data))
|
510
|
-
end
|
511
|
-
|
512
|
-
# Renders an ERB template with a hash of template variables.
|
513
|
-
#
|
514
|
-
# @author Fletcher Nichol <fnichol@nichol.ca>
|
515
|
-
class TemplateRenderer < OpenStruct
|
516
|
-
|
517
|
-
def self.render(template, data = {})
|
518
|
-
renderer = new(template, data)
|
519
|
-
yield renderer if block_given?
|
520
|
-
renderer.render
|
521
|
-
end
|
522
|
-
|
523
|
-
def initialize(template, data = {})
|
524
|
-
super()
|
525
|
-
data[:template] = template
|
526
|
-
data.each { |key, value| send("#{key}=", value) }
|
527
|
-
end
|
528
|
-
|
529
|
-
def render
|
530
|
-
ERB.new(IO.read(template_file)).result(binding)
|
531
|
-
end
|
532
|
-
|
533
|
-
private
|
534
|
-
|
535
|
-
def template_file
|
536
|
-
Kitchen.source_root.join("templates", "#{template}.erb").to_s
|
537
|
-
end
|
538
|
-
end
|
539
|
-
end
|
540
315
|
end
|