shoelaces 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.
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