bently 0.0.0 → 0.1.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.
- data/Gemfile +2 -2
- data/Gemfile.lock +18 -0
- data/README.md +123 -0
- data/bently.gemspec +5 -1
- data/bin/bently +2 -6
- data/lib/bently/clo.rb +33 -0
- data/lib/bently/himself.rb +105 -0
- data/lib/bently/recipe/action-mailer.rb +82 -0
- data/lib/bently/recipe/devise.rb +13 -11
- data/lib/bently/recipe/factory-girl-rails.rb +35 -0
- data/lib/bently/recipe/gitignore-rails.rb +52 -0
- data/lib/bently/recipe/gitignore.rb +12 -7
- data/lib/bently/recipe/guard-livereload.rb +11 -0
- data/lib/bently/recipe/guard.rb +11 -0
- data/lib/bently/recipe/haml-rails.rb +4 -9
- data/lib/bently/recipe/heroku-create.rb +27 -0
- data/lib/bently/recipe/heroku-procfile.rb +14 -0
- data/lib/bently/recipe/heroku-resque.rb +79 -0
- data/lib/bently/recipe/heroku-sendgrid.rb +37 -0
- data/lib/bently/recipe/resque.rb +5 -1
- data/lib/bently/recipe/rspec-rails.rb +16 -11
- data/lib/bently/recipe/rvmrc.rb +18 -0
- data/lib/bently/recipe/twitter-bootstrap-rails.rb +4 -10
- data/lib/bently/recipe/welcome-index.rb +2 -10
- data/lib/bently/recipe.rb +37 -107
- data/lib/bently/recipe_book.rb +15 -0
- data/lib/bently/recipe_template/rails.rb +13 -0
- data/lib/bently/step.rb +93 -0
- data/lib/bently/version.rb +5 -0
- data/lib/bently.rb +11 -1
- data/spec/bently/himself_spec.rb +175 -0
- data/spec/spec_helper.rb +24 -0
- metadata +43 -6
- data/lib/bently/cli.rb +0 -27
@@ -0,0 +1,79 @@
|
|
1
|
+
module Bently
|
2
|
+
|
3
|
+
class HerokuResque < RailsRecipe
|
4
|
+
|
5
|
+
step :shell, 'echo', :description => "WARNING:\nSome steps in this recipe may incur fees to your Heroku account. By proceeding you agree to bear full responsibility for fees charged to you as a result.", :action => 'proceed', :fail_on_skip => true
|
6
|
+
step :add_gem, "gem 'resque', \"~> 1.22.0\""
|
7
|
+
step :shell, 'bundle install'
|
8
|
+
step :append, :file => 'Procfile', :with => 'resque: env TERM_CHILD=1 bundle exec rake jobs:work'
|
9
|
+
step :touch_rakefile
|
10
|
+
step :touch_sample_worker
|
11
|
+
step :prepend, :file => 'config/routes.rb', :with => "require 'resque/server'"
|
12
|
+
step :mount_resque_server
|
13
|
+
step :shell, "heroku addons:add redistogo:nano"
|
14
|
+
step :shell, 'heroku config | grep REDISTOGO_URL'
|
15
|
+
step :touch_resque_initializer
|
16
|
+
step :shell, 'echo REDISTOGO_URL=redis://localhost:6379 >> .env;more .env'
|
17
|
+
step :shell, 'heroku ps:scale resque=1'
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def touch_rakefile
|
22
|
+
touch(
|
23
|
+
:file => "./lib/tasks/resque.rake",
|
24
|
+
:with => rakefile
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def rakefile
|
29
|
+
%{require 'resque/tasks'
|
30
|
+
|
31
|
+
task "resque:setup" => :environment do
|
32
|
+
ENV['QUEUE'] = '*'
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Alias for resque:work (To run workers on Heroku)"
|
36
|
+
task "jobs:work" => "resque:work"}
|
37
|
+
end
|
38
|
+
|
39
|
+
def touch_sample_worker
|
40
|
+
touch(
|
41
|
+
:file => './app/workers/sample_worker.rb',
|
42
|
+
:with => sample_worker
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def sample_worker
|
47
|
+
%{# class SampleWorker
|
48
|
+
# @queue = :sample
|
49
|
+
#
|
50
|
+
# def self.perform(resource_id)
|
51
|
+
# resource = Resource.find(resource_id)
|
52
|
+
# resource.do_something!
|
53
|
+
# end
|
54
|
+
# end}
|
55
|
+
end
|
56
|
+
|
57
|
+
def mount_resque_server
|
58
|
+
insert(
|
59
|
+
:file => 'config/routes.rb',
|
60
|
+
:with => " mount Resque::Server.new, :at => \"/resque\"\n",
|
61
|
+
:after => "Application.routes.draw do\n"
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def touch_resque_initializer
|
66
|
+
touch :file => 'config/initializers/resque.rb', :with => resque_initializer
|
67
|
+
end
|
68
|
+
|
69
|
+
def resque_initializer
|
70
|
+
%{# don't initialize unless ENV hash is present
|
71
|
+
if ENV["REDISTOGO_URL"].present?
|
72
|
+
uri = URI.parse(ENV["REDISTOGO_URL"])
|
73
|
+
Resque.redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
|
74
|
+
end}
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Bently
|
2
|
+
|
3
|
+
class HerokuSendgrid < RailsRecipe
|
4
|
+
|
5
|
+
step :heroku, 'addons:add sendgrid:starter'
|
6
|
+
step :touch_mail_initializer
|
7
|
+
|
8
|
+
protected
|
9
|
+
|
10
|
+
def heroku command
|
11
|
+
shell("heroku #{command}")
|
12
|
+
end
|
13
|
+
|
14
|
+
def touch_mail_initializer
|
15
|
+
touch(
|
16
|
+
:file => "./config/initializers/mail.rb",
|
17
|
+
:with => mail_initializer
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def mail_initializer
|
22
|
+
%{
|
23
|
+
ActionMailer::Base.smtp_settings = {
|
24
|
+
:address => 'smtp.sendgrid.net',
|
25
|
+
:port => '587',
|
26
|
+
:authentication => :plain,
|
27
|
+
:user_name => ENV['SENDGRID_USERNAME'],
|
28
|
+
:password => ENV['SENDGRID_PASSWORD'],
|
29
|
+
:domain => 'heroku.com'
|
30
|
+
}
|
31
|
+
ActionMailer::Base.delivery_method = :smtp
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/lib/bently/recipe/resque.rb
CHANGED
@@ -1,18 +1,23 @@
|
|
1
1
|
module Bently
|
2
2
|
|
3
|
-
class RspecRails <
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
class RspecRails < RailsRecipe
|
4
|
+
|
5
|
+
step :add_gem
|
6
|
+
step :shell, 'bundle install'
|
7
|
+
step :shell, "rails g rspec:install"
|
8
|
+
|
9
|
+
protected
|
9
10
|
|
10
|
-
def
|
11
|
-
|
12
|
-
bundle_install
|
13
|
-
command RAILS_GENERATOR
|
14
|
-
super
|
11
|
+
def add_gem
|
12
|
+
super gem_def
|
15
13
|
end
|
14
|
+
|
15
|
+
def gem_def
|
16
|
+
%{group :test, :development do
|
17
|
+
gem "rspec-rails", "~> 2.0"
|
18
|
+
end}
|
19
|
+
end
|
20
|
+
|
16
21
|
end
|
17
22
|
|
18
23
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Bently
|
2
|
+
|
3
|
+
class Rvmrc < Recipe
|
4
|
+
|
5
|
+
step :touch_rvmrc
|
6
|
+
|
7
|
+
def touch_rvmrc
|
8
|
+
ruby_version = `rvm current`.chomp
|
9
|
+
shell(
|
10
|
+
lambda{|gemset| "echo \"rvm use --create #{ruby_version}@#{gemset}\" > .rvmrc" },
|
11
|
+
:ask => "Enter a gemset name:",
|
12
|
+
:description => "Touch .rvmrc:\nrvm use --create #{ruby_version}@<gemset>"
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -1,16 +1,10 @@
|
|
1
1
|
module Bently
|
2
2
|
|
3
|
-
class TwitterBootstrapRails <
|
3
|
+
class TwitterBootstrapRails < RailsRecipe
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def bake
|
9
|
-
add_gem(GEMFILE_DEF) || return
|
10
|
-
bundle_install
|
11
|
-
command RAILS_GENERATOR
|
12
|
-
super
|
13
|
-
end
|
5
|
+
step :add_gem, 'gem "twitter-bootstrap-rails", :group => :assets'
|
6
|
+
step :shell, 'bundle install'
|
7
|
+
step :shell, 'rails g bootstrap:install'
|
14
8
|
|
15
9
|
end
|
16
10
|
|
@@ -2,16 +2,8 @@ module Bently
|
|
2
2
|
|
3
3
|
class WelcomeIndex < Recipe
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
GSUB_SEARCH = /#\s*(root :to => 'welcome#index')/
|
8
|
-
GSUB_REPLACE = '\1'
|
9
|
-
|
10
|
-
def bake
|
11
|
-
command RAILS_GENERATE
|
12
|
-
gsub_file ROUTES_FILE, GSUB_SEARCH, GSUB_REPLACE
|
13
|
-
super
|
14
|
-
end
|
5
|
+
step :shell, 'bundle exec rails g controller welcome index'
|
6
|
+
step :modify, :file => 'config/routes.rb', :from => /#\s*(root :to => 'welcome#index')/, :to => '\1'
|
15
7
|
|
16
8
|
end
|
17
9
|
|
data/lib/bently/recipe.rb
CHANGED
@@ -1,133 +1,63 @@
|
|
1
1
|
module Bently
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
RECIPE_DIR = "#{BENTLY_REPOSITORY}/lib/bently/recipe/*.rb"
|
7
|
-
|
8
|
-
# list all recipes
|
9
|
-
def self.list
|
10
|
-
Dir[RECIPE_DIR].map{ |f| File.basename f, '.rb' }.sort
|
2
|
+
|
3
|
+
module RecipeMethods
|
4
|
+
def self.extended(base)
|
5
|
+
base.send(:include, InstanceMethods) if base.is_a? Class
|
11
6
|
end
|
12
7
|
|
13
|
-
|
14
|
-
|
15
|
-
"Bently::#{name.camelize}".constantize
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
def initialize options={}
|
21
|
-
@read_only = options[:read_only]
|
8
|
+
def step(*args)
|
9
|
+
step_args << args
|
22
10
|
end
|
23
11
|
|
24
|
-
|
25
|
-
|
26
|
-
puts_step "Done!"
|
12
|
+
def step_args
|
13
|
+
@steps_args ||= []
|
27
14
|
end
|
28
15
|
|
29
|
-
|
30
|
-
|
31
|
-
# instance to CLI
|
32
|
-
# for access to Thor helper methods
|
33
|
-
def cli; @cli ||= CLI.new end
|
34
|
-
|
35
|
-
# add a gem to the Gemfile
|
36
|
-
def add_gem gem_def
|
37
|
-
unless @read_only
|
38
|
-
if confirm_step "Add to Gemfile"
|
39
|
-
begin
|
40
|
-
cli.append_to_file 'Gemfile', gem_def
|
41
|
-
rescue
|
42
|
-
puts "Gemfile was not found. Aborting.."
|
43
|
-
return false
|
44
|
-
end
|
45
|
-
end
|
46
|
-
else
|
47
|
-
puts_quote_step "Add to Gemfile", gem_def
|
48
|
-
end
|
49
|
-
true
|
50
|
-
end
|
16
|
+
private
|
51
17
|
|
52
|
-
|
53
|
-
|
54
|
-
|
18
|
+
def inherited(subclass)
|
19
|
+
super
|
20
|
+
subclass.step_args.concat self.step_args
|
55
21
|
end
|
56
22
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
puts `#{cmd}` if confirm_step cmd
|
61
|
-
else
|
62
|
-
puts_step cmd
|
23
|
+
module InstanceMethods
|
24
|
+
def steps
|
25
|
+
@steps ||= parse_steps
|
63
26
|
end
|
64
|
-
end
|
65
27
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
puts `#{yield resp}`
|
28
|
+
protected
|
29
|
+
|
30
|
+
def parse_steps
|
31
|
+
self.class.step_args.map do |args|
|
32
|
+
self.send(args.shift, *args)
|
72
33
|
end
|
73
|
-
else
|
74
|
-
puts_step cmd
|
75
34
|
end
|
76
35
|
end
|
36
|
+
end
|
77
37
|
|
78
|
-
|
79
|
-
|
80
|
-
unless @read_only
|
81
|
-
cli.create_file destination, data if confirm_step "Touch #{destination}"
|
82
|
-
else
|
83
|
-
puts_quote_step "Touch #{destination}", data
|
84
|
-
end
|
85
|
-
end
|
38
|
+
class Recipe
|
39
|
+
extend RecipeMethods
|
86
40
|
|
87
|
-
#
|
88
|
-
def
|
89
|
-
unless @read_only
|
90
|
-
if confirm_step "Edit #{file}"
|
91
|
-
cli.gsub_file file, search, replace
|
92
|
-
end
|
93
|
-
else
|
94
|
-
puts_step "Edit #{file}"
|
95
|
-
end
|
96
|
-
end
|
41
|
+
# step :shell, command
|
42
|
+
def shell(*args); StepShell.new(*args) end
|
97
43
|
|
98
|
-
#
|
99
|
-
def
|
100
|
-
puts_step "#{text}"
|
101
|
-
puts
|
102
|
-
puts "#{quote}"
|
103
|
-
puts
|
104
|
-
end
|
44
|
+
# step :touch, :file => filename, :with => data
|
45
|
+
def touch(*args) StepTouch.new(*args) end
|
105
46
|
|
106
|
-
#
|
107
|
-
def
|
108
|
-
cli.yes? "#{magenta('==>')} #{bold(text)}?"
|
109
|
-
end
|
47
|
+
# step :modify, :file => filename, :from => pattern, :to => replacement
|
48
|
+
def modify(*args) StepModify.new(*args) end
|
110
49
|
|
111
|
-
#
|
112
|
-
def
|
113
|
-
puts "#{magenta('==>')} #{bold(text)}"
|
114
|
-
end
|
50
|
+
# step :append, :file => filename, :with => data
|
51
|
+
def append(*args) StepAppend.new(*args) end
|
115
52
|
|
116
|
-
#
|
117
|
-
def
|
118
|
-
"#{color_code}#{text}\033[0m"
|
119
|
-
end
|
53
|
+
# step :prepend, :file => filename, :with => data
|
54
|
+
def prepend(*args) StepPrepend.new(*args) end
|
120
55
|
|
121
|
-
|
122
|
-
def
|
123
|
-
def magenta(text); colorize(text, "\033[35m"); end
|
124
|
-
def light_green(text); colorize(text, "\033[32m"); end
|
125
|
-
def bold(text); "\033[1m#{text}\033[22m"; end
|
56
|
+
# step :insert, :file => filename, :with => data, :after => some_text
|
57
|
+
def insert(*args) StepInsert.new(*args) end
|
126
58
|
|
59
|
+
# step :remove, :file => filename
|
60
|
+
def remove(*args) StepRemove.new(*args) end
|
127
61
|
end
|
128
|
-
end
|
129
62
|
|
130
|
-
# load recipes
|
131
|
-
Dir["#{Bently::BENTLY_REPOSITORY}/lib/bently/recipe/*.rb"].map{ |f| File.basename f, '.rb' }.each do |f|
|
132
|
-
require 'bently/recipe/' + f
|
133
63
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Bently
|
2
|
+
|
3
|
+
class RecipeBook
|
4
|
+
|
5
|
+
RECIPE_DIR = "#{BENTLY_REPOSITORY}/lib/bently/recipe/*.rb"
|
6
|
+
|
7
|
+
def self.all
|
8
|
+
Dir[RECIPE_DIR].map{ |f| File.basename f, '.rb' }.sort
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.find(recipe)
|
12
|
+
"Bently::#{recipe.camelize}".constantize
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/bently/step.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
module Bently
|
2
|
+
|
3
|
+
class Step
|
4
|
+
def initialize(*args)
|
5
|
+
end
|
6
|
+
def question; nil end
|
7
|
+
def fail_on_skip?; false end
|
8
|
+
end
|
9
|
+
|
10
|
+
class StepShell < Step
|
11
|
+
attr_reader :command
|
12
|
+
def initialize(*args)
|
13
|
+
@command = args.shift
|
14
|
+
@options = args.first || {}
|
15
|
+
end
|
16
|
+
def action; @options[:action] || 'execute' end
|
17
|
+
def question; @options[:ask] end
|
18
|
+
def description
|
19
|
+
return @options[:description] if @options[:description]
|
20
|
+
command_desc = command
|
21
|
+
if command_desc.is_a?(Proc)
|
22
|
+
placeholder = '...'
|
23
|
+
command_desc = command_desc.yield(placeholder)
|
24
|
+
end
|
25
|
+
"Execute:\n#{command_desc}"
|
26
|
+
end
|
27
|
+
def fail_on_skip?; @options[:fail_on_skip] end
|
28
|
+
end
|
29
|
+
|
30
|
+
class StepTouch < Step
|
31
|
+
attr_reader :file, :data
|
32
|
+
def initialize(*args)
|
33
|
+
opts = args.first
|
34
|
+
@file, @data = [:file,:with].map{|k| opts[k]}
|
35
|
+
end
|
36
|
+
def action; 'touch' end
|
37
|
+
def description; "Touch #{file}:\n#{data}" end
|
38
|
+
end
|
39
|
+
|
40
|
+
class StepModify < Step
|
41
|
+
attr_reader :file, :pattern, :replacement
|
42
|
+
def initialize(*args)
|
43
|
+
opts = args.first
|
44
|
+
@file, @pattern, @replacement = [:file,:from,:to].map{|k| opts[k]}
|
45
|
+
end
|
46
|
+
def action; 'modify' end
|
47
|
+
def description
|
48
|
+
"Modify #{file}:\n#{pattern.inspect} =>\n#{replacement}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class StepAppend < Step
|
53
|
+
attr_reader :file, :data
|
54
|
+
def initialize(*args)
|
55
|
+
opts = args.first
|
56
|
+
@file, @data = [:file,:with].map{|k| opts[k]}
|
57
|
+
end
|
58
|
+
def action; 'append' end
|
59
|
+
def description; "Append to #{file}:\n#{data}" end
|
60
|
+
end
|
61
|
+
|
62
|
+
class StepPrepend < Step
|
63
|
+
attr_reader :file, :data
|
64
|
+
def initialize(*args)
|
65
|
+
opts = args.first
|
66
|
+
@file, @data = [:file,:with].map{|k| opts[k]}
|
67
|
+
end
|
68
|
+
def action; 'prepend' end
|
69
|
+
def description; "Prepend to #{file}:\n#{data}" end
|
70
|
+
end
|
71
|
+
|
72
|
+
class StepInsert < Step
|
73
|
+
attr_reader :file, :data, :options
|
74
|
+
def initialize(*args)
|
75
|
+
opts = args.first
|
76
|
+
@file, @data = [:file,:with].map{|k| opts.delete(k) }
|
77
|
+
@options = opts
|
78
|
+
end
|
79
|
+
def action; 'insert' end
|
80
|
+
def description; "Insert into #{file}:\n#{data}" end
|
81
|
+
end
|
82
|
+
|
83
|
+
class StepRemove < Step
|
84
|
+
attr_reader :file
|
85
|
+
def initialize(*args)
|
86
|
+
opts = args.first
|
87
|
+
@file = opts.delete(:file)
|
88
|
+
end
|
89
|
+
def action; 'remove' end
|
90
|
+
def description; "Remove #{file}" end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/lib/bently.rb
CHANGED
@@ -2,6 +2,16 @@ require 'thor'
|
|
2
2
|
|
3
3
|
require 'bently/core_ext/string'
|
4
4
|
require 'bently/globals'
|
5
|
-
require 'bently/
|
5
|
+
require 'bently/step'
|
6
6
|
require 'bently/recipe'
|
7
|
+
require 'bently/recipe_template/rails.rb'
|
8
|
+
require 'bently/recipe_book'
|
9
|
+
require 'bently/clo'
|
10
|
+
require 'bently/himself'
|
11
|
+
|
12
|
+
Dir[Bently::RecipeBook::RECIPE_DIR].map do |f|
|
13
|
+
File.basename f, '.rb'
|
14
|
+
end.each do |f|
|
15
|
+
require 'bently/recipe/' + f
|
16
|
+
end
|
7
17
|
|