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