suspenders 1.50.0 → 1.54.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +6 -4
  4. data/CONTRIBUTING.md +15 -15
  5. data/GOALS.md +65 -0
  6. data/NEWS.md +55 -0
  7. data/README.md +7 -4
  8. data/docs/heroku_deploy.md +19 -0
  9. data/lib/suspenders.rb +10 -0
  10. data/lib/suspenders/actions.rb +2 -2
  11. data/lib/suspenders/adapters/heroku.rb +14 -5
  12. data/lib/suspenders/app_builder.rb +3 -91
  13. data/lib/suspenders/generators/advisories_generator.rb +15 -0
  14. data/lib/suspenders/generators/analytics_generator.rb +2 -7
  15. data/lib/suspenders/generators/app_generator.rb +14 -41
  16. data/lib/suspenders/generators/base.rb +59 -0
  17. data/lib/suspenders/generators/ci_generator.rb +20 -14
  18. data/lib/suspenders/generators/db_optimizations_generator.rb +6 -18
  19. data/lib/suspenders/generators/factories_generator.rb +3 -8
  20. data/lib/suspenders/generators/forms_generator.rb +3 -3
  21. data/lib/suspenders/generators/inline_svg_generator.rb +14 -0
  22. data/lib/suspenders/generators/jobs_generator.rb +3 -13
  23. data/lib/suspenders/generators/js_driver_generator.rb +9 -11
  24. data/lib/suspenders/generators/json_generator.rb +3 -3
  25. data/lib/suspenders/generators/lint_generator.rb +2 -7
  26. data/lib/suspenders/generators/preloader_generator.rb +122 -0
  27. data/lib/suspenders/generators/production/compression_generator.rb +14 -0
  28. data/lib/suspenders/generators/production/deployment_generator.rb +16 -0
  29. data/lib/suspenders/generators/production/email_generator.rb +7 -18
  30. data/lib/suspenders/generators/production/force_tls_generator.rb +2 -5
  31. data/lib/suspenders/generators/production/manifest_generator.rb +25 -0
  32. data/lib/suspenders/generators/production/single_redirect.rb +15 -0
  33. data/lib/suspenders/generators/production/timeout_generator.rb +3 -2
  34. data/lib/suspenders/generators/profiler_generator.rb +35 -0
  35. data/lib/suspenders/generators/runner_generator.rb +48 -0
  36. data/lib/suspenders/generators/staging/pull_requests_generator.rb +4 -26
  37. data/lib/suspenders/generators/static_generator.rb +7 -3
  38. data/lib/suspenders/generators/stylelint_generator.rb +70 -0
  39. data/lib/suspenders/generators/stylesheet_base_generator.rb +8 -13
  40. data/lib/suspenders/generators/testing_generator.rb +6 -22
  41. data/lib/suspenders/generators/views_generator.rb +2 -7
  42. data/lib/suspenders/version.rb +2 -2
  43. data/spec/adapters/heroku_spec.rb +28 -2
  44. data/spec/expand_json_spec.rb +89 -0
  45. data/spec/features/advisories_spec.rb +24 -0
  46. data/spec/features/api_spec.rb +1 -1
  47. data/spec/features/ci_spec.rb +31 -0
  48. data/spec/features/db_optimizations_spec.rb +19 -0
  49. data/spec/features/heroku_spec.rb +7 -14
  50. data/spec/features/inline_svg_spec.rb +10 -0
  51. data/spec/features/json_spec.rb +1 -1
  52. data/spec/features/new_project_spec.rb +17 -35
  53. data/spec/features/preloader_spec.rb +25 -0
  54. data/spec/features/production/compression_spec.rb +23 -0
  55. data/spec/features/production/deployment_spec.rb +22 -0
  56. data/spec/features/production/email_spec.rb +1 -1
  57. data/spec/features/production/manifest_spec.rb +37 -0
  58. data/spec/features/production/single_redirect_spec.rb +25 -0
  59. data/spec/features/profiler_spec.rb +20 -0
  60. data/spec/features/runner_spec.rb +30 -0
  61. data/spec/features/staging/pull_requests_spec.rb +1 -1
  62. data/spec/features/static_spec.rb +17 -0
  63. data/spec/features/stylelint_spec.rb +60 -0
  64. data/spec/spec_helper.rb +1 -0
  65. data/spec/support/be_executable_matcher.rb +7 -0
  66. data/spec/support/contain_json_matcher.rb +16 -10
  67. data/spec/support/generators.rb +5 -0
  68. data/spec/support/project_files.rb +25 -0
  69. data/spec/support/rails_template.rb +1 -0
  70. data/spec/support/suspenders.rb +18 -15
  71. data/suspenders.gemspec +1 -1
  72. data/templates/Gemfile.erb +5 -11
  73. data/templates/_javascript.html.erb +1 -1
  74. data/templates/application.scss +0 -1
  75. data/templates/bin_auto_migrate +5 -0
  76. data/templates/bin_deploy +0 -2
  77. data/templates/bin_setup +2 -2
  78. data/templates/bin_setup_review_app.erb +0 -1
  79. data/templates/capybara_silence_puma.rb +1 -0
  80. data/templates/chromedriver.rb +14 -4
  81. data/templates/descriptions/advisories.md +5 -0
  82. data/templates/descriptions/analytics.md +4 -0
  83. data/templates/descriptions/ci.md +4 -0
  84. data/templates/descriptions/compression.md +4 -0
  85. data/templates/descriptions/db_optimizations.md +2 -0
  86. data/templates/descriptions/deployment.md +5 -0
  87. data/templates/descriptions/email.md +9 -0
  88. data/templates/descriptions/factories.md +12 -0
  89. data/templates/descriptions/force_tls.md +1 -0
  90. data/templates/descriptions/forms.md +1 -0
  91. data/templates/descriptions/inline_svg.md +2 -0
  92. data/templates/descriptions/jobs.md +3 -0
  93. data/templates/descriptions/js_driver.md +4 -0
  94. data/templates/descriptions/json.md +1 -0
  95. data/templates/descriptions/lint.md +3 -0
  96. data/templates/descriptions/manifest.md +2 -0
  97. data/templates/descriptions/preloader.md +3 -0
  98. data/templates/descriptions/profiler.md +7 -0
  99. data/templates/descriptions/pull_requests.md +4 -0
  100. data/templates/descriptions/runner.md +10 -0
  101. data/templates/descriptions/single_redirect.md +1 -0
  102. data/templates/descriptions/static.md +5 -0
  103. data/templates/descriptions/stylelint.md +3 -0
  104. data/templates/descriptions/stylesheet_base.md +4 -0
  105. data/templates/descriptions/testing.md +9 -0
  106. data/templates/descriptions/timeout.md +4 -0
  107. data/templates/descriptions/views.md +8 -0
  108. data/templates/hound.yml +3 -1
  109. data/templates/inline_svg.rb +3 -0
  110. data/templates/partials/ci_simplecov.rb +16 -0
  111. data/templates/partials/db_optimizations_configuration.rb +7 -0
  112. data/templates/partials/deployment_readme.md +8 -0
  113. data/templates/partials/email_smtp.rb +3 -0
  114. data/templates/partials/profiler_readme.md +8 -0
  115. data/templates/partials/pull_requests_config.rb +5 -0
  116. data/templates/partials/runner_readme.md +31 -0
  117. data/templates/partials/runner_setup.rb +3 -0
  118. data/templates/rack_mini_profiler.rb +2 -0
  119. data/templates/rails_helper.rb +7 -4
  120. data/templates/{dotfiles/.env → sample_env} +0 -2
  121. data/templates/spec_helper.rb +4 -7
  122. data/templates/spring.rb +6 -0
  123. data/templates/stylelintrc.json +3 -0
  124. data/templates/suspenders_gitignore +1 -1
  125. metadata +119 -17
  126. data/templates/app.json.erb +0 -27
  127. data/templates/browserslist +0 -3
  128. data/templates/dotfiles/.ctags +0 -2
  129. data/templates/puma.rb +0 -28
@@ -0,0 +1,14 @@
1
+ require_relative "../base"
2
+
3
+ module Suspenders
4
+ module Production
5
+ class CompressionGenerator < Generators::Base
6
+ def add_rack_deflater
7
+ configure_environment(
8
+ :production,
9
+ %{config.middleware.use Rack::Deflater},
10
+ )
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ require_relative "../base"
2
+
3
+ module Suspenders
4
+ module Production
5
+ class DeploymentGenerator < Generators::Base
6
+ def copy_script
7
+ copy_file "bin_deploy", "bin/deploy"
8
+ chmod "bin/deploy", 0o755
9
+ end
10
+
11
+ def inform_user
12
+ append_template_to_file "README.md", "partials/deployment_readme.md"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -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
 
@@ -19,14 +11,11 @@ module Suspenders
19
11
  end
20
12
 
21
13
  def use_smtp
22
- config = <<-RUBY
23
-
24
- config.action_mailer.delivery_method = :smtp
25
- config.action_mailer.smtp_settings = SMTP_SETTINGS
26
- RUBY
27
-
28
- inject_into_file "config/environments/production.rb", config,
29
- after: "config.action_mailer.perform_caching = false"
14
+ inject_template_into_file(
15
+ "config/environments/production.rb",
16
+ "partials/email_smtp.rb",
17
+ after: "config.action_mailer.perform_caching = false",
18
+ )
30
19
  end
31
20
 
32
21
  def env_vars
@@ -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,25 @@
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
+ AUTO_MIGRATE_DB: { value: true },
14
+ EMAIL_RECIPIENTS: { required: true },
15
+ HEROKU_APP_NAME: { required: true },
16
+ HEROKU_PARENT_APP_NAME: { required: true },
17
+ RACK_ENV: { required: true },
18
+ SECRET_KEY_BASE: { generator: "secret" },
19
+ },
20
+ addons: ["heroku-postgresql"],
21
+ )
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "../base"
2
+
3
+ module Suspenders
4
+ module Production
5
+ class SingleRedirect < Generators::Base
6
+ def add_rack_canonical_host
7
+ inject_into_file(
8
+ "config/environments/production.rb",
9
+ %{\n config.middleware.use Rack::CanonicalHost, ENV.fetch("APPLICATION_HOST")},
10
+ before: "\nend",
11
+ )
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,10 +1,11 @@
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
+ Bundler.with_unbundled_env { run "bundle install" }
8
9
  end
9
10
 
10
11
  def configure_rack_timeout
@@ -0,0 +1,35 @@
1
+ require_relative "base"
2
+
3
+ module Suspenders
4
+ class ProfilerGenerator < Generators::Base
5
+ def augment_default_env
6
+ append_to_file ".env", "RACK_MINI_PROFILER=0\n"
7
+ rescue Errno::ENOENT
8
+ create_file ".env", "RACK_MINI_PROFILER=0\n"
9
+ rescue Thor::Error => e
10
+ if e.message.match?(/does not appear to exist/)
11
+ create_file ".env", "RACK_MINI_PROFILER=0\n"
12
+ else
13
+ raise
14
+ end
15
+ end
16
+
17
+ def add_gem
18
+ gem "rack-mini-profiler", require: false
19
+ Bundler.with_unbundled_env { run "bundle install" }
20
+ end
21
+
22
+ def configure_rack_mini_profiler
23
+ copy_file(
24
+ "rack_mini_profiler.rb",
25
+ "config/initializers/rack_mini_profiler.rb",
26
+ force: false,
27
+ skip: true,
28
+ )
29
+ end
30
+
31
+ def update_readme
32
+ append_template_to_file "README.md", "partials/profiler_readme.md"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,48 @@
1
+ require_relative "base"
2
+
3
+ module Suspenders
4
+ class RunnerGenerator < Generators::Base
5
+ def procfile
6
+ copy_file "Procfile", "Procfile"
7
+ end
8
+
9
+ def sample_env
10
+ copy_file "sample_env", ".sample.env"
11
+ end
12
+
13
+ def copy_sample_env
14
+ if bin_setup_is_ruby?
15
+ inject_template_into_file(
16
+ "bin/setup",
17
+ "partials/runner_setup.rb",
18
+ before: %{ puts "\\n== Preparing database =="},
19
+ )
20
+ elsif bin_setup_mentions_ci?
21
+ inject_into_file(
22
+ "bin/setup",
23
+ %{ cp -i .sample.env .env\n},
24
+ after: %{if [ -z "$CI" ]; then\n},
25
+ )
26
+ else
27
+ append_to_file(
28
+ "bin/setup",
29
+ %{\nif [ -z "$CI" ]; then\n cp -i .sample.env .env\nfi},
30
+ )
31
+ end
32
+ end
33
+
34
+ def update_readme
35
+ append_template_to_file "README.md", "partials/runner_readme.md"
36
+ end
37
+
38
+ private
39
+
40
+ def bin_setup_is_ruby?
41
+ File.read("bin/setup", 20).match?(%r{#!/usr/bin/env ruby})
42
+ end
43
+
44
+ def bin_setup_mentions_ci?
45
+ File.read("bin/setup").match?(/if \[ -z "\$CI" \]/)
46
+ end
47
+ end
48
+ end
@@ -1,28 +1,12 @@
1
- require "rails/generators"
2
- require_relative "../../actions"
1
+ require_relative "../base"
3
2
 
4
3
  module Suspenders
5
4
  module Staging
6
- class PullRequestsGenerator < 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 PullRequestsGenerator < Generators::Base
14
6
  def configure_heroku_staging_pr_pipeline_host
15
- config = <<-RUBY
16
-
17
- if ENV.fetch("HEROKU_APP_NAME", "").include?("staging-pr-")
18
- ENV["APPLICATION_HOST"] = ENV["HEROKU_APP_NAME"] + ".herokuapp.com"
19
- ENV["ASSET_HOST"] = ENV["HEROKU_APP_NAME"] + ".herokuapp.com"
20
- end
21
- RUBY
22
-
23
- inject_into_file(
7
+ inject_template_into_file(
24
8
  "config/environments/production.rb",
25
- config,
9
+ "partials/pull_requests_config.rb",
26
10
  after: "Rails.application.configure do\n",
27
11
  )
28
12
  end
@@ -36,12 +20,6 @@ module Suspenders
36
20
 
37
21
  run "chmod a+x bin/setup_review_app"
38
22
  end
39
-
40
- private
41
-
42
- def app_name
43
- Rails.application.class.parent_name.demodulize.underscore.dasherize
44
- end
45
23
  end
46
24
  end
47
25
  end
@@ -1,10 +1,14 @@
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
- Bundler.with_clean_env { run "bundle install" }
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
+ end
9
+
10
+ def make_placeholder_directory
11
+ empty_directory_with_keep_file "app/views/pages"
8
12
  end
9
13
  end
10
14
  end
@@ -0,0 +1,70 @@
1
+ require_relative "base"
2
+
3
+ module Suspenders
4
+ class StylelintGenerator < Generators::Base
5
+ def setup_hound
6
+ action InvokeGenerator.new(self, "suspenders:lint")
7
+ action ToggleComments.new(self, ".hound.yml", /stylelintrc/)
8
+ end
9
+
10
+ def install_stylelint
11
+ dependencies = ["stylelint", "@thoughtbot/stylelint-config"]
12
+ action YarnInstall.new(self, dependencies, "--dev")
13
+ end
14
+
15
+ def copy_stylelint_config
16
+ copy_file "stylelintrc.json", ".stylelintrc.json"
17
+ end
18
+
19
+ class InvokeGenerator
20
+ def initialize(base, generator)
21
+ @base = base
22
+ @generator = generator
23
+ end
24
+
25
+ def invoke!
26
+ @base.invoke @generator
27
+ end
28
+
29
+ def revoke!; end
30
+ end
31
+
32
+ class ToggleComments
33
+ def initialize(base, filename, pattern)
34
+ @base = base
35
+ @filename = filename
36
+ @pattern = pattern
37
+ end
38
+
39
+ def invoke!
40
+ @base.uncomment_lines(@filename, @pattern)
41
+ end
42
+
43
+ def revoke!
44
+ @base.behavior = :invoke
45
+ @base.comment_lines(@filename, @pattern)
46
+ ensure
47
+ @base.behavior = :revoke
48
+ end
49
+ end
50
+
51
+ class YarnInstall
52
+ def initialize(base, dependencies, flags)
53
+ @base = base
54
+ @dependencies = dependencies.join(" ")
55
+ @flags = flags
56
+ end
57
+
58
+ def invoke!
59
+ @base.run "bin/yarn add #{@dependencies} #{@flags}"
60
+ end
61
+
62
+ def revoke!
63
+ @base.behavior = :invoke
64
+ @base.run "bin/yarn remove #{@dependencies}"
65
+ ensure
66
+ @base.behavior = :revoke
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,15 +1,14 @@
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_stylesheet_gems
10
- gem "bourbon", "~> 5.0"
11
- gem "neat", "~> 2.1"
12
- Bundler.with_clean_env { run "bundle install" }
6
+ gem "bourbon", ">= 6.0.0"
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
+ end
9
+
10
+ def remove_prior_config
11
+ remove_file "app/assets/stylesheets/application.css"
13
12
  end
14
13
 
15
14
  def add_css_config
@@ -20,10 +19,6 @@ module Suspenders
20
19
  )
21
20
  end
22
21
 
23
- def remove_prior_config
24
- remove_file "app/assets/stylesheets/application.css"
25
- end
26
-
27
22
  def install_bitters
28
23
  run "bitters install --path app/assets/stylesheets"
29
24
  end
@@ -1,18 +1,13 @@
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 "spring-commands-rspec", group: :development
12
7
  gem "rspec-rails", "~> 3.6", group: %i(development test)
13
8
  gem "shoulda-matchers", group: :test
14
9
 
15
- Bundler.with_clean_env { run "bundle install" }
10
+ Bundler.with_unbundled_env { run "bundle install" }
16
11
  end
17
12
 
18
13
  def generate_rspec
@@ -33,9 +28,9 @@ module Suspenders
33
28
  )
34
29
  end
35
30
 
36
- def configure_spec_support_features
37
- empty_directory_with_keep_file "spec/features"
38
- empty_directory_with_keep_file "spec/support/features"
31
+ def configure_system_tests
32
+ empty_directory_with_keep_file "spec/system"
33
+ empty_directory_with_keep_file "spec/support/system"
39
34
  end
40
35
 
41
36
  def configure_i18n_for_test_environment
@@ -45,16 +40,5 @@ module Suspenders
45
40
  def configure_action_mailer_in_specs
46
41
  copy_file "action_mailer.rb", "spec/support/action_mailer.rb"
47
42
  end
48
-
49
- private
50
-
51
- def empty_directory_with_keep_file(destination)
52
- empty_directory(destination, {})
53
- keep_file(destination)
54
- end
55
-
56
- def keep_file(destination)
57
- create_file(File.join(destination, ".keep"))
58
- end
59
43
  end
60
44
  end