suspenders 1.51.0 → 1.55.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +6 -3
  4. data/CONTRIBUTING.md +15 -15
  5. data/GOALS.md +65 -0
  6. data/Gemfile +1 -1
  7. data/NEWS.md +52 -0
  8. data/README.md +5 -4
  9. data/Rakefile +6 -5
  10. data/docs/heroku_deploy.md +19 -0
  11. data/lib/suspenders.rb +7 -0
  12. data/lib/suspenders/actions.rb +2 -2
  13. data/lib/suspenders/adapters/heroku.rb +27 -14
  14. data/lib/suspenders/app_builder.rb +42 -111
  15. data/lib/suspenders/generators/advisories_generator.rb +15 -0
  16. data/lib/suspenders/generators/analytics_generator.rb +1 -1
  17. data/lib/suspenders/generators/app_generator.rb +36 -58
  18. data/lib/suspenders/generators/base.rb +40 -1
  19. data/lib/suspenders/generators/ci_generator.rb +19 -9
  20. data/lib/suspenders/generators/db_optimizations_generator.rb +5 -17
  21. data/lib/suspenders/generators/factories_generator.rb +2 -2
  22. data/lib/suspenders/generators/forms_generator.rb +1 -1
  23. data/lib/suspenders/generators/inline_svg_generator.rb +14 -0
  24. data/lib/suspenders/generators/jobs_generator.rb +4 -4
  25. data/lib/suspenders/generators/js_driver_generator.rb +7 -4
  26. data/lib/suspenders/generators/json_generator.rb +1 -1
  27. data/lib/suspenders/generators/lint_generator.rb +5 -0
  28. data/lib/suspenders/generators/preloader_generator.rb +122 -0
  29. data/lib/suspenders/generators/production/compression_generator.rb +14 -0
  30. data/lib/suspenders/generators/production/deployment_generator.rb +1 -12
  31. data/lib/suspenders/generators/production/email_generator.rb +9 -12
  32. data/lib/suspenders/generators/production/manifest_generator.rb +8 -7
  33. data/lib/suspenders/generators/production/single_redirect.rb +15 -0
  34. data/lib/suspenders/generators/production/timeout_generator.rb +3 -2
  35. data/lib/suspenders/generators/profiler_generator.rb +35 -0
  36. data/lib/suspenders/generators/runner_generator.rb +48 -0
  37. data/lib/suspenders/generators/staging/pull_requests_generator.rb +4 -12
  38. data/lib/suspenders/generators/static_generator.rb +5 -1
  39. data/lib/suspenders/generators/stylelint_generator.rb +2 -1
  40. data/lib/suspenders/generators/stylesheet_base_generator.rb +7 -8
  41. data/lib/suspenders/generators/testing_generator.rb +6 -17
  42. data/lib/suspenders/version.rb +6 -6
  43. data/spec/adapters/heroku_spec.rb +36 -10
  44. data/spec/expand_json_spec.rb +89 -0
  45. data/spec/fakes/bin/heroku +1 -1
  46. data/spec/fakes/bin/hub +1 -1
  47. data/spec/features/advisories_spec.rb +24 -0
  48. data/spec/features/api_spec.rb +1 -1
  49. data/spec/features/ci_spec.rb +31 -0
  50. data/spec/features/cli_help_spec.rb +4 -4
  51. data/spec/features/db_optimizations_spec.rb +19 -0
  52. data/spec/features/heroku_spec.rb +9 -16
  53. data/spec/features/inline_svg_spec.rb +10 -0
  54. data/spec/features/lint_spec.rb +26 -0
  55. data/spec/features/new_project_spec.rb +38 -60
  56. data/spec/features/preloader_spec.rb +25 -0
  57. data/spec/features/production/compression_spec.rb +23 -0
  58. data/spec/features/production/email_spec.rb +10 -10
  59. data/spec/features/production/manifest_spec.rb +16 -14
  60. data/spec/features/production/single_redirect_spec.rb +25 -0
  61. data/spec/features/profiler_spec.rb +20 -0
  62. data/spec/features/runner_spec.rb +30 -0
  63. data/spec/features/staging/pull_requests_spec.rb +1 -1
  64. data/spec/features/static_spec.rb +17 -0
  65. data/spec/features/stylelint_spec.rb +7 -7
  66. data/spec/spec_helper.rb +3 -3
  67. data/spec/support/contain_json_matcher.rb +16 -10
  68. data/spec/support/fake_github.rb +3 -3
  69. data/spec/support/fake_heroku.rb +8 -8
  70. data/spec/support/project_files.rb +12 -0
  71. data/spec/support/rails_template.rb +1 -0
  72. data/spec/support/suspenders.rb +21 -19
  73. data/suspenders.gemspec +20 -20
  74. data/templates/Gemfile.erb +2 -10
  75. data/templates/_javascript.html.erb +1 -1
  76. data/templates/application.scss +0 -1
  77. data/templates/bin_auto_migrate +5 -0
  78. data/templates/bin_deploy +0 -2
  79. data/templates/bin_setup +2 -2
  80. data/templates/bin_setup_review_app.erb +0 -1
  81. data/templates/capybara_silence_puma.rb +1 -0
  82. data/templates/chromedriver.rb +14 -4
  83. data/templates/descriptions/advisories.md +5 -0
  84. data/templates/descriptions/analytics.md +4 -0
  85. data/templates/descriptions/ci.md +4 -0
  86. data/templates/descriptions/compression.md +4 -0
  87. data/templates/descriptions/db_optimizations.md +2 -0
  88. data/templates/descriptions/deployment.md +5 -0
  89. data/templates/descriptions/email.md +9 -0
  90. data/templates/descriptions/factories.md +12 -0
  91. data/templates/descriptions/force_tls.md +1 -0
  92. data/templates/descriptions/forms.md +1 -0
  93. data/templates/descriptions/inline_svg.md +2 -0
  94. data/templates/descriptions/jobs.md +3 -0
  95. data/templates/descriptions/js_driver.md +4 -0
  96. data/templates/descriptions/json.md +1 -0
  97. data/templates/descriptions/lint.md +3 -0
  98. data/templates/descriptions/manifest.md +2 -0
  99. data/templates/descriptions/preloader.md +3 -0
  100. data/templates/descriptions/profiler.md +7 -0
  101. data/templates/descriptions/pull_requests.md +4 -0
  102. data/templates/descriptions/runner.md +10 -0
  103. data/templates/descriptions/single_redirect.md +1 -0
  104. data/templates/descriptions/static.md +5 -0
  105. data/templates/descriptions/stylelint.md +3 -0
  106. data/templates/descriptions/stylesheet_base.md +4 -0
  107. data/templates/descriptions/testing.md +9 -0
  108. data/templates/descriptions/timeout.md +4 -0
  109. data/templates/descriptions/views.md +8 -0
  110. data/templates/errors.rb +3 -3
  111. data/templates/hound.yml +1 -2
  112. data/templates/inline_svg.rb +3 -0
  113. data/templates/partials/ci_simplecov.rb +14 -0
  114. data/templates/partials/db_optimizations_configuration.rb +5 -0
  115. data/templates/partials/deployment_readme.md +8 -0
  116. data/templates/partials/email_smtp.rb +2 -0
  117. data/templates/partials/profiler_readme.md +8 -0
  118. data/templates/partials/pull_requests_config.rb +4 -0
  119. data/templates/partials/runner_readme.md +31 -0
  120. data/templates/partials/runner_setup.rb +2 -0
  121. data/templates/rack_mini_profiler.rb +2 -0
  122. data/templates/rails_helper.rb +7 -4
  123. data/templates/{dotfiles/.env → sample_env} +0 -2
  124. data/templates/spec_helper.rb +4 -7
  125. data/templates/spring.rb +6 -0
  126. data/templates/suspenders_gitignore +1 -1
  127. metadata +99 -14
  128. data/templates/browserslist +0 -3
  129. data/templates/dotfiles/.ctags +0 -2
  130. data/templates/puma.rb +0 -28
@@ -0,0 +1,15 @@
1
+ require_relative "base"
2
+
3
+ module Suspenders
4
+ class AdvisoriesGenerator < Generators::Base
5
+ def bundler_audit_gem
6
+ gem "bundler-audit", ">= 0.7.0", require: false, group: %i[development test]
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
+ end
9
+
10
+ def rake_task
11
+ copy_file "bundler_audit.rake", "lib/tasks/bundler_audit.rake"
12
+ append_file "Rakefile", %(\ntask default: "bundle:audit"\n)
13
+ end
14
+ end
15
+ end
@@ -10,7 +10,7 @@ module Suspenders
10
10
  def render_partial
11
11
  if File.exist?(js_partial)
12
12
  inject_into_file js_partial,
13
- %{\n\n<%= render "analytics" %>},
13
+ %(\n\n<%= render "analytics" %>),
14
14
  after: "<%= yield :javascript %>"
15
15
  end
16
16
  end
@@ -1,39 +1,39 @@
1
- require 'rails/generators'
2
- require 'rails/generators/rails/app/app_generator'
1
+ require "rails/generators"
2
+ require "rails/generators/rails/app/app_generator"
3
3
 
4
4
  module Suspenders
5
5
  class AppGenerator < Rails::Generators::AppGenerator
6
6
  hide!
7
7
 
8
8
  class_option :database, type: :string, aliases: "-d", default: "postgresql",
9
- desc: "Configure for selected database (options: #{DATABASES.join("/")})"
9
+ desc: "Configure for selected database (options: #{DATABASES.join("/")})"
10
10
 
11
11
  class_option :heroku, type: :boolean, aliases: "-H", default: false,
12
- desc: "Create staging and production Heroku apps"
12
+ desc: "Create staging and production Heroku apps"
13
13
 
14
14
  class_option :heroku_flags, type: :string, default: "",
15
- desc: "Set extra Heroku flags"
15
+ desc: "Set extra Heroku flags"
16
16
 
17
17
  class_option :github, type: :string, default: nil,
18
- desc: "Create Github repository and add remote origin pointed to repo"
18
+ desc: "Create Github repository and add remote origin pointed to repo"
19
19
 
20
20
  class_option :version, type: :boolean, aliases: "-v", group: :suspenders,
21
- desc: "Show Suspenders version number and quit"
21
+ desc: "Show Suspenders version number and quit"
22
22
 
23
- class_option :help, type: :boolean, aliases: '-h', group: :suspenders,
24
- desc: "Show this help message and quit"
23
+ class_option :help, type: :boolean, aliases: "-h", group: :suspenders,
24
+ desc: "Show this help message and quit"
25
25
 
26
26
  class_option :path, type: :string, default: nil,
27
- desc: "Path to the gem"
27
+ desc: "Path to the gem"
28
28
 
29
29
  class_option :skip_test, type: :boolean, default: true,
30
- desc: "Skip Test Unit"
30
+ desc: "Skip Test Unit"
31
31
 
32
32
  class_option :skip_system_test,
33
- type: :boolean, default: true, desc: "Skip system test files"
33
+ type: :boolean, default: true, desc: "Skip system test files"
34
34
 
35
35
  class_option :skip_turbolinks,
36
- type: :boolean, default: true, desc: "Skip turbolinks gem"
36
+ type: :boolean, default: true, desc: "Skip turbolinks gem"
37
37
 
38
38
  def finish_template
39
39
  invoke :suspenders_customization
@@ -47,14 +47,9 @@ module Suspenders
47
47
  invoke :setup_secret_token
48
48
  invoke :configure_app
49
49
  invoke :copy_miscellaneous_files
50
- invoke :customize_error_pages
51
- invoke :setup_dotfiles
52
50
  invoke :setup_database
53
51
  invoke :create_github_repo
54
- invoke :setup_bundler_audit
55
- invoke :setup_spring
56
52
  invoke :generate_default
57
- invoke :setup_default_directories
58
53
  invoke :create_heroku_apps
59
54
  invoke :generate_deployment_default
60
55
  invoke :remove_config_comment_lines
@@ -64,13 +59,13 @@ module Suspenders
64
59
 
65
60
  def customize_gemfile
66
61
  build :replace_gemfile, options[:path]
67
- bundle_command 'install'
62
+ bundle_command "install"
68
63
  end
69
64
 
70
65
  def setup_database
71
- say 'Setting up database'
66
+ say "Setting up database"
72
67
 
73
- if 'postgresql' == options[:database]
68
+ if options[:database] == "postgresql"
74
69
  build :use_postgres_config_template
75
70
  end
76
71
 
@@ -78,7 +73,7 @@ module Suspenders
78
73
  end
79
74
 
80
75
  def setup_development_environment
81
- say 'Setting up the development environment'
76
+ say "Setting up the development environment"
82
77
  build :configure_local_mail
83
78
  build :raise_on_missing_assets_in_test
84
79
  build :raise_on_delivery_errors
@@ -91,25 +86,20 @@ module Suspenders
91
86
  end
92
87
 
93
88
  def setup_production_environment
94
- say 'Setting up the production environment'
95
- build :enable_rack_canonical_host
96
- build :enable_rack_deflater
89
+ say "Setting up the production environment"
97
90
  build :setup_asset_host
98
91
  end
99
92
 
100
93
  def setup_secret_token
101
- say 'Moving secret token out of version control'
94
+ say "Moving secret token out of version control"
102
95
  build :setup_secret_token
103
96
  end
104
97
 
105
98
  def configure_app
106
- say 'Configuring app'
99
+ say "Configuring app"
107
100
  build :configure_action_mailer
108
101
  build :configure_time_formats
109
102
  build :setup_default_rake_task
110
- build :replace_default_puma_configuration
111
- build :set_up_forego
112
- build :setup_rack_mini_profiler
113
103
  end
114
104
 
115
105
  def create_heroku_apps
@@ -121,6 +111,7 @@ module Suspenders
121
111
  build :set_heroku_application_host
122
112
  build :set_heroku_honeybadger_env
123
113
  build :set_heroku_backup_schedule
114
+ build :set_heroku_buildpacks
124
115
  build :create_heroku_pipeline
125
116
  build :configure_automatic_deployment
126
117
  end
@@ -128,39 +119,16 @@ module Suspenders
128
119
 
129
120
  def create_github_repo
130
121
  if !options[:skip_git] && options[:github]
131
- say 'Creating Github repo'
122
+ say "Creating Github repo"
132
123
  build :create_github_repo, options[:github]
133
124
  end
134
125
  end
135
126
 
136
- def setup_dotfiles
137
- build :copy_dotfiles
138
- end
139
-
140
- def setup_default_directories
141
- build :setup_default_directories
142
- end
143
-
144
- def setup_bundler_audit
145
- say "Setting up bundler-audit"
146
- build :setup_bundler_audit
147
- end
148
-
149
- def setup_spring
150
- say "Springifying binstubs"
151
- build :setup_spring
152
- end
153
-
154
127
  def copy_miscellaneous_files
155
- say 'Copying miscellaneous support files'
128
+ say "Copying miscellaneous support files"
156
129
  build :copy_miscellaneous_files
157
130
  end
158
131
 
159
- def customize_error_pages
160
- say 'Customizing the 500/404/422 pages'
161
- build :customize_error_pages
162
- end
163
-
164
132
  def remove_config_comment_lines
165
133
  build :remove_config_comment_lines
166
134
  end
@@ -171,6 +139,8 @@ module Suspenders
171
139
 
172
140
  def generate_default
173
141
  run("spring stop")
142
+ generate("suspenders:runner")
143
+ generate("suspenders:profiler")
174
144
  generate("suspenders:json")
175
145
  generate("suspenders:static")
176
146
  generate("suspenders:stylesheet_base")
@@ -185,11 +155,15 @@ module Suspenders
185
155
  generate("suspenders:lint")
186
156
  generate("suspenders:jobs")
187
157
  generate("suspenders:analytics")
188
- generate("suspenders:views")
158
+ generate("suspenders:inline_svg")
159
+ generate("suspenders:advisories")
160
+ generate("suspenders:preloader")
189
161
  end
190
162
 
191
163
  def generate_deployment_default
192
164
  generate("suspenders:staging:pull_requests")
165
+ generate("suspenders:production:single_redirect")
166
+ generate("suspenders:production:compression")
193
167
  generate("suspenders:production:force_tls")
194
168
  generate("suspenders:production:email")
195
169
  generate("suspenders:production:timeout")
@@ -197,13 +171,17 @@ module Suspenders
197
171
  generate("suspenders:production:manifest")
198
172
  end
199
173
 
174
+ def generate_views
175
+ generate("suspenders:views")
176
+ end
177
+
200
178
  def outro
201
- say 'Congratulations! You just pulled our suspenders.'
179
+ say "Congratulations! You just pulled our suspenders."
202
180
  say honeybadger_outro
203
181
  end
204
182
 
205
183
  def self.banner
206
- "suspenders #{arguments.map(&:usage).join(' ')} [options]"
184
+ "suspenders #{arguments.map(&:usage).join(" ")} [options]"
207
185
  end
208
186
 
209
187
  protected
@@ -10,10 +10,49 @@ module Suspenders
10
10
  File.expand_path(File.join("..", "..", "..", "templates"), __dir__)
11
11
  end
12
12
 
13
+ def self.inherited(subclass)
14
+ super
15
+
16
+ description_file = File.expand_path(
17
+ File.join(
18
+ default_source_root,
19
+ "descriptions",
20
+ "#{subclass.generator_name}.md"
21
+ )
22
+ )
23
+
24
+ subclass.desc File.read(description_file)
25
+ rescue Errno::ENOENT
26
+ end
27
+
13
28
  private
14
29
 
15
30
  def app_name
16
- Rails.app_class.parent_name.demodulize.underscore.dasherize
31
+ Rails.app_class.module_parent_name.demodulize.underscore.dasherize
32
+ end
33
+
34
+ def empty_directory_with_keep_file(destination)
35
+ empty_directory(destination, {})
36
+ keep_file(destination)
37
+ end
38
+
39
+ def keep_file(destination)
40
+ create_file(File.join(destination, ".keep"))
41
+ end
42
+
43
+ def append_template_to_file(destination, source, *args)
44
+ partial = File.expand_path(find_in_source_paths(source))
45
+ append_to_file(destination, File.read(partial, *args))
46
+ end
47
+
48
+ def prepend_template_to_file(destination, source, *args)
49
+ partial = File.expand_path(find_in_source_paths(source))
50
+ prepend_to_file(destination, File.read(partial, *args))
51
+ end
52
+
53
+ def inject_template_into_file(destination, source, *args)
54
+ partial = File.expand_path(find_in_source_paths(source))
55
+ inject_into_file(destination, File.read(partial), *args)
17
56
  end
18
57
  end
19
58
  end
@@ -2,21 +2,31 @@ require_relative "base"
2
2
 
3
3
  module Suspenders
4
4
  class CiGenerator < Generators::Base
5
+ def simplecov_gem
6
+ gem "simplecov", require: false, group: [:test]
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
+ end
9
+
5
10
  def simplecov_test_integration
6
- inject_into_file "spec/spec_helper.rb", before: 'SimpleCov.start "rails"' do
7
- <<-RUBY
11
+ prepend_template_to_file(test_helper_file, "partials/ci_simplecov.rb")
12
+ end
8
13
 
9
- if ENV["CIRCLE_ARTIFACTS"]
10
- dir = File.join(ENV["CIRCLE_ARTIFACTS"], "coverage")
11
- SimpleCov.coverage_dir(dir)
12
- end
14
+ def configure_ci
15
+ template "circle.yml.erb", "circle.yml"
16
+ end
17
+
18
+ private
13
19
 
14
- RUBY
20
+ def test_helper_file
21
+ if using_rspec?
22
+ "spec/spec_helper.rb"
23
+ else
24
+ "test/test_helper.rb"
15
25
  end
16
26
  end
17
27
 
18
- def configure_ci
19
- template "circle.yml.erb", "circle.yml"
28
+ def using_rspec?
29
+ File.exist?("spec/spec_helper.rb")
20
30
  end
21
31
  end
22
32
  end
@@ -3,28 +3,16 @@ require_relative "base"
3
3
  module Suspenders
4
4
  class DbOptimizationsGenerator < Generators::Base
5
5
  def add_bullet
6
- gem "bullet", group: %i(development test)
7
- Bundler.with_clean_env { run "bundle install" }
6
+ gem "bullet", group: %i[development test]
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
8
  end
9
9
 
10
10
  def configure_bullet
11
- inject_into_file(
11
+ inject_template_into_file(
12
12
  "config/environments/development.rb",
13
- configuration,
14
- after: "config.action_mailer.raise_delivery_errors = true\n",
13
+ "partials/db_optimizations_configuration.rb",
14
+ after: /config.action_mailer.raise_delivery_errors = .*/
15
15
  )
16
16
  end
17
-
18
- private
19
-
20
- def configuration
21
- <<-RUBY
22
- config.after_initialize do
23
- Bullet.enable = true
24
- Bullet.bullet_logger = true
25
- Bullet.rails_logger = true
26
- end
27
- RUBY
28
- end
29
17
  end
30
18
  end
@@ -3,8 +3,8 @@ require_relative "base"
3
3
  module Suspenders
4
4
  class FactoriesGenerator < Generators::Base
5
5
  def add_factory_bot
6
- gem "factory_bot_rails", group: %i(development test)
7
- Bundler.with_clean_env { run "bundle install" }
6
+ gem "factory_bot_rails", group: %i[development test]
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
8
  end
9
9
 
10
10
  def set_up_factory_bot_for_rspec
@@ -4,7 +4,7 @@ module Suspenders
4
4
  class FormsGenerator < Generators::Base
5
5
  def add_simple_form
6
6
  gem "simple_form"
7
- Bundler.with_clean_env { run "bundle install" }
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
8
  end
9
9
 
10
10
  def configure_simple_form
@@ -0,0 +1,14 @@
1
+ require_relative "base"
2
+
3
+ module Suspenders
4
+ class InlineSvgGenerator < Generators::Base
5
+ def add_inline_svg
6
+ gem "inline_svg"
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
+ end
9
+
10
+ def configure_inline_svg
11
+ copy_file "inline_svg.rb", "config/initializers/inline_svg.rb"
12
+ end
13
+ end
14
+ end
@@ -4,7 +4,7 @@ module Suspenders
4
4
  class JobsGenerator < Generators::Base
5
5
  def add_jobs_gem
6
6
  gem "delayed_job_active_record"
7
- Bundler.with_clean_env { run "bundle install" }
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
8
  end
9
9
 
10
10
  def configure_background_jobs_for_rspec
@@ -14,13 +14,13 @@ module Suspenders
14
14
  def initialize_active_job
15
15
  copy_file(
16
16
  "active_job.rb",
17
- "config/initializers/active_job.rb",
17
+ "config/initializers/active_job.rb"
18
18
  )
19
19
  end
20
20
 
21
21
  def configure_active_job
22
22
  configure_application_file(
23
- "config.active_job.queue_adapter = :delayed_job",
23
+ "config.active_job.queue_adapter = :delayed_job"
24
24
  )
25
25
  configure_environment "test", "config.active_job.queue_adapter = :inline"
26
26
  end
@@ -31,7 +31,7 @@ module Suspenders
31
31
  inject_into_file(
32
32
  "config/application.rb",
33
33
  "\n #{config}",
34
- before: "\n end",
34
+ before: "\n end"
35
35
  )
36
36
  end
37
37
  end
@@ -3,13 +3,16 @@ require_relative "base"
3
3
  module Suspenders
4
4
  class JsDriverGenerator < Generators::Base
5
5
  def add_gems
6
- gem "capybara-selenium", group: :test
7
- gem "chromedriver-helper", group: :test
8
- Bundler.with_clean_env { run "bundle install" }
6
+ gem "webdrivers", group: :test
7
+ Bundler.with_unbundled_env { run "bundle install" }
9
8
  end
10
9
 
11
- def configure_chromedriver
10
+ def configure_capybara
12
11
  copy_file "chromedriver.rb", "spec/support/chromedriver.rb"
12
+ copy_file(
13
+ "capybara_silence_puma.rb",
14
+ "spec/support/capybara_silence_puma.rb"
15
+ )
13
16
  end
14
17
  end
15
18
  end