armadura 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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +11 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +19 -0
  7. data/README.md +218 -0
  8. data/Rakefile +8 -0
  9. data/USAGE +9 -0
  10. data/armadura.gemspec +29 -0
  11. data/bin/armadura +23 -0
  12. data/bin/rake +16 -0
  13. data/bin/rspec +16 -0
  14. data/bin/setup +13 -0
  15. data/lib/armadura.rb +7 -0
  16. data/lib/armadura/actions.rb +33 -0
  17. data/lib/armadura/adapters/heroku.rb +118 -0
  18. data/lib/armadura/app_builder.rb +484 -0
  19. data/lib/armadura/generators/app_generator.rb +245 -0
  20. data/lib/armadura/generators/static_generator.rb +10 -0
  21. data/lib/armadura/generators/stylesheet_base_generator.rb +37 -0
  22. data/lib/armadura/version.rb +8 -0
  23. data/spec/adapters/heroku_spec.rb +57 -0
  24. data/spec/fakes/bin/heroku +5 -0
  25. data/spec/fakes/bin/hub +5 -0
  26. data/spec/features/cli_help_spec.rb +36 -0
  27. data/spec/features/github_spec.rb +16 -0
  28. data/spec/features/heroku_spec.rb +75 -0
  29. data/spec/features/new_project_spec.rb +295 -0
  30. data/spec/features/sidekiq_spec.rb +30 -0
  31. data/spec/spec_helper.rb +20 -0
  32. data/spec/support/armadura.rb +83 -0
  33. data/spec/support/fake_github.rb +21 -0
  34. data/spec/support/fake_heroku.rb +53 -0
  35. data/templates/Gemfile.erb +60 -0
  36. data/templates/Procfile +2 -0
  37. data/templates/README.md.erb +28 -0
  38. data/templates/_analytics.html.erb +7 -0
  39. data/templates/_css_overrides.html.erb +7 -0
  40. data/templates/_flashes.html.erb +7 -0
  41. data/templates/_javascript.html.erb +12 -0
  42. data/templates/action_mailer.rb +5 -0
  43. data/templates/app.json.erb +39 -0
  44. data/templates/application.scss +9 -0
  45. data/templates/armadura_gitignore +14 -0
  46. data/templates/armadura_layout.html.erb.erb +22 -0
  47. data/templates/bin_deploy +12 -0
  48. data/templates/bin_setup +22 -0
  49. data/templates/bin_setup_review_app.erb +19 -0
  50. data/templates/browserslist +3 -0
  51. data/templates/bundler_audit.rake +12 -0
  52. data/templates/capybara_webkit.rb +5 -0
  53. data/templates/circle.yml.erb +6 -0
  54. data/templates/config_locales_en.yml.erb +19 -0
  55. data/templates/database_cleaner_rspec.rb +21 -0
  56. data/templates/dev.rake +12 -0
  57. data/templates/dotfiles/.ctags +2 -0
  58. data/templates/dotfiles/.env +14 -0
  59. data/templates/errors.rb +34 -0
  60. data/templates/factories.rb +2 -0
  61. data/templates/factory_girl_rspec.rb +3 -0
  62. data/templates/flashes_helper.rb +5 -0
  63. data/templates/hound.yml +14 -0
  64. data/templates/i18n.rb +3 -0
  65. data/templates/json_encoding.rb +1 -0
  66. data/templates/postgresql_database.yml.erb +21 -0
  67. data/templates/puma.rb +28 -0
  68. data/templates/rack_mini_profiler.rb +5 -0
  69. data/templates/rails_helper.rb +22 -0
  70. data/templates/secrets.yml +14 -0
  71. data/templates/shoulda_matchers_config_rspec.rb +6 -0
  72. data/templates/sidekiq.yml +6 -0
  73. data/templates/smtp.rb +13 -0
  74. data/templates/spec_helper.rb +29 -0
  75. metadata +188 -0
@@ -0,0 +1,118 @@
1
+ module Armadura
2
+ module Adapters
3
+ class Heroku
4
+ def initialize(app_builder)
5
+ @app_builder = app_builder
6
+ end
7
+
8
+ def set_heroku_remotes
9
+ remotes = <<-SHELL.strip_heredoc
10
+ #{command_to_join_heroku_app('staging')}
11
+ #{command_to_join_heroku_app('production')}
12
+
13
+ git config heroku.remote staging
14
+ SHELL
15
+
16
+ app_builder.append_file "bin/setup", remotes
17
+ end
18
+
19
+ def create_staging_heroku_app(flags)
20
+ app_name = heroku_app_name_for("staging")
21
+
22
+ run_toolbelt_command "create #{app_name} #{flags}", "staging"
23
+ end
24
+
25
+ def create_production_heroku_app(flags)
26
+ app_name = heroku_app_name_for("production")
27
+
28
+ run_toolbelt_command "create #{app_name} #{flags}", "production"
29
+ end
30
+
31
+ def set_heroku_rails_secrets
32
+ %w(staging production).each do |environment|
33
+ run_toolbelt_command(
34
+ "config:add SECRET_KEY_BASE=#{generate_secret}",
35
+ environment,
36
+ )
37
+ end
38
+ end
39
+
40
+ def create_review_apps_setup_script
41
+ app_builder.template(
42
+ "bin_setup_review_app.erb",
43
+ "bin/setup_review_app",
44
+ force: true,
45
+ )
46
+ app_builder.run "chmod a+x bin/setup_review_app"
47
+ end
48
+
49
+ def create_heroku_application_manifest_file
50
+ app_builder.template "app.json.erb", "app.json"
51
+ end
52
+
53
+ def create_heroku_pipeline
54
+ pipelines_plugin = `heroku help | grep pipelines`
55
+ if pipelines_plugin.empty?
56
+ puts "You need heroku pipelines plugin. Run: brew upgrade heroku-toolbelt"
57
+ exit 1
58
+ end
59
+
60
+ run_toolbelt_command(
61
+ "pipelines:create #{heroku_app_name} \
62
+ -a #{heroku_app_name}-staging --stage staging",
63
+ "staging",
64
+ )
65
+
66
+ run_toolbelt_command(
67
+ "pipelines:add #{heroku_app_name} \
68
+ -a #{heroku_app_name}-production --stage production",
69
+ "production",
70
+ )
71
+ end
72
+
73
+ def set_heroku_application_host
74
+ %w(staging production).each do |environment|
75
+ run_toolbelt_command(
76
+ "config:add APPLICATION_HOST=#{heroku_app_name}-#{environment}.herokuapp.com",
77
+ environment,
78
+ )
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ attr_reader :app_builder
85
+
86
+ def command_to_join_heroku_app(environment)
87
+ heroku_app_name = heroku_app_name_for(environment)
88
+ <<-SHELL
89
+
90
+ if heroku join --app #{heroku_app_name} &> /dev/null; then
91
+ git remote add #{environment} git@heroku.com:#{heroku_app_name}.git || true
92
+ printf 'You are a collaborator on the "#{heroku_app_name}" Heroku app\n'
93
+ else
94
+ printf 'Ask for access to the "#{heroku_app_name}" Heroku app\n'
95
+ fi
96
+ SHELL
97
+ end
98
+
99
+ def heroku_app_name
100
+ app_builder.app_name.dasherize
101
+ end
102
+
103
+ def heroku_app_name_for(environment)
104
+ "#{heroku_app_name}-#{environment}"
105
+ end
106
+
107
+ def generate_secret
108
+ SecureRandom.hex(64)
109
+ end
110
+
111
+ def run_toolbelt_command(command, environment)
112
+ app_builder.run(
113
+ "heroku #{command} --remote #{environment}",
114
+ )
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,484 @@
1
+ require "forwardable"
2
+
3
+ module Armadura
4
+ class AppBuilder < Rails::AppBuilder
5
+ include Armadura::Actions
6
+ extend Forwardable
7
+
8
+ def_delegators :heroku_adapter,
9
+ :create_heroku_application_manifest_file,
10
+ :create_heroku_pipeline,
11
+ :create_production_heroku_app,
12
+ :create_staging_heroku_app,
13
+ :create_review_apps_setup_script,
14
+ :set_heroku_rails_secrets,
15
+ :set_heroku_remotes,
16
+ :set_heroku_application_host
17
+
18
+ def readme
19
+ template 'README.md.erb', 'README.md'
20
+ end
21
+
22
+ def gitignore
23
+ copy_file "armadura_gitignore", ".gitignore"
24
+ end
25
+
26
+ def gemfile
27
+ template "Gemfile.erb", "Gemfile"
28
+ end
29
+
30
+ def setup_rack_mini_profiler
31
+ copy_file(
32
+ "rack_mini_profiler.rb",
33
+ "config/initializers/rack_mini_profiler.rb",
34
+ )
35
+ end
36
+
37
+ def raise_on_missing_assets_in_test
38
+ configure_environment "test", "config.assets.raise_runtime_errors = true"
39
+ end
40
+
41
+ def raise_on_delivery_errors
42
+ replace_in_file 'config/environments/development.rb',
43
+ 'raise_delivery_errors = false', 'raise_delivery_errors = true'
44
+ end
45
+
46
+ def remove_turbolinks
47
+ replace_in_file(
48
+ "app/assets/javascripts/application.js",
49
+ "//= require turbolinks",
50
+ ""
51
+ )
52
+ end
53
+
54
+ def set_test_delivery_method
55
+ inject_into_file(
56
+ "config/environments/development.rb",
57
+ "\n config.action_mailer.delivery_method = :file",
58
+ after: "config.action_mailer.raise_delivery_errors = true",
59
+ )
60
+ end
61
+
62
+ def add_bullet_gem_configuration
63
+ config = <<-RUBY
64
+ config.after_initialize do
65
+ Bullet.enable = true
66
+ Bullet.bullet_logger = true
67
+ Bullet.rails_logger = true
68
+ end
69
+
70
+ RUBY
71
+
72
+ inject_into_file(
73
+ "config/environments/development.rb",
74
+ config,
75
+ after: "config.action_mailer.raise_delivery_errors = true\n",
76
+ )
77
+ end
78
+
79
+ def raise_on_unpermitted_parameters
80
+ config = <<-RUBY
81
+ config.action_controller.action_on_unpermitted_parameters = :raise
82
+ RUBY
83
+
84
+ inject_into_class "config/application.rb", "Application", config
85
+ end
86
+
87
+ def configure_quiet_assets
88
+ config = <<-RUBY
89
+ config.assets.quiet = true
90
+ RUBY
91
+
92
+ inject_into_class "config/application.rb", "Application", config
93
+ end
94
+
95
+ def provide_setup_script
96
+ template "bin_setup", "bin/setup", force: true
97
+ run "chmod a+x bin/setup"
98
+ end
99
+
100
+ def provide_dev_prime_task
101
+ copy_file 'dev.rake', 'lib/tasks/dev.rake'
102
+ end
103
+
104
+ def configure_generators
105
+ config = <<-RUBY
106
+
107
+ config.generators do |generate|
108
+ generate.helper false
109
+ generate.javascript_engine false
110
+ generate.request_specs false
111
+ generate.routing_specs false
112
+ generate.stylesheets false
113
+ generate.test_framework :rspec
114
+ generate.view_specs false
115
+ end
116
+
117
+ RUBY
118
+
119
+ inject_into_class 'config/application.rb', 'Application', config
120
+ end
121
+
122
+ def set_up_factory_girl_for_rspec
123
+ copy_file 'factory_girl_rspec.rb', 'spec/support/factory_girl.rb'
124
+ end
125
+
126
+ def generate_factories_file
127
+ copy_file "factories.rb", "spec/factories.rb"
128
+ end
129
+
130
+ def set_up_hound
131
+ copy_file "hound.yml", ".hound.yml"
132
+ end
133
+
134
+ def configure_smtp
135
+ copy_file 'smtp.rb', 'config/smtp.rb'
136
+
137
+ prepend_file 'config/environments/production.rb',
138
+ %{require Rails.root.join("config/smtp")\n}
139
+
140
+ config = <<-RUBY
141
+
142
+ config.action_mailer.delivery_method = :smtp
143
+ config.action_mailer.smtp_settings = SMTP_SETTINGS
144
+ RUBY
145
+
146
+ inject_into_file 'config/environments/production.rb', config,
147
+ after: "config.action_mailer.raise_delivery_errors = false"
148
+ end
149
+
150
+ def enable_rack_canonical_host
151
+ config = <<-RUBY
152
+
153
+ if ENV.fetch("HEROKU_APP_NAME", "").include?("staging-pr-")
154
+ ENV["APPLICATION_HOST"] = ENV["HEROKU_APP_NAME"] + ".herokuapp.com"
155
+ end
156
+
157
+ config.middleware.use Rack::CanonicalHost, ENV.fetch("APPLICATION_HOST")
158
+ RUBY
159
+
160
+ inject_into_file(
161
+ "config/environments/production.rb",
162
+ config,
163
+ after: "Rails.application.configure do",
164
+ )
165
+ end
166
+
167
+ def enable_rack_deflater
168
+ configure_environment "production", "config.middleware.use Rack::Deflater"
169
+ end
170
+
171
+ def setup_asset_host
172
+ replace_in_file 'config/environments/production.rb',
173
+ "# config.action_controller.asset_host = 'http://assets.example.com'",
174
+ 'config.action_controller.asset_host = ENV.fetch("ASSET_HOST", ENV.fetch("APPLICATION_HOST"))'
175
+
176
+ replace_in_file 'config/initializers/assets.rb',
177
+ "config.assets.version = '1.0'",
178
+ 'config.assets.version = (ENV["ASSETS_VERSION"] || "1.0")'
179
+
180
+ config = <<-EOD
181
+ config.public_file_server.headers = {
182
+ "Cache-Control" => "public, max-age=31557600",
183
+ }
184
+ EOD
185
+
186
+ configure_environment("production", config)
187
+ end
188
+
189
+ def setup_secret_token
190
+ template 'secrets.yml', 'config/secrets.yml', force: true
191
+ end
192
+
193
+ def disallow_wrapping_parameters
194
+ remove_file "config/initializers/wrap_parameters.rb"
195
+ end
196
+
197
+ def create_partials_directory
198
+ empty_directory 'app/views/application'
199
+ end
200
+
201
+ def create_shared_flashes
202
+ copy_file "_flashes.html.erb", "app/views/application/_flashes.html.erb"
203
+ copy_file "flashes_helper.rb", "app/helpers/flashes_helper.rb"
204
+ end
205
+
206
+ def create_shared_javascripts
207
+ copy_file '_javascript.html.erb', 'app/views/application/_javascript.html.erb'
208
+ end
209
+
210
+ def create_shared_css_overrides
211
+ copy_file(
212
+ "_css_overrides.html.erb",
213
+ "app/views/application/_css_overrides.html.erb",
214
+ )
215
+ end
216
+
217
+ def create_application_layout
218
+ template 'armadura_layout.html.erb.erb',
219
+ 'app/views/layouts/application.html.erb',
220
+ force: true
221
+ end
222
+
223
+ def use_postgres_config_template
224
+ template 'postgresql_database.yml.erb', 'config/database.yml',
225
+ force: true
226
+ end
227
+
228
+ def create_database
229
+ bundle_command 'exec rake db:create db:migrate'
230
+ end
231
+
232
+ def replace_gemfile(path)
233
+ template 'Gemfile.erb', 'Gemfile', force: true do |content|
234
+ if path
235
+ content.gsub(%r{gem .armadura.}) { |s| %{#{s}, path: "#{path}"} }
236
+ else
237
+ content
238
+ end
239
+ end
240
+ end
241
+
242
+ def set_ruby_to_version_being_used
243
+ create_file '.ruby-version', "#{Armadura::RUBY_VERSION}\n"
244
+ end
245
+
246
+ def enable_database_cleaner
247
+ copy_file 'database_cleaner_rspec.rb', 'spec/support/database_cleaner.rb'
248
+ end
249
+
250
+ def provide_shoulda_matchers_config
251
+ copy_file(
252
+ "shoulda_matchers_config_rspec.rb",
253
+ "spec/support/shoulda_matchers.rb"
254
+ )
255
+ end
256
+
257
+ def configure_spec_support_features
258
+ empty_directory_with_keep_file 'spec/features'
259
+ empty_directory_with_keep_file 'spec/support/features'
260
+ end
261
+
262
+ def configure_rspec
263
+ remove_file "spec/rails_helper.rb"
264
+ remove_file "spec/spec_helper.rb"
265
+ copy_file "rails_helper.rb", "spec/rails_helper.rb"
266
+ copy_file "spec_helper.rb", "spec/spec_helper.rb"
267
+ end
268
+
269
+ def configure_ci
270
+ template "circle.yml.erb", "circle.yml"
271
+ end
272
+
273
+ def configure_i18n_for_test_environment
274
+ copy_file "i18n.rb", "spec/support/i18n.rb"
275
+ end
276
+
277
+ def configure_i18n_for_missing_translations
278
+ raise_on_missing_translations_in("development")
279
+ raise_on_missing_translations_in("test")
280
+ end
281
+
282
+ def configure_action_mailer_in_specs
283
+ copy_file 'action_mailer.rb', 'spec/support/action_mailer.rb'
284
+ end
285
+
286
+ def configure_capybara_webkit
287
+ copy_file "capybara_webkit.rb", "spec/support/capybara_webkit.rb"
288
+ end
289
+
290
+ def configure_time_formats
291
+ remove_file "config/locales/en.yml"
292
+ template "config_locales_en.yml.erb", "config/locales/en.yml"
293
+ end
294
+
295
+ def configure_rack_timeout
296
+ rack_timeout_config = <<-RUBY
297
+ Rack::Timeout.timeout = (ENV["RACK_TIMEOUT"] || 10).to_i
298
+ RUBY
299
+
300
+ append_file "config/environments/production.rb", rack_timeout_config
301
+ end
302
+
303
+ def configure_simple_form
304
+ bundle_command "exec rails generate simple_form:install"
305
+ end
306
+
307
+ def configure_action_mailer
308
+ action_mailer_host "development", %{"localhost:3000"}
309
+ action_mailer_host "test", %{"www.example.com"}
310
+ action_mailer_host "production", %{ENV.fetch("APPLICATION_HOST")}
311
+ end
312
+
313
+ def configure_active_job
314
+ configure_application_file "config.active_job.queue_adapter = :sidekiq"
315
+ configure_environment "test", "config.active_job.queue_adapter = :inline"
316
+ end
317
+
318
+ def configure_sidekiq
319
+ copy_file "sidekiq.yml", "config/sidekiq.yml", force: true
320
+ end
321
+
322
+ def generate_rspec
323
+ generate 'rspec:install'
324
+ end
325
+
326
+ def replace_default_puma_configuration
327
+ copy_file "puma.rb", "config/puma.rb", force: true
328
+ end
329
+
330
+ def set_up_forego
331
+ copy_file "Procfile", "Procfile"
332
+ end
333
+
334
+ def setup_default_directories
335
+ [
336
+ 'app/views/pages',
337
+ 'spec/lib',
338
+ 'spec/controllers',
339
+ 'spec/helpers',
340
+ 'spec/support/matchers',
341
+ 'spec/support/mixins',
342
+ 'spec/support/shared_examples'
343
+ ].each do |dir|
344
+ empty_directory_with_keep_file dir
345
+ end
346
+ end
347
+
348
+ def copy_dotfiles
349
+ directory("dotfiles", ".")
350
+ end
351
+
352
+ def init_git
353
+ run 'git init'
354
+ end
355
+
356
+ def create_heroku_apps(flags)
357
+ create_staging_heroku_app(flags)
358
+ create_production_heroku_app(flags)
359
+ end
360
+
361
+ def create_deploy_script
362
+ copy_file "bin_deploy", "bin/deploy"
363
+
364
+ instructions = <<-MARKDOWN
365
+
366
+ ## Deploying
367
+
368
+ If you have previously run the `./bin/setup` script,
369
+ you can deploy to staging and production with:
370
+
371
+ $ ./bin/deploy staging
372
+ $ ./bin/deploy production
373
+ MARKDOWN
374
+
375
+ append_file "README.md", instructions
376
+ run "chmod a+x bin/deploy"
377
+ end
378
+
379
+ def configure_automatic_deployment
380
+ deploy_command = <<-YML.strip_heredoc
381
+ deployment:
382
+ staging:
383
+ branch: master
384
+ commands:
385
+ - bin/deploy staging
386
+ YML
387
+
388
+ append_file "circle.yml", deploy_command
389
+ end
390
+
391
+ def create_github_repo(repo_name)
392
+ run "hub create #{repo_name}"
393
+ end
394
+
395
+ def setup_segment
396
+ copy_file '_analytics.html.erb',
397
+ 'app/views/application/_analytics.html.erb'
398
+ end
399
+
400
+ def setup_bundler_audit
401
+ copy_file "bundler_audit.rake", "lib/tasks/bundler_audit.rake"
402
+ append_file "Rakefile", %{\ntask default: "bundler:audit"\n}
403
+ end
404
+
405
+ def setup_spring
406
+ bundle_command "exec spring binstub --all"
407
+ end
408
+
409
+ def copy_miscellaneous_files
410
+ copy_file "browserslist", "browserslist"
411
+ copy_file "errors.rb", "config/initializers/errors.rb"
412
+ copy_file "json_encoding.rb", "config/initializers/json_encoding.rb"
413
+ end
414
+
415
+ def customize_error_pages
416
+ meta_tags =<<-EOS
417
+ <meta charset="utf-8" />
418
+ <meta name="ROBOTS" content="NOODP" />
419
+ <meta name="viewport" content="initial-scale=1" />
420
+ EOS
421
+
422
+ %w(500 404 422).each do |page|
423
+ inject_into_file "public/#{page}.html", meta_tags, after: "<head>\n"
424
+ replace_in_file "public/#{page}.html", /<!--.+-->\n/, ''
425
+ end
426
+ end
427
+
428
+ def remove_config_comment_lines
429
+ config_files = [
430
+ "application.rb",
431
+ "environment.rb",
432
+ "environments/development.rb",
433
+ "environments/production.rb",
434
+ "environments/test.rb",
435
+ ]
436
+
437
+ config_files.each do |config_file|
438
+ path = File.join(destination_root, "config/#{config_file}")
439
+
440
+ accepted_content = File.readlines(path).reject do |line|
441
+ line =~ /^.*#.*$/ || line =~ /^$\n/
442
+ end
443
+
444
+ File.open(path, "w") do |file|
445
+ accepted_content.each { |line| file.puts line }
446
+ end
447
+ end
448
+ end
449
+
450
+ def remove_routes_comment_lines
451
+ replace_in_file 'config/routes.rb',
452
+ /Rails\.application\.routes\.draw do.*end/m,
453
+ "Rails.application.routes.draw do\nend"
454
+ end
455
+
456
+ def setup_default_rake_task
457
+ append_file 'Rakefile' do
458
+ <<-EOS
459
+ task(:default).clear
460
+ task default: [:spec]
461
+
462
+ if defined? RSpec
463
+ task(:spec).clear
464
+ RSpec::Core::RakeTask.new(:spec) do |t|
465
+ t.verbose = false
466
+ end
467
+ end
468
+ EOS
469
+ end
470
+ end
471
+
472
+ private
473
+
474
+ def raise_on_missing_translations_in(environment)
475
+ config = 'config.action_view.raise_on_missing_translations = true'
476
+
477
+ uncomment_lines("config/environments/#{environment}.rb", config)
478
+ end
479
+
480
+ def heroku_adapter
481
+ @heroku_adapter ||= Adapters::Heroku.new(self)
482
+ end
483
+ end
484
+ end