shoelaces 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +11 -0
  5. data/CONTRIBUTING.md +37 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +131 -0
  8. data/LICENSE +21 -0
  9. data/README.md +211 -0
  10. data/Rakefile +8 -0
  11. data/bin/rake +16 -0
  12. data/bin/rspec +16 -0
  13. data/bin/setup +13 -0
  14. data/bin/shoelaces +13 -0
  15. data/lib/shoelaces.rb +4 -0
  16. data/lib/shoelaces/actions.rb +29 -0
  17. data/lib/shoelaces/app_builder.rb +437 -0
  18. data/lib/shoelaces/generators/app_generator.rb +233 -0
  19. data/lib/shoelaces/version.rb +5 -0
  20. data/shoelaces.gemspec +53 -0
  21. data/spec/fakes/bin/heroku +5 -0
  22. data/spec/fakes/bin/hub +5 -0
  23. data/spec/features/github_spec.rb +10 -0
  24. data/spec/features/heroku_spec.rb +19 -0
  25. data/spec/features/new_project_spec.rb +77 -0
  26. data/spec/spec_helper.rb +24 -0
  27. data/spec/support/fake_github.rb +21 -0
  28. data/spec/support/fake_heroku.rb +38 -0
  29. data/spec/support/shoelaces.rb +49 -0
  30. data/templates/Gemfile.erb +63 -0
  31. data/templates/Guardfile +33 -0
  32. data/templates/Procfile +2 -0
  33. data/templates/README.md.erb +34 -0
  34. data/templates/_analytics.html.erb +7 -0
  35. data/templates/_flashes.html.erb +7 -0
  36. data/templates/_javascript.html.erb +12 -0
  37. data/templates/_variables.scss +2 -0
  38. data/templates/about.html.erb.erb +67 -0
  39. data/templates/action_mailer.rb +5 -0
  40. data/templates/application.css.scss +18 -0
  41. data/templates/background_jobs_rspec.rb +19 -0
  42. data/templates/bin_setup.erb +34 -0
  43. data/templates/config_locales_en.yml +16 -0
  44. data/templates/contact.html.erb.erb +67 -0
  45. data/templates/database_cleaner_rspec.rb +21 -0
  46. data/templates/development_seeds.rb +12 -0
  47. data/templates/disable_xml_params.rb +3 -0
  48. data/templates/errors.rb +34 -0
  49. data/templates/factory_girl_rspec.rb +3 -0
  50. data/templates/high_voltage.rb +3 -0
  51. data/templates/home.html.erb.erb +16 -0
  52. data/templates/i18n.rb +3 -0
  53. data/templates/newrelic.yml.erb +34 -0
  54. data/templates/noise.png +0 -0
  55. data/templates/postgresql_database.yml.erb +12 -0
  56. data/templates/rack_timeout.rb +1 -0
  57. data/templates/sample.env +3 -0
  58. data/templates/secrets.yml +14 -0
  59. data/templates/shoelaces_gitignore +13 -0
  60. data/templates/shoelaces_layout.html.erb.erb +25 -0
  61. data/templates/shoelaces_layout_footer.html.erb.erb +11 -0
  62. data/templates/shoelaces_layout_header.html.erb.erb +33 -0
  63. data/templates/smtp.rb +9 -0
  64. data/templates/spec_helper.rb +30 -0
  65. data/templates/staging.rb +5 -0
  66. data/templates/travis.yml.erb +24 -0
  67. data/templates/unicorn.rb +30 -0
  68. metadata +232 -0
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rspec-core', 'rspec')
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env sh
2
+
3
+ # Run this script immediately after cloning the codebase.
4
+
5
+ # Exit if any subcommand fails
6
+ set -e
7
+
8
+ # Set up Ruby dependencies via Bundler
9
+ bundle install
10
+
11
+ # Add binstubs to PATH in ~/.zshenv like this:
12
+ # export PATH=".git/safe/../../bin:$PATH"
13
+ mkdir -p .git/safe
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ source_path = (Pathname.new(__FILE__).dirname + '../lib').expand_path
5
+ $LOAD_PATH << source_path
6
+
7
+ require 'shoelaces'
8
+
9
+ templates_root = File.expand_path(File.join("..", "templates"), File.dirname(__FILE__))
10
+ Shoelaces::AppGenerator.source_root templates_root
11
+ Shoelaces::AppGenerator.source_paths << Rails::Generators::AppGenerator.source_root << templates_root
12
+
13
+ Shoelaces::AppGenerator.start
@@ -0,0 +1,4 @@
1
+ require 'shoelaces/version'
2
+ require 'shoelaces/generators/app_generator'
3
+ require 'shoelaces/actions'
4
+ require 'shoelaces/app_builder'
@@ -0,0 +1,29 @@
1
+ module Shoelaces
2
+ module Actions
3
+ def replace_in_file(relative_path, find, replace)
4
+ path = File.join(destination_root, relative_path)
5
+ contents = IO.read(path)
6
+ unless contents.gsub!(find, replace)
7
+ raise "#{find.inspect} not found in #{relative_path}"
8
+ end
9
+ File.open(path, "w") { |file| file.write(contents) }
10
+ end
11
+
12
+ def uncomment_in_file(path, uncommented)
13
+ replace_in_file(path, "# #{uncommented}", uncommented)
14
+ end
15
+
16
+ def action_mailer_host(rails_env, host)
17
+ host_config = "config.action_mailer.default_url_options = { host: '#{host}' }"
18
+ configure_environment(rails_env, host_config)
19
+ end
20
+
21
+ def configure_environment(rails_env, config)
22
+ inject_into_file(
23
+ "config/environments/#{rails_env}.rb",
24
+ "\n\n #{config}",
25
+ before: "\nend"
26
+ )
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,437 @@
1
+ module Shoelaces
2
+ class AppBuilder < Rails::AppBuilder
3
+ include Shoelaces::Actions
4
+
5
+ @@port_number = nil
6
+ def self.set_port_number(number)
7
+ @@port_number = number
8
+ end
9
+
10
+ def readme
11
+ template 'README.md.erb', 'README.md'
12
+ end
13
+
14
+ def raise_on_delivery_errors
15
+ replace_in_file 'config/environments/development.rb',
16
+ 'raise_delivery_errors = false', 'raise_delivery_errors = true'
17
+ end
18
+
19
+ def raise_on_unpermitted_parameters
20
+ action_on_unpermitted_parameters = <<-RUBY
21
+
22
+ # Raise an ActionController::UnpermittedParameters exception when
23
+ # a parameter is not explcitly permitted but is passed anyway.
24
+ config.action_controller.action_on_unpermitted_parameters = :raise
25
+ RUBY
26
+ inject_into_file(
27
+ "config/environments/development.rb",
28
+ action_on_unpermitted_parameters,
29
+ before: "\nend"
30
+ )
31
+ end
32
+
33
+ def provide_setup_script
34
+ template 'bin_setup.erb', 'bin/setup', port_number: port_number
35
+ run 'chmod a+x bin/setup'
36
+ end
37
+
38
+ def provide_dev_prime_task
39
+ copy_file 'development_seeds.rb', 'lib/tasks/development_seeds.rake'
40
+ end
41
+
42
+ def configure_generators
43
+ config = <<-RUBY
44
+ config.generators do |generate|
45
+ generate.helper false
46
+ generate.javascript_engine false
47
+ generate.request_specs false
48
+ generate.routing_specs false
49
+ generate.stylesheets false
50
+ generate.test_framework :rspec
51
+ generate.view_specs false
52
+ end
53
+
54
+ RUBY
55
+
56
+ inject_into_class 'config/application.rb', 'Application', config
57
+ end
58
+
59
+ def set_up_factory_girl_for_rspec
60
+ copy_file 'factory_girl_rspec.rb', 'spec/support/factory_girl.rb'
61
+ end
62
+
63
+ def configure_newrelic
64
+ template 'newrelic.yml.erb', 'config/newrelic.yml'
65
+ end
66
+
67
+ def configure_smtp
68
+ copy_file 'smtp.rb', 'config/smtp.rb'
69
+
70
+ prepend_file 'config/environments/production.rb',
71
+ %{require Rails.root.join("config/smtp")\n}
72
+
73
+ config = <<-RUBY
74
+
75
+ config.action_mailer.delivery_method = :smtp
76
+ config.action_mailer.smtp_settings = SMTP_SETTINGS
77
+ RUBY
78
+
79
+ inject_into_file 'config/environments/production.rb', config,
80
+ :after => 'config.action_mailer.raise_delivery_errors = false'
81
+ end
82
+
83
+ def enable_rack_deflater
84
+ config = <<-RUBY
85
+
86
+ # Enable deflate / gzip compression of controller-generated responses
87
+ config.middleware.use Rack::Deflater
88
+ RUBY
89
+
90
+ inject_into_file 'config/environments/production.rb', config,
91
+ :after => "config.serve_static_assets = false\n"
92
+ end
93
+
94
+ def setup_asset_host
95
+ replace_in_file 'config/environments/production.rb',
96
+ '# config.action_controller.asset_host = "http://assets.example.com"',
97
+ 'config.action_controller.asset_host = ENV.fetch("ASSET_HOST")'
98
+
99
+ replace_in_file 'config/initializers/assets.rb',
100
+ "config.assets.version = '1.0'",
101
+ 'config.assets.version = (ENV["ASSETS_VERSION"] || "1.0")'
102
+
103
+ replace_in_file 'config/environments/production.rb',
104
+ 'config.serve_static_assets = false',
105
+ 'config.static_cache_control = "public, max-age=#{1.year.to_i}"'
106
+ end
107
+
108
+ def setup_staging_environment
109
+ staging_file = 'config/environments/staging.rb'
110
+ copy_file 'staging.rb', staging_file
111
+
112
+ config = <<-RUBY
113
+
114
+ Rails.application.configure do
115
+ # ...
116
+ end
117
+ RUBY
118
+
119
+ append_file staging_file, config
120
+ end
121
+
122
+ def setup_secret_token
123
+ template 'secrets.yml', 'config/secrets.yml', force: true
124
+ end
125
+
126
+ def create_partials_directory
127
+ empty_directory 'app/views/application'
128
+ end
129
+
130
+ def create_shared_flashes
131
+ copy_file '_flashes.html.erb', 'app/views/application/_flashes.html.erb'
132
+ end
133
+
134
+ def add_images
135
+ copy_file 'noise.png', 'app/assets/images/noise.png'
136
+ end
137
+
138
+ def add_static_pages
139
+ template 'home.html.erb.erb',
140
+ 'app/views/pages/home.html.erb',
141
+ force: true
142
+ template 'about.html.erb.erb',
143
+ 'app/views/pages/about.html.erb',
144
+ force: true
145
+ template 'contact.html.erb.erb',
146
+ 'app/views/pages/contact.html.erb',
147
+ force: true
148
+ end
149
+
150
+ def create_application_layout
151
+ template 'shoelaces_layout.html.erb.erb',
152
+ 'app/views/layouts/application.html.erb',
153
+ force: true
154
+ template 'shoelaces_layout_header.html.erb.erb',
155
+ 'app/views/layouts/_header.html.erb',
156
+ force: true
157
+ template 'shoelaces_layout_footer.html.erb.erb',
158
+ 'app/views/layouts/_footer.html.erb',
159
+ force: true
160
+ end
161
+
162
+ def remove_turbolinks
163
+ replace_in_file 'app/assets/javascripts/application.js',
164
+ /\/\/= require turbolinks\n/,
165
+ ''
166
+ end
167
+
168
+ def setup_bootstrap_javascript
169
+ bootstrap_javascript = <<-RUBY
170
+ //= require bootstrap
171
+ RUBY
172
+ inject_into_file(
173
+ 'app/assets/javascripts/application.js',
174
+ bootstrap_javascript,
175
+ before: "//= require_tree ."
176
+ )
177
+ end
178
+
179
+ def use_postgres_config_template
180
+ template 'postgresql_database.yml.erb', 'config/database.yml',
181
+ force: true
182
+ end
183
+
184
+ def use_high_voltage_config_template
185
+ copy_file 'high_voltage.rb', 'config/initializers/high_voltage.rb'
186
+ end
187
+
188
+ def create_database
189
+ bundle_command 'exec rake db:create db:migrate'
190
+ end
191
+
192
+ def replace_gemfile
193
+ remove_file 'Gemfile'
194
+ template 'Gemfile.erb', 'Gemfile'
195
+ end
196
+
197
+ def set_ruby_to_version_being_used
198
+ create_file '.ruby-version', "#{Shoelaces::RUBY_VERSION}\n"
199
+ end
200
+
201
+ def setup_heroku_specific_gems
202
+ inject_into_file 'Gemfile', "\n\s\sgem 'rails_12factor'",
203
+ after: /group :staging, :production do/
204
+ end
205
+
206
+ def enable_database_cleaner
207
+ copy_file 'database_cleaner_rspec.rb', 'spec/support/database_cleaner.rb'
208
+ end
209
+
210
+ def configure_spec_support_features
211
+ empty_directory_with_keep_file 'spec/features'
212
+ empty_directory_with_keep_file 'spec/support/features'
213
+ end
214
+
215
+ def configure_rspec
216
+ remove_file 'spec/spec_helper.rb'
217
+ copy_file 'spec_helper.rb', 'spec/spec_helper.rb'
218
+ end
219
+
220
+ def configure_travis
221
+ template 'travis.yml.erb', '.travis.yml'
222
+ end
223
+
224
+ def configure_i18n_for_test_environment
225
+ copy_file 'i18n.rb', 'spec/support/i18n.rb'
226
+ raise_on_missing_translations_in("test")
227
+ end
228
+
229
+ def configure_i18n_for_development_environment
230
+ raise_on_missing_translations_in("development")
231
+ end
232
+
233
+ def configure_background_jobs_for_rspec
234
+ copy_file 'background_jobs_rspec.rb', 'spec/support/background_jobs.rb'
235
+ run 'rails g delayed_job:active_record'
236
+ end
237
+
238
+ def configure_action_mailer_in_specs
239
+ copy_file 'action_mailer.rb', 'spec/support/action_mailer.rb'
240
+ end
241
+
242
+ def configure_time_zone
243
+ config = <<-RUBY
244
+ config.active_record.default_timezone = :utc
245
+
246
+ RUBY
247
+ inject_into_class 'config/application.rb', 'Application', config
248
+ end
249
+
250
+ def configure_time_formats
251
+ remove_file 'config/locales/en.yml'
252
+ copy_file 'config_locales_en.yml', 'config/locales/en.yml'
253
+ end
254
+
255
+ def configure_rack_timeout
256
+ copy_file 'rack_timeout.rb', 'config/initializers/rack_timeout.rb'
257
+ end
258
+
259
+ def configure_action_mailer
260
+ action_mailer_host 'development', "localhost:#{port_number}"
261
+ action_mailer_host 'test', 'www.example.com'
262
+ action_mailer_host 'staging', "staging.#{app_name}.com"
263
+ action_mailer_host 'production', "#{app_name}.com"
264
+ end
265
+
266
+ def fix_i18n_deprecation_warning
267
+ config = <<-RUBY
268
+ config.i18n.enforce_available_locales = true
269
+
270
+ RUBY
271
+ inject_into_class 'config/application.rb', 'Application', config
272
+ end
273
+
274
+ def generate_rspec
275
+ generate 'rspec:install'
276
+ end
277
+
278
+ def generate_simple_form
279
+ generate 'simple_form:install --bootstrap'
280
+ end
281
+
282
+ def configure_unicorn
283
+ copy_file 'unicorn.rb', 'config/unicorn.rb'
284
+ end
285
+
286
+ def setup_foreman
287
+ copy_file 'sample.env', '.sample.env'
288
+ copy_file 'Procfile', 'Procfile'
289
+ end
290
+
291
+ def setup_guard
292
+ copy_file 'Guardfile', 'Guardfile'
293
+ end
294
+
295
+ def setup_stylesheets
296
+ remove_file 'app/assets/stylesheets/application.css'
297
+ copy_file 'application.css.scss',
298
+ 'app/assets/stylesheets/application.css.scss'
299
+ copy_file '_variables.scss',
300
+ 'app/assets/stylesheets/_variables.scss'
301
+ end
302
+
303
+ def gitignore_files
304
+ remove_file '.gitignore'
305
+ copy_file 'shoelaces_gitignore', '.gitignore'
306
+ [
307
+ 'app/views/pages',
308
+ 'spec/lib',
309
+ 'spec/controllers',
310
+ 'spec/helpers',
311
+ 'spec/support/matchers',
312
+ 'spec/support/mixins',
313
+ 'spec/support/shared_examples'
314
+ ].each do |dir|
315
+ run "mkdir #{dir}"
316
+ run "touch #{dir}/.keep"
317
+ end
318
+ end
319
+
320
+ def init_git
321
+ run 'git init'
322
+ end
323
+
324
+ def create_heroku_apps
325
+ path_addition = override_path_for_tests
326
+ run "#{path_addition} heroku create #{app_name}-production --remote=production"
327
+ run "#{path_addition} heroku create #{app_name}-staging --remote=staging"
328
+ run "#{path_addition} heroku config:add RACK_ENV=staging RAILS_ENV=staging --remote=staging"
329
+ end
330
+
331
+ def set_heroku_remotes
332
+ remotes = <<-SHELL
333
+
334
+ # Set up staging and production git remotes.
335
+ git remote add staging git@heroku.com:#{app_name}-staging.git || true
336
+ git remote add production git@heroku.com:#{app_name}-production.git || true
337
+
338
+ # Join the staging and production apps.
339
+ #{join_heroku_app('staging')}
340
+ #{join_heroku_app('production')}
341
+ SHELL
342
+
343
+ append_file 'bin/setup', remotes
344
+ end
345
+
346
+ def join_heroku_app(environment)
347
+ heroku_app_name = "#{app_name}-#{environment}"
348
+ <<-SHELL
349
+ if heroku join --app #{heroku_app_name} &> /dev/null; then
350
+ echo 'You are a collaborator on the "#{heroku_app_name}" Heroku app'
351
+ else
352
+ echo 'Ask for access to the "#{heroku_app_name}" Heroku app'
353
+ fi
354
+ SHELL
355
+ end
356
+
357
+ def set_heroku_rails_secrets
358
+ path_addition = override_path_for_tests
359
+ run "#{path_addition} heroku config:add SECRET_KEY_BASE=#{generate_secret} --remote=staging"
360
+ run "#{path_addition} heroku config:add SECRET_KEY_BASE=#{generate_secret} --remote=production"
361
+ end
362
+
363
+ def create_github_repo(repo_name)
364
+ path_addition = override_path_for_tests
365
+ run "#{path_addition} hub create #{repo_name}"
366
+ end
367
+
368
+ def setup_segment_io
369
+ copy_file '_analytics.html.erb',
370
+ 'app/views/application/_analytics.html.erb'
371
+ end
372
+
373
+ def copy_miscellaneous_files
374
+ copy_file 'errors.rb', 'config/initializers/errors.rb'
375
+ end
376
+
377
+ def customize_error_pages
378
+ meta_tags =<<-EOS
379
+ <meta charset="utf-8" />
380
+ <meta name="ROBOTS" content="NOODP" />
381
+ <meta name="viewport" content="initial-scale=1" />
382
+ EOS
383
+
384
+ %w(500 404 422).each do |page|
385
+ inject_into_file "public/#{page}.html", meta_tags, :after => "<head>\n"
386
+ replace_in_file "public/#{page}.html", /<!--.+-->\n/, ''
387
+ end
388
+ end
389
+
390
+ def remove_routes_comment_lines
391
+ replace_in_file 'config/routes.rb',
392
+ /Rails\.application\.routes\.draw do.*end/m,
393
+ "Rails.application.routes.draw do\nend"
394
+ end
395
+
396
+ def disable_xml_params
397
+ copy_file 'disable_xml_params.rb', 'config/initializers/disable_xml_params.rb'
398
+ end
399
+
400
+ def setup_default_rake_task
401
+ append_file 'Rakefile' do
402
+ "task(:default).clear\ntask default: [:spec]\n"
403
+ end
404
+ end
405
+
406
+ private
407
+
408
+ def raise_on_missing_translations_in(environment)
409
+ config = 'config.action_view.raise_on_missing_translations = true'
410
+
411
+ uncomment_in_file("config/environments/#{environment}.rb", config)
412
+ end
413
+
414
+ def override_path_for_tests
415
+ if ENV['TESTING']
416
+ support_bin = File.expand_path(File.join('..', '..', 'spec', 'fakes', 'bin'))
417
+ "PATH=#{support_bin}:$PATH"
418
+ end
419
+ end
420
+
421
+ def factories_spec_rake_task
422
+ IO.read find_in_source_paths('factories_spec_rake_task.rb')
423
+ end
424
+
425
+ def generate_secret
426
+ SecureRandom.hex(64)
427
+ end
428
+
429
+ def port_number
430
+ if @@port_number
431
+ @port_number = @@port_number
432
+ else
433
+ @port_number ||= [3000, 5000, 6000, 7000, 8000, 9000].sample
434
+ end
435
+ end
436
+ end
437
+ end