underwear 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) 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 +38 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +123 -0
  8. data/LICENSE +21 -0
  9. data/NEWS.md +0 -0
  10. data/README.md +194 -0
  11. data/Rakefile +8 -0
  12. data/bin/rake +16 -0
  13. data/bin/rspec +16 -0
  14. data/bin/setup +13 -0
  15. data/bin/underwear +13 -0
  16. data/lib/underwear.rb +4 -0
  17. data/lib/underwear/actions.rb +33 -0
  18. data/lib/underwear/app_builder.rb +511 -0
  19. data/lib/underwear/generators/app_generator.rb +239 -0
  20. data/lib/underwear/version.rb +5 -0
  21. data/spec/fakes/bin/heroku +5 -0
  22. data/spec/fakes/bin/hub +5 -0
  23. data/spec/features/github_spec.rb +15 -0
  24. data/spec/features/heroku_spec.rb +46 -0
  25. data/spec/features/new_project_spec.rb +113 -0
  26. data/spec/spec_helper.rb +20 -0
  27. data/spec/support/fake_github.rb +21 -0
  28. data/spec/support/fake_heroku.rb +43 -0
  29. data/spec/support/underwear.rb +49 -0
  30. data/templates/Gemfile.erb +65 -0
  31. data/templates/Procfile +3 -0
  32. data/templates/README.md.erb +32 -0
  33. data/templates/_analytics.html.erb +7 -0
  34. data/templates/_flashes.html.erb +7 -0
  35. data/templates/_javascript.html.erb +12 -0
  36. data/templates/action_mailer.rb +5 -0
  37. data/templates/application.scss +1 -0
  38. data/templates/bin_deploy +12 -0
  39. data/templates/bin_setup.erb +36 -0
  40. data/templates/browserslist +4 -0
  41. data/templates/bundler_audit.rake +12 -0
  42. data/templates/circle.yml.erb +8 -0
  43. data/templates/config_i18n_tasks.yml +11 -0
  44. data/templates/config_locales_en.yml.erb +16 -0
  45. data/templates/database_cleaner_rspec.rb +21 -0
  46. data/templates/dev.rake +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/flashes_helper.rb +5 -0
  51. data/templates/i18n.rb +3 -0
  52. data/templates/json_encoding.rb +1 -0
  53. data/templates/newrelic.yml.erb +34 -0
  54. data/templates/postgresql_database.yml.erb +22 -0
  55. data/templates/puma.rb +19 -0
  56. data/templates/rails_helper.rb +17 -0
  57. data/templates/sample.env +6 -0
  58. data/templates/secrets.yml +14 -0
  59. data/templates/sidekiq.rb +1 -0
  60. data/templates/smtp.rb +9 -0
  61. data/templates/spec_helper.rb +23 -0
  62. data/templates/staging.rb +5 -0
  63. data/templates/test.rb +48 -0
  64. data/templates/underwear_gitignore +14 -0
  65. data/templates/underwear_layout.html.erb.erb +21 -0
  66. data/underwear.gemspec +33 -0
  67. metadata +166 -0
@@ -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 'underwear'
8
+
9
+ templates_root = File.expand_path(File.join("..", "templates"), File.dirname(__FILE__))
10
+ Underwear::AppGenerator.source_root templates_root
11
+ Underwear::AppGenerator.source_paths << Rails::Generators::AppGenerator.source_root << templates_root
12
+
13
+ Underwear::AppGenerator.start
@@ -0,0 +1,4 @@
1
+ require 'underwear/version'
2
+ require 'underwear/generators/app_generator'
3
+ require 'underwear/actions'
4
+ require 'underwear/app_builder'
@@ -0,0 +1,33 @@
1
+ module Underwear
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 action_mailer_host(rails_env, host)
13
+ config = "config.action_mailer.default_url_options = { host: #{host} }"
14
+ configure_environment(rails_env, config)
15
+ end
16
+
17
+ def configure_application_file(config)
18
+ inject_into_file(
19
+ "config/application.rb",
20
+ "\n\n #{config}",
21
+ before: "\n end"
22
+ )
23
+ end
24
+
25
+ def configure_environment(rails_env, config)
26
+ inject_into_file(
27
+ "config/environments/#{rails_env}.rb",
28
+ "\n\n #{config}",
29
+ before: "\nend"
30
+ )
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,511 @@
1
+ module Underwear
2
+ class AppBuilder < Rails::AppBuilder
3
+ include Underwear::Actions
4
+
5
+ def readme
6
+ template 'README.md.erb', 'README.md'
7
+ end
8
+
9
+ def raise_on_delivery_errors
10
+ replace_in_file 'config/environments/development.rb',
11
+ 'raise_delivery_errors = false', 'raise_delivery_errors = true'
12
+ end
13
+
14
+ def set_test_delivery_method
15
+ inject_into_file(
16
+ "config/environments/development.rb",
17
+ "\n config.action_mailer.delivery_method = :test",
18
+ after: "config.action_mailer.raise_delivery_errors = true",
19
+ )
20
+ end
21
+
22
+ def raise_on_unpermitted_parameters
23
+ config = <<-RUBY
24
+ config.action_controller.action_on_unpermitted_parameters = :raise
25
+ RUBY
26
+
27
+ inject_into_class "config/application.rb", "Application", config
28
+ end
29
+
30
+ def provide_setup_script
31
+ template "bin_setup.erb", "bin/setup", port_number: port, force: true
32
+ run "chmod a+x bin/setup"
33
+ end
34
+
35
+ def provide_dev_prime_task
36
+ copy_file 'dev.rake', 'lib/tasks/dev.rake'
37
+ end
38
+
39
+ def configure_generators
40
+ config = <<-RUBY
41
+
42
+ config.generators do |generate|
43
+ generate.helper false
44
+ generate.javascript_engine false
45
+ generate.request_specs false
46
+ generate.routing_specs false
47
+ generate.stylesheets false
48
+ generate.test_framework :rspec
49
+ generate.view_specs false
50
+ end
51
+
52
+ RUBY
53
+
54
+ inject_into_class 'config/application.rb', 'Application', config
55
+ end
56
+
57
+ def set_up_factory_girl_for_rspec
58
+ copy_file 'factory_girl_rspec.rb', 'spec/support/factory_girl.rb'
59
+ end
60
+
61
+ def configure_newrelic
62
+ template 'newrelic.yml.erb', 'config/newrelic.yml'
63
+ end
64
+
65
+ def configure_smtp
66
+ copy_file 'smtp.rb', 'config/smtp.rb'
67
+
68
+ prepend_file 'config/environments/production.rb',
69
+ %{require Rails.root.join("config/smtp")\n}
70
+
71
+ config = <<-RUBY
72
+
73
+ config.action_mailer.delivery_method = :smtp
74
+ config.action_mailer.smtp_settings = SMTP_SETTINGS
75
+ RUBY
76
+
77
+ inject_into_file 'config/environments/production.rb', config,
78
+ :after => 'config.action_mailer.raise_delivery_errors = false'
79
+ end
80
+
81
+ def enable_rack_canonical_host
82
+ config = <<-RUBY
83
+
84
+ # Ensure requests are only served from one, canonical host name
85
+ config.middleware.use Rack::CanonicalHost, ENV.fetch("HOST")
86
+ RUBY
87
+
88
+ inject_into_file(
89
+ "config/environments/production.rb",
90
+ config,
91
+ after: serve_static_files_line
92
+ )
93
+ end
94
+
95
+ def enable_rack_deflater
96
+ config = <<-RUBY
97
+
98
+ # Enable deflate / gzip compression of controller-generated responses
99
+ config.middleware.use Rack::Deflater
100
+ RUBY
101
+
102
+ inject_into_file(
103
+ "config/environments/production.rb",
104
+ config,
105
+ after: serve_static_files_line
106
+ )
107
+ end
108
+
109
+ def setup_asset_host
110
+ replace_in_file 'config/environments/production.rb',
111
+ "# config.action_controller.asset_host = 'http://assets.example.com'",
112
+ 'config.action_controller.asset_host = ENV.fetch("ASSET_HOST", ENV.fetch("HOST"))'
113
+
114
+ replace_in_file 'config/initializers/assets.rb',
115
+ "config.assets.version = '1.0'",
116
+ 'config.assets.version = (ENV["ASSETS_VERSION"] || "1.0")'
117
+
118
+ inject_into_file(
119
+ "config/environments/production.rb",
120
+ ' config.static_cache_control = "public, max-age=#{1.year.to_i}"',
121
+ after: serve_static_files_line
122
+ )
123
+ end
124
+
125
+ def setup_staging_environment
126
+ staging_file = 'config/environments/staging.rb'
127
+ copy_file 'staging.rb', staging_file
128
+
129
+ config = <<-RUBY
130
+
131
+ Rails.application.configure do
132
+ # ...
133
+ end
134
+ RUBY
135
+
136
+ append_file staging_file, config
137
+ end
138
+
139
+ def setup_test_environment
140
+ copy_file 'test.rb', 'config/environments/test.rb'
141
+ end
142
+
143
+ def setup_secret_token
144
+ template 'secrets.yml', 'config/secrets.yml', force: true
145
+ end
146
+
147
+ def disallow_wrapping_parameters
148
+ remove_file "config/initializers/wrap_parameters.rb"
149
+ end
150
+
151
+ def create_partials_directory
152
+ empty_directory 'app/views/application'
153
+ end
154
+
155
+ def create_shared_flashes
156
+ copy_file "_flashes.html.erb", "app/views/application/_flashes.html.erb"
157
+ copy_file "flashes_helper.rb", "app/helpers/flashes_helper.rb"
158
+ end
159
+
160
+ def create_shared_javascripts
161
+ copy_file '_javascript.html.erb', 'app/views/application/_javascript.html.erb'
162
+ end
163
+
164
+ def create_application_layout
165
+ template 'underwear_layout.html.erb.erb',
166
+ 'app/views/layouts/application.html.erb',
167
+ force: true
168
+ end
169
+
170
+ def use_postgres_config_template
171
+ template 'postgresql_database.yml.erb', 'config/database.yml',
172
+ force: true
173
+ end
174
+
175
+ def create_database
176
+ bundle_command 'exec rake db:drop db:create db:migrate'
177
+ end
178
+
179
+ def replace_gemfile
180
+ remove_file 'Gemfile'
181
+ template 'Gemfile.erb', 'Gemfile'
182
+ end
183
+
184
+ def set_ruby_to_version_being_used
185
+ create_file '.ruby-version', "#{Underwear::RUBY_VERSION}\n"
186
+ end
187
+
188
+ def setup_heroku_specific_gems
189
+ inject_into_file(
190
+ "Gemfile",
191
+ %{\n\s\sgem "rails_stdout_logging"},
192
+ after: /group :staging, :production do/
193
+ )
194
+ end
195
+
196
+ def enable_database_cleaner
197
+ copy_file 'database_cleaner_rspec.rb', 'spec/support/database_cleaner.rb'
198
+ end
199
+
200
+ def configure_spec_support_features
201
+ empty_directory_with_keep_file 'spec/features'
202
+ empty_directory_with_keep_file 'spec/support/features'
203
+ end
204
+
205
+ def configure_rspec
206
+ remove_file "spec/rails_helper.rb"
207
+ remove_file "spec/spec_helper.rb"
208
+ copy_file "rails_helper.rb", "spec/rails_helper.rb"
209
+ copy_file "spec_helper.rb", "spec/spec_helper.rb"
210
+ end
211
+
212
+ def configure_ci
213
+ template "circle.yml.erb", "circle.yml"
214
+ end
215
+
216
+ def setup_sidekiq
217
+ template "sidekiq.rb", "config/initializers/sidekiq.rb"
218
+ end
219
+
220
+ def setup_friendly_id
221
+ bundle_command "exec rails g friendly_id"
222
+ end
223
+
224
+ def setup_rails_admin
225
+ bundle_command "exec rails g rails_admin:install"
226
+ end
227
+
228
+ def configure_i18n_for_test_environment
229
+ copy_file "i18n.rb", "spec/support/i18n.rb"
230
+ end
231
+
232
+ def configure_i18n_for_missing_translations
233
+ raise_on_missing_translations_in("development")
234
+ raise_on_missing_translations_in("test")
235
+ end
236
+
237
+ def configure_i18n_tasks
238
+ run "cp $(i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/"
239
+ copy_file "config_i18n_tasks.yml", "config/i18n-tasks.yml"
240
+ end
241
+
242
+ def configure_action_mailer_in_specs
243
+ copy_file 'action_mailer.rb', 'spec/support/action_mailer.rb'
244
+ end
245
+
246
+ def configure_time_formats
247
+ remove_file "config/locales/en.yml"
248
+ template "config_locales_en.yml.erb", "config/locales/en.yml"
249
+ end
250
+
251
+ def configure_rack_timeout
252
+ rack_timeout_config = <<-RUBY
253
+ Rack::Timeout.timeout = (ENV["RACK_TIMEOUT"] || 10).to_i
254
+ RUBY
255
+
256
+ append_file "config/environments/production.rb", rack_timeout_config
257
+ end
258
+
259
+ def setup_devise
260
+ bundle_command "exec rails generate devise:install"
261
+ inject_into_file 'config/initializers/devise.rb', "config.secret_key = '12345'\n\n",
262
+ :before => "config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'"
263
+ bundle_command "exec rails generate devise User"
264
+ devise_routes = <<-RUBY
265
+ devise_scope :user do
266
+ get 'signup' => 'devise/registrations#new'
267
+ get 'login' => 'devise/sessions#new'
268
+ delete 'logout' => 'devise/sessions#destroy'
269
+ end
270
+ RUBY
271
+ append_file "config/routes.rb", devise_routes
272
+ end
273
+
274
+ def configure_action_mailer
275
+ action_mailer_host "development", %{"localhost:#{port}"}
276
+ action_mailer_host "test", %{"www.example.com"}
277
+ action_mailer_host "staging", %{ENV.fetch("HOST")}
278
+ action_mailer_host "production", %{ENV.fetch("HOST")}
279
+ end
280
+
281
+ def fix_i18n_deprecation_warning
282
+ config = <<-RUBY
283
+ config.i18n.enforce_available_locales = true
284
+ RUBY
285
+
286
+ inject_into_class 'config/application.rb', 'Application', config
287
+ end
288
+
289
+ def generate_rspec
290
+ generate 'rspec:install'
291
+ end
292
+
293
+ def configure_puma
294
+ copy_file "puma.rb", "config/puma.rb"
295
+ end
296
+
297
+ def setup_foreman
298
+ copy_file 'sample.env', '.sample.env'
299
+ copy_file 'Procfile', 'Procfile'
300
+ end
301
+
302
+ def setup_stylesheets
303
+ remove_file "app/assets/stylesheets/application.css"
304
+ copy_file "application.scss",
305
+ "app/assets/stylesheets/application.scss"
306
+ prepend_file "app/assets/stylesheets/application.scss",
307
+ %{@import "semantic-ui";}
308
+ end
309
+
310
+ def setup_javascripts
311
+ append_file "app/assets/javascripts/application.js",
312
+ %{//= require semantic-ui}
313
+ end
314
+
315
+ def gitignore_files
316
+ remove_file '.gitignore'
317
+ copy_file 'underwear_gitignore', '.gitignore'
318
+ [
319
+ 'spec/lib',
320
+ 'spec/controllers',
321
+ 'spec/helpers',
322
+ 'spec/support/matchers',
323
+ 'spec/support/mixins',
324
+ 'spec/support/shared_examples'
325
+ ].each do |dir|
326
+ run "mkdir #{dir}"
327
+ run "touch #{dir}/.keep"
328
+ end
329
+ end
330
+
331
+ def init_git
332
+ run 'git init'
333
+ end
334
+
335
+ def create_staging_heroku_app(flags)
336
+ rack_env = "RACK_ENV=staging RAILS_ENV=staging"
337
+ app_name = heroku_app_name_for("staging")
338
+
339
+ run_heroku "create #{app_name} #{flags}", "staging"
340
+ run_heroku "config:add #{rack_env}", "staging"
341
+ end
342
+
343
+ def create_production_heroku_app(flags)
344
+ app_name = heroku_app_name_for("production")
345
+
346
+ run_heroku "create #{app_name} #{flags}", "production"
347
+ end
348
+
349
+ def create_heroku_apps(flags)
350
+ create_staging_heroku_app(flags)
351
+ create_production_heroku_app(flags)
352
+ end
353
+
354
+ def set_heroku_remotes
355
+ remotes = <<-SHELL
356
+
357
+ # Set up the staging and production apps.
358
+ #{join_heroku_app('staging')}
359
+ #{join_heroku_app('production')}
360
+ SHELL
361
+
362
+ append_file 'bin/setup', remotes
363
+ end
364
+
365
+ def join_heroku_app(environment)
366
+ heroku_app_name = heroku_app_name_for(environment)
367
+ <<-SHELL
368
+ if heroku join --app #{heroku_app_name} &> /dev/null; then
369
+ git remote add #{environment} git@heroku.com:#{heroku_app_name}.git || true
370
+ printf 'You are a collaborator on the "#{heroku_app_name}" Heroku app\n'
371
+ else
372
+ printf 'Ask for access to the "#{heroku_app_name}" Heroku app\n'
373
+ fi
374
+ SHELL
375
+ end
376
+
377
+ def set_heroku_rails_secrets
378
+ %w(staging production).each do |environment|
379
+ run_heroku "config:add SECRET_KEY_BASE=#{generate_secret}", environment
380
+ end
381
+ end
382
+
383
+ def set_heroku_serve_static_files
384
+ %w(staging production).each do |environment|
385
+ run_heroku "config:add RAILS_SERVE_STATIC_FILES=true", environment
386
+ end
387
+ end
388
+
389
+ def provide_deploy_script
390
+ copy_file "bin_deploy", "bin/deploy"
391
+
392
+ instructions = <<-MARKDOWN
393
+
394
+ ## Deploying
395
+
396
+ If you have previously run the `./bin/setup` script,
397
+ you can deploy to staging and production with:
398
+
399
+ $ ./bin/deploy staging
400
+ $ ./bin/deploy production
401
+ MARKDOWN
402
+
403
+ append_file "README.md", instructions
404
+ run "chmod a+x bin/deploy"
405
+ end
406
+
407
+ def create_github_repo(repo_name)
408
+ path_addition = override_path_for_tests
409
+ run "#{path_addition} hub create #{repo_name}"
410
+ end
411
+
412
+ def setup_segment
413
+ copy_file '_analytics.html.erb',
414
+ 'app/views/application/_analytics.html.erb'
415
+ end
416
+
417
+ def setup_bundler_audit
418
+ copy_file "bundler_audit.rake", "lib/tasks/bundler_audit.rake"
419
+ append_file "Rakefile", %{\ntask default: "bundler:audit"\n}
420
+ end
421
+
422
+ def setup_spring
423
+ bundle_command "exec spring binstub --all"
424
+ end
425
+
426
+ def copy_miscellaneous_files
427
+ copy_file "browserslist", "browserslist"
428
+ copy_file "errors.rb", "config/initializers/errors.rb"
429
+ copy_file "json_encoding.rb", "config/initializers/json_encoding.rb"
430
+ end
431
+
432
+ def customize_error_pages
433
+ meta_tags =<<-EOS
434
+ <meta charset="utf-8" />
435
+ <meta name="ROBOTS" content="NOODP" />
436
+ <meta name="viewport" content="initial-scale=1" />
437
+ EOS
438
+
439
+ %w(500 404 422).each do |page|
440
+ inject_into_file "public/#{page}.html", meta_tags, :after => "<head>\n"
441
+ replace_in_file "public/#{page}.html", /<!--.+-->\n/, ''
442
+ end
443
+ end
444
+
445
+ def remove_routes_comment_lines
446
+ replace_in_file 'config/routes.rb',
447
+ /Rails\.application\.routes\.draw do.*end/m,
448
+ "Rails.application.routes.draw do\nend"
449
+ end
450
+
451
+ def disable_xml_params
452
+ copy_file 'disable_xml_params.rb', 'config/initializers/disable_xml_params.rb'
453
+ end
454
+
455
+ def setup_default_rake_task
456
+ append_file 'Rakefile' do
457
+ <<-EOS
458
+ task(:default).clear
459
+ task default: [:spec]
460
+
461
+ if defined? RSpec
462
+ task(:spec).clear
463
+ RSpec::Core::RakeTask.new(:spec) do |t|
464
+ t.verbose = false
465
+ end
466
+ end
467
+ EOS
468
+ end
469
+ end
470
+
471
+ def setup_pages
472
+ bundle_command "exec rails generate controller pages home about terms privacy"
473
+ end
474
+
475
+ private
476
+
477
+ def raise_on_missing_translations_in(environment)
478
+ config = 'config.action_view.raise_on_missing_translations = true'
479
+
480
+ uncomment_lines("config/environments/#{environment}.rb", config)
481
+ end
482
+
483
+ def override_path_for_tests
484
+ if ENV['TESTING']
485
+ support_bin = File.expand_path(File.join('..', '..', 'spec', 'fakes', 'bin'))
486
+ "PATH=#{support_bin}:$PATH"
487
+ end
488
+ end
489
+
490
+ def run_heroku(command, environment)
491
+ path_addition = override_path_for_tests
492
+ run "#{path_addition} heroku #{command} --remote #{environment}"
493
+ end
494
+
495
+ def generate_secret
496
+ SecureRandom.hex(64)
497
+ end
498
+
499
+ def port
500
+ @port ||= [3000, 4000, 5000, 7000, 8000, 9000].sample
501
+ end
502
+
503
+ def serve_static_files_line
504
+ "config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?\n"
505
+ end
506
+
507
+ def heroku_app_name_for(environment)
508
+ "#{app_name.dasherize}-#{environment}"
509
+ end
510
+ end
511
+ end