welaika-suspenders 2.29.0 → 2.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +2 -3
  4. data/NEWS.md +18 -0
  5. data/README.md +2 -1
  6. data/lib/suspenders.rb +4 -0
  7. data/lib/suspenders/adapters/heroku.rb +13 -27
  8. data/lib/suspenders/app_builder.rb +2 -29
  9. data/lib/suspenders/generators/app_generator.rb +10 -16
  10. data/lib/suspenders/generators/base.rb +20 -0
  11. data/lib/suspenders/generators/ci_generator.rb +3 -10
  12. data/lib/suspenders/generators/db_optimizations_generator.rb +2 -2
  13. data/lib/suspenders/generators/decorator_generator.rb +1 -6
  14. data/lib/suspenders/generators/factories_generator.rb +2 -7
  15. data/lib/suspenders/generators/faker_generator.rb +1 -6
  16. data/lib/suspenders/generators/js_driver_generator.rb +2 -7
  17. data/lib/suspenders/generators/json_generator.rb +10 -0
  18. data/lib/suspenders/generators/lint_generator.rb +2 -7
  19. data/lib/suspenders/generators/production/deployment_generator.rb +27 -0
  20. data/lib/suspenders/generators/production/email_generator.rb +3 -11
  21. data/lib/suspenders/generators/production/error_reporting_generator.rb +1 -8
  22. data/lib/suspenders/generators/production/force_tls_generator.rb +2 -5
  23. data/lib/suspenders/generators/production/manifest_generator.rb +24 -0
  24. data/lib/suspenders/generators/production/timeout_generator.rb +2 -2
  25. data/lib/suspenders/generators/security_generator.rb +1 -6
  26. data/lib/suspenders/generators/staging/pull_requests_generator.rb +33 -0
  27. data/lib/suspenders/generators/static_generator.rb +2 -2
  28. data/lib/suspenders/generators/stylesheet_base_generator.rb +2 -6
  29. data/lib/suspenders/generators/testing_generator.rb +2 -7
  30. data/lib/suspenders/generators/views_generator.rb +2 -7
  31. data/lib/suspenders/version.rb +2 -2
  32. data/spec/adapters/heroku_spec.rb +2 -2
  33. data/spec/features/heroku_spec.rb +22 -6
  34. data/spec/features/json_spec.rb +15 -0
  35. data/spec/features/new_project_spec.rb +13 -8
  36. data/spec/features/production/deployment_spec.rb +22 -0
  37. data/spec/features/production/email_spec.rb +1 -1
  38. data/spec/features/production/manifest_spec.rb +35 -0
  39. data/spec/features/staging/pull_requests_spec.rb +22 -0
  40. data/spec/spec_helper.rb +3 -0
  41. data/spec/support/be_executable_matcher.rb +7 -0
  42. data/spec/support/generators.rb +5 -0
  43. data/spec/support/project_files.rb +13 -0
  44. data/suspenders.gemspec +2 -0
  45. data/templates/Gemfile.erb +3 -5
  46. data/templates/_flashes.html.slim +1 -1
  47. data/templates/factory_bot_rspec.rb +2 -0
  48. data/templates/gitlab-ci.yml.erb +13 -16
  49. data/templates/overcommit.yml +1 -1
  50. data/templates/suspenders_gitignore +3 -0
  51. data/templates/suspenders_layout.html.slim +2 -3
  52. metadata +53 -9
  53. data/templates/app.json.erb +0 -27
  54. data/templates/browserslist +0 -3
@@ -1,16 +1,8 @@
1
- require "rails/generators"
2
- require_relative "../../actions"
1
+ require_relative "../base"
3
2
 
4
3
  module Suspenders
5
4
  module Production
6
- class EmailGenerator < Rails::Generators::Base
7
- include Suspenders::Actions
8
-
9
- source_root File.expand_path(
10
- File.join("..", "..", "..", "..", "templates"),
11
- File.dirname(__FILE__),
12
- )
13
-
5
+ class EmailGenerator < Generators::Base
14
6
  def smtp_configuration
15
7
  copy_file "smtp.rb", "config/smtp.rb"
16
8
 
@@ -26,7 +18,7 @@ module Suspenders
26
18
  RUBY
27
19
 
28
20
  inject_into_file "config/environments/production.rb", config,
29
- after: "config.action_mailer.raise_delivery_errors = false"
21
+ after: "config.action_mailer.perform_caching = false"
30
22
  end
31
23
 
32
24
  def env_vars
@@ -3,14 +3,7 @@ require_relative "../../actions"
3
3
 
4
4
  module Suspenders
5
5
  module Production
6
- class ErrorReportingGenerator < Rails::Generators::Base
7
- include Suspenders::Actions
8
-
9
- source_root File.expand_path(
10
- File.join("..", "..", "..", "..", "templates"),
11
- File.dirname(__FILE__),
12
- )
13
-
6
+ class ErrorReportingGenerator < Generators::Base
14
7
  def add_sentry
15
8
  gem "sentry-raven"
16
9
  Bundler.with_clean_env { run "bundle install" }
@@ -1,11 +1,8 @@
1
- require "rails/generators"
2
- require_relative "../../actions"
1
+ require_relative "../base"
3
2
 
4
3
  module Suspenders
5
4
  module Production
6
- class ForceTlsGenerator < Rails::Generators::Base
7
- include Suspenders::Actions
8
-
5
+ class ForceTlsGenerator < Generators::Base
9
6
  def config_enforce_ssl
10
7
  configure_environment "production", "config.force_ssl = true"
11
8
  end
@@ -0,0 +1,24 @@
1
+ require_relative "../base"
2
+
3
+ module Suspenders
4
+ module Production
5
+ class ManifestGenerator < Generators::Base
6
+ def render_manifest
7
+ expand_json(
8
+ "app.json",
9
+ name: app_name.dasherize,
10
+ scripts: {},
11
+ env: {
12
+ APPLICATION_HOST: { required: true },
13
+ EMAIL_RECIPIENTS: { required: true },
14
+ HEROKU_APP_NAME: { required: true },
15
+ HEROKU_PARENT_APP_NAME: { required: true },
16
+ RACK_ENV: { required: true },
17
+ SECRET_KEY_BASE: { generator: "secret" },
18
+ },
19
+ addons: ["heroku-postgresql"],
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,8 +1,8 @@
1
- require "rails/generators"
1
+ require_relative "../base"
2
2
 
3
3
  module Suspenders
4
4
  module Production
5
- class TimeoutGenerator < Rails::Generators::Base
5
+ class TimeoutGenerator < Generators::Base
6
6
  def add_gem
7
7
  gem "rack-timeout", group: :production
8
8
  end
@@ -1,12 +1,7 @@
1
1
  require "rails/generators"
2
2
 
3
3
  module Suspenders
4
- class SecurityGenerator < Rails::Generators::Base
5
- source_root File.expand_path(
6
- File.join("..", "..", "..", "templates"),
7
- File.dirname(__FILE__),
8
- )
9
-
4
+ class SecurityGenerator < Generators::Base
10
5
  def add_checkers_gems
11
6
  gem 'brakeman', require: false, group: :development
12
7
  gem 'bundler-audit', '>= 0.5.0', require: false, group: :development
@@ -0,0 +1,33 @@
1
+ require_relative "../base"
2
+
3
+ module Suspenders
4
+ module Staging
5
+ class PullRequestsGenerator < Generators::Base
6
+ def configure_heroku_staging_pr_pipeline_host
7
+ config = <<-RUBY
8
+
9
+ if ENV.fetch("HEROKU_APP_NAME", "").include?("staging-pr-")
10
+ ENV["APPLICATION_HOST"] = ENV["HEROKU_APP_NAME"] + ".herokuapp.com"
11
+ ENV["ASSET_HOST"] = ENV["HEROKU_APP_NAME"] + ".herokuapp.com"
12
+ end
13
+ RUBY
14
+
15
+ inject_into_file(
16
+ "config/environments/production.rb",
17
+ config,
18
+ after: "Rails.application.configure do\n",
19
+ )
20
+ end
21
+
22
+ def create_review_apps_setup_script
23
+ template(
24
+ "bin_setup_review_app.erb",
25
+ "bin/setup_review_app",
26
+ force: true,
27
+ )
28
+
29
+ run "chmod a+x bin/setup_review_app"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,7 +1,7 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class StaticGenerator < Rails::Generators::Base
4
+ class StaticGenerator < Generators::Base
5
5
  def add_high_voltage
6
6
  gem "high_voltage"
7
7
  Bundler.with_clean_env { run "bundle install" }
@@ -1,11 +1,7 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class StylesheetBaseGenerator < Rails::Generators::Base
5
- source_root File.expand_path(
6
- File.join("..", "..", "..", "templates"),
7
- File.dirname(__FILE__))
8
-
4
+ class StylesheetBaseGenerator < Generators::Base
9
5
  def add_css_config
10
6
  copy_file(
11
7
  "application.sass",
@@ -1,12 +1,7 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class TestingGenerator < Rails::Generators::Base
5
- source_root File.expand_path(
6
- File.join("..", "..", "..", "templates"),
7
- File.dirname(__FILE__),
8
- )
9
-
4
+ class TestingGenerator < Generators::Base
10
5
  def add_testing_gems
11
6
  gem "rspec-rails", "~> 3.8", group: %i(development test)
12
7
  gem "shoulda-matchers", group: :test
@@ -1,12 +1,7 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class ViewsGenerator < Rails::Generators::Base
5
- source_root File.expand_path(
6
- File.join("..", "..", "..", "templates"),
7
- File.dirname(__FILE__),
8
- )
9
-
4
+ class ViewsGenerator < Generators::Base
10
5
  def add_slim_gem
11
6
  gem "slim-rails"
12
7
  Bundler.with_clean_env { run "bundle install" }
@@ -1,9 +1,9 @@
1
1
  module Suspenders
2
- RAILS_VERSION = "~> 5.2.1".freeze
2
+ RAILS_VERSION = "~> 5.2.2".freeze
3
3
  POSTGRES_VERSION = "10.4".freeze # Used in CI
4
4
  RUBY_VERSION = IO.
5
5
  read("#{File.dirname(__FILE__)}/../../.ruby-version").
6
6
  strip.
7
7
  freeze
8
- VERSION = "2.29.0".freeze
8
+ VERSION = "2.30.0".freeze
9
9
  end
@@ -11,9 +11,9 @@ module Suspenders
11
11
  Heroku.new(app_builder).set_heroku_remotes
12
12
 
13
13
  expect(app_builder).to have_received(:append_file).
14
- with(setup_file, /git remote add -f production #{app_name.dasherize}-production/)
14
+ with(setup_file, /git remote add -f production git@heroku\.com:#{app_name.dasherize}-production\.git/)
15
15
  expect(app_builder).to have_received(:append_file).
16
- with(setup_file, /git remote add -f staging #{app_name.dasherize}-staging/)
16
+ with(setup_file, /git remote add -f staging git@heroku\.com:#{app_name.dasherize}-staging\.git/)
17
17
  end
18
18
 
19
19
  it "sets the heroku rails secrets" do
@@ -7,26 +7,29 @@ RSpec.describe "Heroku" do
7
7
  run_suspenders("--heroku=true")
8
8
  setup_app_dependencies
9
9
  end
10
+ let(:app_name) { SuspendersTestHelpers::APP_NAME.dasherize }
10
11
 
11
12
  it "suspends a project for Heroku" do
12
- app_name = SuspendersTestHelpers::APP_NAME.dasherize
13
-
14
13
  expect(FakeHeroku).to have_created_app_for("staging", "--region eu")
15
14
  expect(FakeHeroku).to have_created_app_for("production", "--region eu")
16
15
  %w(staging production).each do |env|
17
16
  expect(FakeHeroku).to have_configured_vars(env, "APPLICATION_HOST")
18
17
  expect(FakeHeroku).to have_configured_vars(env, "SENTRY_DSN")
19
- expect(FakeHeroku).to have_configured_vars(env, "SECRET_KEY_BASE")
18
+ expect(FakeHeroku).to have_configured_vars(env, "SENTRY_ENV")
19
+ expect(FakeHeroku).to have_configured_vars(env, "SMTP_ADDRESS")
20
+ expect(FakeHeroku).to have_configured_vars(env, "SMTP_DOMAIN")
21
+ expect(FakeHeroku).to have_configured_vars(env, "SMTP_PASSWORD")
22
+ expect(FakeHeroku).to have_configured_vars(env, "SMTP_USERNAME")
20
23
  end
21
24
  expect(FakeHeroku).to have_setup_pipeline_for(app_name)
22
25
 
23
26
  bin_setup_path = "#{project_path}/bin/setup"
24
27
  bin_setup = IO.read(bin_setup_path)
25
28
 
26
- expect(bin_setup).to match(/^if heroku join --app #{app_name}-production/)
27
- expect(bin_setup).to match(/^if heroku join --app #{app_name}-staging/)
29
+ expect(bin_setup).to match(/^if heroku apps | grep #{app_name}-production/)
30
+ expect(bin_setup).to match(/^if heroku apps | grep #{app_name}-staging/)
28
31
  expect(bin_setup).to match(/^git config heroku.remote staging/)
29
- expect(File.stat(bin_setup_path)).to be_executable
32
+ expect("bin/setup").to be_executable
30
33
 
31
34
  readme = IO.read("#{project_path}/README.md")
32
35
 
@@ -35,6 +38,19 @@ RSpec.describe "Heroku" do
35
38
  end
36
39
  end
37
40
 
41
+ context "--heroku with region flag" do
42
+ before(:all) do
43
+ clean_up
44
+ run_suspenders(%{--heroku=true --heroku-flags="--region eu"})
45
+ setup_app_dependencies
46
+ end
47
+
48
+ it "suspends a project with extra Heroku flags" do
49
+ expect(FakeHeroku).to have_created_app_for("staging", "--region eu")
50
+ expect(FakeHeroku).to have_created_app_for("production", "--region eu")
51
+ end
52
+ end
53
+
38
54
  def clean_up
39
55
  drop_dummy_database
40
56
  remove_project_directory
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "suspenders:json", type: :generator do
4
+ it "generates the Gemfile for JSON parsing" do
5
+ with_app { generate("suspenders:json") }
6
+
7
+ expect("Gemfile").to match_contents(%r{gem .oj.})
8
+ end
9
+
10
+ it "cleans up the Gemfile from JSON parsing" do
11
+ with_app { destroy("suspenders:json") }
12
+
13
+ expect("Gemfile").not_to match_contents(%r{gem .oj.})
14
+ end
15
+ end
@@ -14,7 +14,7 @@ RSpec.describe "Suspend a new project with default configuration" do
14
14
  /^ruby '#{Suspenders::RUBY_VERSION}'$/,
15
15
  )
16
16
  expect(gemfile_file).to match(
17
- /^gem 'autoprefixer-rails'$/,
17
+ /^gem 'active_interaction'/,
18
18
  )
19
19
  expect(gemfile_file).to match(
20
20
  /^gem 'rails', '#{Suspenders::RAILS_VERSION}'$/,
@@ -57,9 +57,7 @@ RSpec.describe "Suspend a new project with default configuration" do
57
57
  end
58
58
 
59
59
  it "makes bin/setup executable" do
60
- bin_setup_path = "#{project_path}/bin/setup"
61
-
62
- expect(File.stat(bin_setup_path)).to be_executable
60
+ expect("bin/setup").to be_executable
63
61
  end
64
62
 
65
63
  it "adds support file for action mailer" do
@@ -213,8 +211,9 @@ RSpec.describe "Suspend a new project with default configuration" do
213
211
  ]
214
212
 
215
213
  config_files.each do |file|
216
- expect(file).not_to match(/.*#.*/)
217
- expect(file).not_to match(/^$\n/)
214
+ expect(file).not_to match(%r{.*#.*})
215
+ expect(file).not_to eq(file.strip)
216
+ expect(file).not_to match(%r{^$\n\n})
218
217
  end
219
218
  end
220
219
 
@@ -229,7 +228,7 @@ RSpec.describe "Suspend a new project with default configuration" do
229
228
  expect(bin_setup).to include("heroku ps:scale worker=1 --app $APP_NAME")
230
229
  expect(bin_setup).to include("heroku restart --app $APP_NAME")
231
230
 
232
- expect(File.stat(bin_setup_path)).to be_executable
231
+ expect("bin/setup_review_app").to be_executable
233
232
  end
234
233
 
235
234
  it "creates deploy script" do
@@ -237,7 +236,7 @@ RSpec.describe "Suspend a new project with default configuration" do
237
236
  bin_deploy = IO.read(bin_deploy_path)
238
237
 
239
238
  expect(bin_deploy).to include("heroku run rails db:migrate --exit-code")
240
- expect(File.stat(bin_deploy_path)).to be_executable
239
+ expect("bin/deploy").to be_executable
241
240
  end
242
241
 
243
242
  it "creates heroku application manifest file with application name in it" do
@@ -255,6 +254,12 @@ RSpec.describe "Suspend a new project with default configuration" do
255
254
  expect(gemfile).to match(/high_voltage/)
256
255
  end
257
256
 
257
+ it "adds sassc-rails" do
258
+ gemfile = read_project_file("Gemfile")
259
+
260
+ expect(gemfile).to match(/sassc-rails/)
261
+ end
262
+
258
263
  it "doesn't use turbolinks" do
259
264
  app_js = read_project_file(%w(app assets javascripts application.js))
260
265
  expect(app_js).not_to match(/turbolinks/)
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "suspenders:production:deployment", type: :generator do
4
+ it "generates the configuration for a production deployment" do
5
+ rm "bin/deploy"
6
+
7
+ with_app { generate("suspenders:production:deployment") }
8
+
9
+ expect("bin/deploy").to exist_as_a_file
10
+ expect("bin/deploy").to be_executable
11
+ expect("README.md").to match_contents(%r{bin/deploy})
12
+ end
13
+
14
+ it "destroys the configuration for a production deployment" do
15
+ touch "bin/deploy"
16
+
17
+ with_app { destroy("suspenders:production:deployment") }
18
+
19
+ expect("bin/deploy").not_to exist_as_a_file
20
+ expect("README.md").not_to match_contents(%r{bin/deploy})
21
+ end
22
+ end
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
- RSpec.describe "suspenders:production:email" do
3
+ RSpec.describe "suspenders:production:email", type: :generator do
4
4
  it "generates the configuration for a production email deployment" do
5
5
  with_app { generate("suspenders:production:email") }
6
6
 
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "suspenders:production:manifest", type: :generator do
4
+ it "generates the manifest for a production build" do
5
+ with_app { generate("suspenders:production:manifest") }
6
+
7
+ expect("app.json").to contain_json(
8
+ name: SuspendersTestHelpers::APP_NAME.dasherize,
9
+ env: {
10
+ APPLICATION_HOST: { required: true },
11
+ EMAIL_RECIPIENTS: { required: true },
12
+ HEROKU_APP_NAME: { required: true },
13
+ HEROKU_PARENT_APP_NAME: { required: true },
14
+ RACK_ENV: { required: true },
15
+ SECRET_KEY_BASE: { generator: "secret" },
16
+ },
17
+ )
18
+ end
19
+
20
+ it "destroys the manifest for a production build" do
21
+ with_app { destroy("suspenders:production:manifest") }
22
+
23
+ expect("app.json").not_to contain_json(
24
+ name: SuspendersTestHelpers::APP_NAME.dasherize,
25
+ env: {
26
+ APPLICATION_HOST: { required: true },
27
+ EMAIL_RECIPIENTS: { required: true },
28
+ HEROKU_APP_NAME: { required: true },
29
+ HEROKU_PARENT_APP_NAME: { required: true },
30
+ RACK_ENV: { required: true },
31
+ SECRET_KEY_BASE: { generator: "secret" },
32
+ },
33
+ )
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "suspenders:staging:pull_requests", type: :generators do
4
+ it "generates the configuration for Heroku pipeline review apps" do
5
+ with_app { generate("suspenders:staging:pull_requests") }
6
+
7
+ expect("config/environments/production.rb").to \
8
+ match_contents(%r{HEROKU_APP_NAME})
9
+
10
+ expect("bin/setup_review_app").to \
11
+ match_contents(%r{APP_NAME=dummy-app-staging-pr-\$1})
12
+ end
13
+
14
+ it "destroys the configuration for Heroku pipeline review apps" do
15
+ with_app { destroy("suspenders:staging:pull_requests") }
16
+
17
+ expect("config/environments/production.rb").not_to \
18
+ match_contents(%r{APP_NAME=dummy-app-staging-pr-\$1})
19
+
20
+ expect("bin/setup_review_app").not_to exist_as_a_file
21
+ end
22
+ end