engineyard-recipes 0.0.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/.gitignore +6 -0
- data/Gemfile +4 -0
- data/README.md +11 -0
- data/Rakefile +1 -0
- data/bin/ey-recipes +17 -0
- data/engineyard-recipes.gemspec +33 -0
- data/features/init-new-cookbook.feature +18 -0
- data/features/step_definitions/api_steps.rb +10 -0
- data/features/step_definitions/common_steps.rb +211 -0
- data/features/step_definitions/fixture_project_steps.rb +14 -0
- data/features/step_definitions/jenkins_steps.rb +21 -0
- data/features/support/common.rb +51 -0
- data/features/support/env.rb +18 -0
- data/features/support/matchers.rb +10 -0
- data/fixtures/bin/README.md +4 -0
- data/fixtures/bin/scp +6 -0
- data/fixtures/cookbooks/main/recipes/default.rb +1 -0
- data/fixtures/cookbooks/redis/recipes/default.rb +0 -0
- data/fixtures/jenkins_boot_sequence/jenkins_booting.html +1 -0
- data/fixtures/jenkins_boot_sequence/jenkins_ready.html +1 -0
- data/fixtures/jenkins_boot_sequence/pre_jenkins_booting.html +1 -0
- data/fixtures/projects/rails/Gemfile +3 -0
- data/fixtures/projects/rails/Rakefile +4 -0
- data/lib/engineyard-recipes/cli.rb +86 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/attributes/recipe.rb +3 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/definitions/ey_cloud_report.rb +6 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/libraries/ruby_block.rb +40 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/libraries/run_for_app.rb +12 -0
- data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/recipes/default.rb +0 -0
- data/lib/engineyard-recipes/generators/init_generator.rb +38 -0
- data/lib/engineyard-recipes/thor-ext/actions/directory.rb +33 -0
- data/lib/engineyard-recipes/version.rb +5 -0
- data/lib/engineyard-recipes.rb +7 -0
- metadata +149 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/ey-recipes
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
|
4
|
+
require 'engineyard-recipes'
|
5
|
+
require 'engineyard-recipes/cli'
|
6
|
+
|
7
|
+
begin
|
8
|
+
Engineyard::Recipes::CLI.start
|
9
|
+
rescue EY::Error => e
|
10
|
+
EY.ui.print_exception(e)
|
11
|
+
exit(1)
|
12
|
+
rescue Interrupt => e
|
13
|
+
puts
|
14
|
+
EY.ui.print_exception(e)
|
15
|
+
EY.ui.say("Quitting...")
|
16
|
+
exit(1)
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "engineyard-recipes/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "engineyard-recipes"
|
7
|
+
s.version = Engineyard::Recipes::VERSION
|
8
|
+
s.authors = ["Dr Nic Williams"]
|
9
|
+
s.email = ["drnicwilliams@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Tools to generate, upload, test and apply chef recipes for Engine Yard Cloud.}
|
12
|
+
s.description = %q{Tools to generate, upload, test and apply chef recipes for Engine Yard Cloud.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "engineyard-recipes"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency("thor", ["~> 0.14.6"])
|
22
|
+
s.add_dependency("engineyard", ["~> 1.4.6"])
|
23
|
+
|
24
|
+
s.add_development_dependency("rake", ["~> 0.9.2"])
|
25
|
+
s.add_development_dependency("cucumber", ["~> 1.1.2"])
|
26
|
+
s.add_development_dependency("rspec", ["~> 2.7.0"])
|
27
|
+
# s.add_development_dependency("json")
|
28
|
+
# s.add_development_dependency("awesome_print")
|
29
|
+
# s.add_development_dependency("realweb", '~>0.1.6')
|
30
|
+
# s.add_development_dependency("open4")
|
31
|
+
# s.add_development_dependency("sinatra")
|
32
|
+
# s.add_development_dependency("fakeweb", "~>1.3.0")
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
Feature: Generate a new custom cookbook for your EY Cloud environments
|
2
|
+
|
3
|
+
Scenario: Generate basic cookbook scaffold
|
4
|
+
Given I am in the "rails" project folder
|
5
|
+
When I run local executable "ey-recipes" with arguments "init"
|
6
|
+
And file "cookbooks/main/recipes/default.rb" is created
|
7
|
+
And file "cookbooks/main/libraries/ruby_block.rb" is created
|
8
|
+
And I should see exactly
|
9
|
+
"""
|
10
|
+
create cookbooks
|
11
|
+
create cookbooks/main/attributes/recipe.rb
|
12
|
+
create cookbooks/main/definitions/ey_cloud_report.rb
|
13
|
+
create cookbooks/main/libraries/ruby_block.rb
|
14
|
+
create cookbooks/main/libraries/run_for_app.rb
|
15
|
+
create cookbooks/main/recipes/default.rb
|
16
|
+
|
17
|
+
Lovely.
|
18
|
+
"""
|
@@ -0,0 +1,10 @@
|
|
1
|
+
Given /^I have setup my engineyard email\/password for API access$/ do
|
2
|
+
ENV['EYRC'] = File.join(@home_path, ".eyrc")
|
3
|
+
token = { ENV['CLOUD_URL'] => {
|
4
|
+
"api_token" => "f81a1706ddaeb148cfb6235ddecfc1cf"} }
|
5
|
+
File.open(ENV['EYRC'], "w"){|f| YAML.dump(token, f) }
|
6
|
+
end
|
7
|
+
|
8
|
+
When /^I have "two accounts, two apps, two environments, ambiguous"$/ do
|
9
|
+
api_scenario "two accounts, two apps, two environments, ambiguous"
|
10
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
Given /^this project is active project folder/ do
|
2
|
+
@active_project_folder = File.expand_path(File.dirname(__FILE__) + "/../..")
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^env variable \$([\w_]+) set to( project path|) "(.*)"/ do |env_var, path, value|
|
6
|
+
in_project_folder {
|
7
|
+
value = File.expand_path(value)
|
8
|
+
} unless path.empty?
|
9
|
+
ENV[env_var] = value
|
10
|
+
end
|
11
|
+
|
12
|
+
Given /"(.*)" folder is deleted/ do |folder|
|
13
|
+
in_project_folder { FileUtils.rm_rf folder }
|
14
|
+
end
|
15
|
+
|
16
|
+
When /^I invoke "(.*)" generator with arguments "(.*)"$/ do |generator, arguments|
|
17
|
+
@stdout = StringIO.new
|
18
|
+
in_project_folder do
|
19
|
+
if Object.const_defined?("APP_ROOT")
|
20
|
+
APP_ROOT.replace(FileUtils.pwd)
|
21
|
+
else
|
22
|
+
APP_ROOT = FileUtils.pwd
|
23
|
+
end
|
24
|
+
run_generator(generator, arguments.split(' '), SOURCES, :stdout => @stdout)
|
25
|
+
end
|
26
|
+
File.open(File.join(@tmp_root, "generator.out"), "w") do |f|
|
27
|
+
@stdout.rewind
|
28
|
+
f << @stdout.read
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
When /^I run executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
|
33
|
+
@stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
34
|
+
in_project_folder do
|
35
|
+
system "#{executable.inspect} #{arguments} > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
When /^I run project executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
|
40
|
+
@stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
41
|
+
in_project_folder do
|
42
|
+
system "ruby -rubygems #{executable.inspect} #{arguments} > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
When /^I run local executable "(.*)" with arguments "(.*)"/ do |executable, arguments|
|
47
|
+
if executable == "ey-recipes"
|
48
|
+
require 'engineyard-recipes'
|
49
|
+
require 'engineyard-recipes/cli'
|
50
|
+
in_project_folder do
|
51
|
+
stdout, stderr = capture_stdios do
|
52
|
+
Engineyard::Recipes::CLI.start(arguments.split(/ /))
|
53
|
+
end
|
54
|
+
@stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
55
|
+
File.open(@stdout, "w") {|f| f << stdout; f << stderr}
|
56
|
+
end
|
57
|
+
else
|
58
|
+
@stdout = File.expand_path(File.join(@tmp_root, "executable.out"))
|
59
|
+
executable = File.expand_path(File.join(File.dirname(__FILE__), "/../../bin", executable))
|
60
|
+
in_project_folder do
|
61
|
+
system "ruby -rubygems #{executable.inspect} #{arguments} > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
When /^I invoke task "rake (.*)"/ do |task|
|
67
|
+
@stdout = File.expand_path(File.join(@tmp_root, "tests.out"))
|
68
|
+
in_project_folder do
|
69
|
+
system "bundle exec rake #{task} --trace > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Then /^folder "(.*)" (is|is not) created/ do |folder, is|
|
74
|
+
in_project_folder do
|
75
|
+
File.exists?(folder).should(is == 'is' ? be_true : be_false)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
Then /^file "(.*)" (is|is not) created/ do |file, is|
|
80
|
+
in_project_folder do
|
81
|
+
File.exists?(file).should(is == 'is' ? be_true : be_false)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
Then /^file with name matching "(.*)" is created/ do |pattern|
|
86
|
+
in_project_folder do
|
87
|
+
Dir[pattern].should_not be_empty
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Then /^file "(.*)" contents (does|does not) match \/(.*)\// do |file, does, regex|
|
92
|
+
in_project_folder do
|
93
|
+
actual_output = File.read(file)
|
94
|
+
(does == 'does') ?
|
95
|
+
actual_output.should(match(/#{regex}/)) :
|
96
|
+
actual_output.should_not(match(/#{regex}/))
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
Then /^file "([^"]*)" contains "([^"]*)"$/ do |file, text|
|
101
|
+
in_project_folder do
|
102
|
+
actual_output = File.read(file)
|
103
|
+
actual_output.should contain(text)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
Then /gem file "(.*)" and generated file "(.*)" should be the same/ do |gem_file, project_file|
|
109
|
+
File.exists?(gem_file).should be_true
|
110
|
+
File.exists?(project_file).should be_true
|
111
|
+
gem_file_contents = File.read(File.dirname(__FILE__) + "/../../#{gem_file}")
|
112
|
+
project_file_contents = File.read(File.join(@active_project_folder, project_file))
|
113
|
+
project_file_contents.should == gem_file_contents
|
114
|
+
end
|
115
|
+
|
116
|
+
Then /^(does|does not) invoke generator "(.*)"$/ do |does_invoke, generator|
|
117
|
+
actual_output = get_command_output
|
118
|
+
does_invoke == "does" ?
|
119
|
+
actual_output.should(match(/dependency\s+#{generator}/)) :
|
120
|
+
actual_output.should_not(match(/dependency\s+#{generator}/))
|
121
|
+
end
|
122
|
+
|
123
|
+
Then /help options "(.*)" and "(.*)" are displayed/ do |opt1, opt2|
|
124
|
+
actual_output = get_command_output
|
125
|
+
actual_output.should match(/#{opt1}/)
|
126
|
+
actual_output.should match(/#{opt2}/)
|
127
|
+
end
|
128
|
+
|
129
|
+
Then /^I should see "([^\"]*)"$/ do |text|
|
130
|
+
actual_output = get_command_output
|
131
|
+
actual_output.should contain(text)
|
132
|
+
end
|
133
|
+
|
134
|
+
Then /^I should not see "([^\"]*)"$/ do |text|
|
135
|
+
actual_output =
|
136
|
+
actual_output.should_not contain(text)
|
137
|
+
end
|
138
|
+
|
139
|
+
Then /^I should see$/ do |text|
|
140
|
+
actual_output = get_command_output
|
141
|
+
actual_output.should contain(text)
|
142
|
+
end
|
143
|
+
|
144
|
+
Then /^I should not see$/ do |text|
|
145
|
+
actual_output = get_command_output
|
146
|
+
actual_output.should_not contain(text)
|
147
|
+
end
|
148
|
+
|
149
|
+
Then /^I should see exactly$/ do |text|
|
150
|
+
actual_output = get_command_output
|
151
|
+
actual_output.should == text
|
152
|
+
end
|
153
|
+
|
154
|
+
Then /^I should see all (\d+) tests pass/ do |expected_test_count|
|
155
|
+
expected = %r{^#{expected_test_count} tests, \d+ assertions, 0 failures, 0 errors}
|
156
|
+
actual_output = get_command_output
|
157
|
+
actual_output.should match(expected)
|
158
|
+
end
|
159
|
+
|
160
|
+
Then /^I should see all (\d+) examples pass/ do |expected_test_count|
|
161
|
+
expected = %r{^#{expected_test_count} examples?, 0 failures}
|
162
|
+
actual_output = get_command_output
|
163
|
+
actual_output.should match(expected)
|
164
|
+
end
|
165
|
+
|
166
|
+
Then /^yaml file "(.*)" contains (\{.*\})/ do |file, yaml|
|
167
|
+
in_project_folder do
|
168
|
+
yaml = eval yaml
|
169
|
+
YAML.load(File.read(file)).should == yaml
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
Then /^Rakefile can display tasks successfully/ do
|
174
|
+
@stdout = File.expand_path(File.join(@tmp_root, "rakefile.out"))
|
175
|
+
in_project_folder do
|
176
|
+
system "rake -T > #{@stdout.inspect} 2> #{@stdout.inspect}"
|
177
|
+
end
|
178
|
+
actual_output = get_command_output
|
179
|
+
actual_output.should match(/^rake\s+\w+\s+#\s.*/)
|
180
|
+
end
|
181
|
+
|
182
|
+
Then /^task "rake (.*)" is executed successfully/ do |task|
|
183
|
+
@stdout.should_not be_nil
|
184
|
+
actual_output = get_command_output
|
185
|
+
actual_output.should_not match(/^Don't know how to build task '#{task}'/)
|
186
|
+
actual_output.should_not match(/Error/i)
|
187
|
+
end
|
188
|
+
|
189
|
+
Then /^gem spec key "(.*)" contains \/(.*)\// do |key, regex|
|
190
|
+
in_project_folder do
|
191
|
+
gem_file = Dir["pkg/*.gem"].first
|
192
|
+
gem_spec = Gem::Specification.from_yaml(`gem spec #{gem_file}`)
|
193
|
+
spec_value = gem_spec.send(key.to_sym)
|
194
|
+
spec_value.to_s.should match(/#{regex}/)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
Then /^the file "([^\"]*)" is a valid gemspec$/ do |filename|
|
199
|
+
spec = eval(File.read(filename))
|
200
|
+
spec.validate
|
201
|
+
end
|
202
|
+
|
203
|
+
When /^I create a new node with the following options on "http:\/\/(.+?):(\d+)":$/ do |host, port, table|
|
204
|
+
options = table.raw.inject({}) do |options, (key, value)|
|
205
|
+
options[(key.to_sym rescue key) || key] = value
|
206
|
+
options
|
207
|
+
end
|
208
|
+
|
209
|
+
Recipes::Api.setup_base_url(:host => host, :port => port.to_i)
|
210
|
+
Recipes::Api.add_node(options)
|
211
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Given /^I am in the "([^\"]*)" project folder$/ do |project|
|
2
|
+
project_folder = File.expand_path(File.join(@fixtures_path, "projects", project))
|
3
|
+
in_tmp_folder do
|
4
|
+
FileUtils.cp_r(project_folder, project)
|
5
|
+
setup_active_project_folder(project)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^I already have cookbooks installed$/ do
|
10
|
+
cookbooks_folder = File.expand_path(File.join(@fixtures_path, "cookbooks"))
|
11
|
+
in_project_folder do
|
12
|
+
FileUtils.cp_r(cookbooks_folder, ".")
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Given /^I want to fake out the boot sequence of Recipes$/ do
|
2
|
+
base_path = File.join(File.dirname(__FILE__) + "/../../fixtures/Recipes_boot_sequence/")
|
3
|
+
FakeWeb.register_uri(:get, "http://app-master-hostname.compute-1.amazonaws.com/", [
|
4
|
+
{:body => File.read(base_path + "pre_Recipes_booting.html")},
|
5
|
+
{:body => File.read(base_path + "Recipes_booting.html")},
|
6
|
+
{:body => File.read(base_path + "Recipes_ready.html")}
|
7
|
+
])
|
8
|
+
end
|
9
|
+
|
10
|
+
Given /^I have public key "([^"]*)" on host "([^"]*)"$/ do |public_key_value, host|
|
11
|
+
mock_target = File.expand_path("../../../tmp/scp_mock", __FILE__)
|
12
|
+
File.open(mock_target, "w") { |file| file << public_key_value }
|
13
|
+
end
|
14
|
+
|
15
|
+
Given /^I set "([^"]*)" as the default Recipes server$/ do |host|
|
16
|
+
require "Recipes"
|
17
|
+
require "Recipes/config"
|
18
|
+
Recipes::Api.setup_base_url(:host => host, :port => 80)
|
19
|
+
Recipes::Api.send(:cache_base_uri)
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module CommonHelpers
|
2
|
+
def get_command_output
|
3
|
+
strip_color_codes(File.read(@stdout)).chomp
|
4
|
+
end
|
5
|
+
|
6
|
+
def strip_color_codes(text)
|
7
|
+
text.gsub(/\e\[\d+m/, '')
|
8
|
+
end
|
9
|
+
|
10
|
+
def in_tmp_folder(&block)
|
11
|
+
FileUtils.chdir(@tmp_root, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def in_project_folder(&block)
|
15
|
+
project_folder = @active_project_folder || @tmp_root
|
16
|
+
FileUtils.chdir(project_folder, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def in_home_folder(&block)
|
20
|
+
FileUtils.chdir(@home_path, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def force_local_lib_override(project_name = @project_name)
|
24
|
+
rakefile = File.read(File.join(project_name, 'Rakefile'))
|
25
|
+
File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
|
26
|
+
f << "$:.unshift('#{@lib_path}')\n"
|
27
|
+
f << rakefile
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_active_project_folder project_name
|
32
|
+
@active_project_folder = File.join(@tmp_root, project_name)
|
33
|
+
@project_name = project_name
|
34
|
+
end
|
35
|
+
|
36
|
+
# capture both [stdout, stderr] as well as stdin
|
37
|
+
def capture_stdios(input = nil, &block)
|
38
|
+
require 'stringio'
|
39
|
+
org_stdin, $stdin = $stdin, StringIO.new(input) if input
|
40
|
+
org_stdout, $stdout = $stdout, StringIO.new
|
41
|
+
org_stderr, $stderr = $stdout, StringIO.new
|
42
|
+
yield
|
43
|
+
return [$stdout.string, $stderr.string]
|
44
|
+
ensure
|
45
|
+
$stderr = org_stderr
|
46
|
+
$stdout = org_stdout
|
47
|
+
$stdin = org_stdin
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
World(CommonHelpers)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../lib'))
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'engineyard-recipes'
|
4
|
+
|
5
|
+
path = ENV['PATH']
|
6
|
+
|
7
|
+
Before do
|
8
|
+
@tmp_root = File.dirname(__FILE__) + "/../../tmp"
|
9
|
+
@active_project_folder = @tmp_root
|
10
|
+
@home_path = File.expand_path(File.join(@tmp_root, "home"))
|
11
|
+
@lib_path = File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
12
|
+
@fixtures_path = File.expand_path(File.dirname(__FILE__) + "/../../fixtures")
|
13
|
+
FileUtils.rm_rf @tmp_root
|
14
|
+
FileUtils.mkdir_p @home_path
|
15
|
+
ENV['HOME'] = @home_path
|
16
|
+
fixture_bin_path = File.expand_path('../../../fixtures/bin', __FILE__)
|
17
|
+
ENV['PATH'] = fixture_bin_path + ":" + path
|
18
|
+
end
|
data/fixtures/bin/scp
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_recipe 'redis'
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
Please wait while Recipes is getting ready to work
|
@@ -0,0 +1 @@
|
|
1
|
+
Recipes is up!
|
@@ -0,0 +1 @@
|
|
1
|
+
This is some page before the instance is launched.
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'engineyard-recipes/thor-ext/actions/directory'
|
3
|
+
|
4
|
+
module Engineyard
|
5
|
+
module Recipes
|
6
|
+
class CLI < Thor
|
7
|
+
|
8
|
+
desc "init", "Creates cookbooks scaffolding for your recipes"
|
9
|
+
def init
|
10
|
+
require 'engineyard-recipes/generators/init_generator'
|
11
|
+
Engineyard::Recipes::Generators::InitGenerator.start
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "version", "show version information"
|
15
|
+
def version
|
16
|
+
require 'engineyard-recipes/version'
|
17
|
+
shell.say Engineyard::Recipes::VERSION
|
18
|
+
end
|
19
|
+
|
20
|
+
map "-v" => :version, "--version" => :version, "-h" => :help, "--help" => :help
|
21
|
+
|
22
|
+
private
|
23
|
+
def say(msg, color = nil)
|
24
|
+
color ? shell.say(msg, color) : shell.say(msg)
|
25
|
+
end
|
26
|
+
|
27
|
+
def display(text)
|
28
|
+
shell.say text
|
29
|
+
exit
|
30
|
+
end
|
31
|
+
|
32
|
+
def error(text)
|
33
|
+
shell.say "ERROR: #{text}", :red
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the [host, port] for the target Recipes CI server
|
38
|
+
def host_port(options)
|
39
|
+
require "recipes"
|
40
|
+
require "recipes/config"
|
41
|
+
if base_uri = ::Recipes::Config.config['base_uri']
|
42
|
+
uri = URI.parse(::Recipes::Config.config['base_uri'])
|
43
|
+
host = uri.host
|
44
|
+
port = uri.port
|
45
|
+
end
|
46
|
+
host = options["host"] if options["host"]
|
47
|
+
port = options["port"] || port || '80'
|
48
|
+
[host, port]
|
49
|
+
end
|
50
|
+
|
51
|
+
def no_environments_discovered
|
52
|
+
say "No environments with name recipes, recipes_server, recipes_production, recipes_server_production.", :red
|
53
|
+
say "Either:"
|
54
|
+
say " * Create an Engine Yard Cloud environment called recipes, recipes_server, recipes_production, recipes_server_production"
|
55
|
+
say " * Use --environment/--account flags to select Engine Yard Cloud environment"
|
56
|
+
end
|
57
|
+
|
58
|
+
def too_many_environments_discovered(environments)
|
59
|
+
say "Multiple environments possible, please be more specific:", :red
|
60
|
+
say ""
|
61
|
+
environments.each do |env_name, account_name, environment|
|
62
|
+
say " ey-recipes install_server --environment "; say "'#{env_name}' ", :yellow;
|
63
|
+
say "--account "; say "'#{account_name}'", :yellow
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def watch_page_while(host, port, path)
|
68
|
+
waiting = true
|
69
|
+
while waiting
|
70
|
+
begin
|
71
|
+
Net::HTTP.start(host, port) do |http|
|
72
|
+
req = http.get(path)
|
73
|
+
waiting = yield req
|
74
|
+
end
|
75
|
+
sleep 1; print '.'; $stdout.flush
|
76
|
+
rescue SocketError => e
|
77
|
+
sleep 1; print 'x'; $stdout.flush
|
78
|
+
rescue Exception => e
|
79
|
+
puts e.message
|
80
|
+
sleep 1; print '.'; $stdout.flush
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
class Chef
|
3
|
+
class Resource
|
4
|
+
class RubyBlock < Chef::Resource
|
5
|
+
def initialize(name, collection=nil, node=nil)
|
6
|
+
super(name, collection, node)
|
7
|
+
@resource_name = :ruby_block
|
8
|
+
@action = :create
|
9
|
+
@allowed_actions.push(:create)
|
10
|
+
end
|
11
|
+
|
12
|
+
def block(&block)
|
13
|
+
if block
|
14
|
+
@block = block
|
15
|
+
else
|
16
|
+
@block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
class Chef
|
25
|
+
class Provider
|
26
|
+
class RubyBlock < Chef::Provider
|
27
|
+
def load_current_resource
|
28
|
+
Chef::Log.debug(@new_resource.inspect)
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def action_create
|
33
|
+
@new_resource.block.call
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Chef::Platform.platforms[:default].merge! :ruby_block => Chef::Provider::RubyBlock
|
40
|
+
|
data/lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/recipes/default.rb
ADDED
File without changes
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'thor/group'
|
2
|
+
|
3
|
+
module Engineyard::Recipes
|
4
|
+
module Generators
|
5
|
+
class InitGenerator < Thor::Group
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
def self.source_root
|
9
|
+
File.join(File.dirname(__FILE__), "init_generator", "templates")
|
10
|
+
end
|
11
|
+
|
12
|
+
def install_cookbooks
|
13
|
+
file = "cookbooks/main/recipes/default.rb"
|
14
|
+
unless File.exists?(File.join(destination_root, "cookbooks/main/recipes/default.rb"))
|
15
|
+
directory "cookbooks"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# def attributes
|
20
|
+
# template "attributes.rb.tt", "cookbooks/recipes_slave/attributes/default.rb"
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# def recipe
|
24
|
+
# copy_file "recipes.rb", "cookbooks/recipes_slave/recipes/default.rb"
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
def readme
|
28
|
+
say ""
|
29
|
+
say "Lovely.", :green
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def say(msg, color = nil)
|
34
|
+
color ? shell.say(msg, color) : shell.say(msg)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Extension: Sorts the Dir[lookup] to ensure deterministic ordering of actions
|
2
|
+
# to allow test assertions
|
3
|
+
|
4
|
+
class Thor
|
5
|
+
module Actions
|
6
|
+
class Directory < EmptyDirectory #:nodoc:
|
7
|
+
protected
|
8
|
+
|
9
|
+
def execute!
|
10
|
+
lookup = config[:recursive] ? File.join(source, '**') : source
|
11
|
+
lookup = File.join(lookup, '{*,.[a-z]*}')
|
12
|
+
|
13
|
+
Dir[lookup].sort.each do |file_source|
|
14
|
+
next if File.directory?(file_source)
|
15
|
+
file_destination = File.join(given_destination, file_source.gsub(source, '.'))
|
16
|
+
file_destination.gsub!('/./', '/')
|
17
|
+
|
18
|
+
case file_source
|
19
|
+
when /\.empty_directory$/
|
20
|
+
dirname = File.dirname(file_destination).gsub(/\/\.$/, '')
|
21
|
+
next if dirname == given_destination
|
22
|
+
base.empty_directory(dirname, config)
|
23
|
+
when /\.tt$/
|
24
|
+
destination = base.template(file_source, file_destination[0..-4], config, &@block)
|
25
|
+
else
|
26
|
+
destination = base.copy_file(file_source, file_destination, config, &@block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: engineyard-recipes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dr Nic Williams
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-13 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: &70345820762760 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.14.6
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70345820762760
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: engineyard
|
27
|
+
requirement: &70345820762200 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.4.6
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70345820762200
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rake
|
38
|
+
requirement: &70345820761680 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.2
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70345820761680
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: cucumber
|
49
|
+
requirement: &70345820761180 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.1.2
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70345820761180
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rspec
|
60
|
+
requirement: &70345820760660 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 2.7.0
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70345820760660
|
69
|
+
description: Tools to generate, upload, test and apply chef recipes for Engine Yard
|
70
|
+
Cloud.
|
71
|
+
email:
|
72
|
+
- drnicwilliams@gmail.com
|
73
|
+
executables:
|
74
|
+
- ey-recipes
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- .gitignore
|
79
|
+
- Gemfile
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- bin/ey-recipes
|
83
|
+
- engineyard-recipes.gemspec
|
84
|
+
- features/init-new-cookbook.feature
|
85
|
+
- features/step_definitions/api_steps.rb
|
86
|
+
- features/step_definitions/common_steps.rb
|
87
|
+
- features/step_definitions/fixture_project_steps.rb
|
88
|
+
- features/step_definitions/jenkins_steps.rb
|
89
|
+
- features/support/common.rb
|
90
|
+
- features/support/env.rb
|
91
|
+
- features/support/matchers.rb
|
92
|
+
- fixtures/bin/README.md
|
93
|
+
- fixtures/bin/scp
|
94
|
+
- fixtures/cookbooks/main/recipes/default.rb
|
95
|
+
- fixtures/cookbooks/redis/recipes/default.rb
|
96
|
+
- fixtures/jenkins_boot_sequence/jenkins_booting.html
|
97
|
+
- fixtures/jenkins_boot_sequence/jenkins_ready.html
|
98
|
+
- fixtures/jenkins_boot_sequence/pre_jenkins_booting.html
|
99
|
+
- fixtures/projects/rails/Gemfile
|
100
|
+
- fixtures/projects/rails/Rakefile
|
101
|
+
- lib/engineyard-recipes.rb
|
102
|
+
- lib/engineyard-recipes/cli.rb
|
103
|
+
- lib/engineyard-recipes/generators/init_generator.rb
|
104
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/attributes/recipe.rb
|
105
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/definitions/ey_cloud_report.rb
|
106
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/libraries/ruby_block.rb
|
107
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/libraries/run_for_app.rb
|
108
|
+
- lib/engineyard-recipes/generators/init_generator/templates/cookbooks/main/recipes/default.rb
|
109
|
+
- lib/engineyard-recipes/thor-ext/actions/directory.rb
|
110
|
+
- lib/engineyard-recipes/version.rb
|
111
|
+
homepage: ''
|
112
|
+
licenses: []
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
segments:
|
124
|
+
- 0
|
125
|
+
hash: -3089194490767720342
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
segments:
|
133
|
+
- 0
|
134
|
+
hash: -3089194490767720342
|
135
|
+
requirements: []
|
136
|
+
rubyforge_project: engineyard-recipes
|
137
|
+
rubygems_version: 1.8.6
|
138
|
+
signing_key:
|
139
|
+
specification_version: 3
|
140
|
+
summary: Tools to generate, upload, test and apply chef recipes for Engine Yard Cloud.
|
141
|
+
test_files:
|
142
|
+
- features/init-new-cookbook.feature
|
143
|
+
- features/step_definitions/api_steps.rb
|
144
|
+
- features/step_definitions/common_steps.rb
|
145
|
+
- features/step_definitions/fixture_project_steps.rb
|
146
|
+
- features/step_definitions/jenkins_steps.rb
|
147
|
+
- features/support/common.rb
|
148
|
+
- features/support/env.rb
|
149
|
+
- features/support/matchers.rb
|