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,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
@@ -1,12 +1,7 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class AnalyticsGenerator < Rails::Generators::Base
5
- source_root File.expand_path(
6
- File.join("..", "..", "..", "templates"),
7
- File.dirname(__FILE__),
8
- )
9
-
4
+ class AnalyticsGenerator < Generators::Base
10
5
  def install_partial
11
6
  copy_file "_analytics.html.erb",
12
7
  "app/views/application/_analytics.html.erb"
@@ -47,15 +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
- invoke :create_local_heroku_setup
59
53
  invoke :create_heroku_apps
60
54
  invoke :generate_deployment_default
61
55
  invoke :remove_config_comment_lines
@@ -93,8 +87,6 @@ module Suspenders
93
87
 
94
88
  def setup_production_environment
95
89
  say 'Setting up the production environment'
96
- build :enable_rack_canonical_host
97
- build :enable_rack_deflater
98
90
  build :setup_asset_host
99
91
  end
100
92
 
@@ -108,15 +100,6 @@ module Suspenders
108
100
  build :configure_action_mailer
109
101
  build :configure_time_formats
110
102
  build :setup_default_rake_task
111
- build :replace_default_puma_configuration
112
- build :set_up_forego
113
- build :setup_rack_mini_profiler
114
- end
115
-
116
- def create_local_heroku_setup
117
- say "Creating local Heroku setup"
118
- build :create_deploy_script
119
- build :create_heroku_application_manifest_file
120
103
  end
121
104
 
122
105
  def create_heroku_apps
@@ -128,6 +111,7 @@ module Suspenders
128
111
  build :set_heroku_application_host
129
112
  build :set_heroku_honeybadger_env
130
113
  build :set_heroku_backup_schedule
114
+ build :set_heroku_buildpacks
131
115
  build :create_heroku_pipeline
132
116
  build :configure_automatic_deployment
133
117
  end
@@ -140,34 +124,11 @@ module Suspenders
140
124
  end
141
125
  end
142
126
 
143
- def setup_dotfiles
144
- build :copy_dotfiles
145
- end
146
-
147
- def setup_default_directories
148
- build :setup_default_directories
149
- end
150
-
151
- def setup_bundler_audit
152
- say "Setting up bundler-audit"
153
- build :setup_bundler_audit
154
- end
155
-
156
- def setup_spring
157
- say "Springifying binstubs"
158
- build :setup_spring
159
- end
160
-
161
127
  def copy_miscellaneous_files
162
128
  say 'Copying miscellaneous support files'
163
129
  build :copy_miscellaneous_files
164
130
  end
165
131
 
166
- def customize_error_pages
167
- say 'Customizing the 500/404/422 pages'
168
- build :customize_error_pages
169
- end
170
-
171
132
  def remove_config_comment_lines
172
133
  build :remove_config_comment_lines
173
134
  end
@@ -178,6 +139,7 @@ module Suspenders
178
139
 
179
140
  def generate_default
180
141
  run("spring stop")
142
+ generate("suspenders:profiler")
181
143
  generate("suspenders:json")
182
144
  generate("suspenders:static")
183
145
  generate("suspenders:stylesheet_base")
@@ -192,14 +154,25 @@ module Suspenders
192
154
  generate("suspenders:lint")
193
155
  generate("suspenders:jobs")
194
156
  generate("suspenders:analytics")
195
- generate("suspenders:views")
157
+ generate("suspenders:inline_svg")
158
+ generate("suspenders:advisories")
159
+ generate("suspenders:runner")
160
+ generate("suspenders:preloader")
196
161
  end
197
162
 
198
163
  def generate_deployment_default
199
164
  generate("suspenders:staging:pull_requests")
165
+ generate("suspenders:production:single_redirect")
166
+ generate("suspenders:production:compression")
200
167
  generate("suspenders:production:force_tls")
201
168
  generate("suspenders:production:email")
202
169
  generate("suspenders:production:timeout")
170
+ generate("suspenders:production:deployment")
171
+ generate("suspenders:production:manifest")
172
+ end
173
+
174
+ def generate_views
175
+ generate("suspenders:views")
203
176
  end
204
177
 
205
178
  def outro
@@ -0,0 +1,59 @@
1
+ require "rails/generators"
2
+ require_relative "../actions"
3
+
4
+ module Suspenders
5
+ module Generators
6
+ class Base < Rails::Generators::Base
7
+ include Suspenders::Actions
8
+
9
+ def self.default_source_root
10
+ File.expand_path(File.join("..", "..", "..", "templates"), __dir__)
11
+ end
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
+
28
+ private
29
+
30
+ def app_name
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)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,26 +1,32 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class CiGenerator < Rails::Generators::Base
5
- source_root File.expand_path(
6
- File.join("..", "..", "..", "templates"),
7
- File.dirname(__FILE__))
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
8
9
 
9
10
  def simplecov_test_integration
10
- inject_into_file "spec/spec_helper.rb", before: 'SimpleCov.start "rails"' do
11
- <<-RUBY
11
+ prepend_template_to_file(test_helper_file, "partials/ci_simplecov.rb")
12
+ end
12
13
 
13
- if ENV["CIRCLE_ARTIFACTS"]
14
- dir = File.join(ENV["CIRCLE_ARTIFACTS"], "coverage")
15
- SimpleCov.coverage_dir(dir)
16
- end
14
+ def configure_ci
15
+ template "circle.yml.erb", "circle.yml"
16
+ end
17
+
18
+ private
17
19
 
18
- RUBY
20
+ def test_helper_file
21
+ if using_rspec?
22
+ "spec/spec_helper.rb"
23
+ else
24
+ "test/test_helper.rb"
19
25
  end
20
26
  end
21
27
 
22
- def configure_ci
23
- template "circle.yml.erb", "circle.yml"
28
+ def using_rspec?
29
+ File.exist?("spec/spec_helper.rb")
24
30
  end
25
31
  end
26
32
  end
@@ -1,30 +1,18 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class DbOptimizationsGenerator < Rails::Generators::Base
4
+ class DbOptimizationsGenerator < Generators::Base
5
5
  def add_bullet
6
6
  gem "bullet", group: %i(development test)
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_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
@@ -1,15 +1,10 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class FactoriesGenerator < Rails::Generators::Base
5
- source_root File.expand_path(
6
- File.join("..", "..", "..", "templates"),
7
- File.dirname(__FILE__),
8
- )
9
-
4
+ class FactoriesGenerator < Generators::Base
10
5
  def add_factory_bot
11
6
  gem "factory_bot_rails", group: %i(development test)
12
- Bundler.with_clean_env { run "bundle install" }
7
+ Bundler.with_unbundled_env { run "bundle install" }
13
8
  end
14
9
 
15
10
  def set_up_factory_bot_for_rspec
@@ -1,10 +1,10 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class FormsGenerator < Rails::Generators::Base
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
@@ -1,20 +1,10 @@
1
- require "rails/generators"
2
- require_relative "../actions"
1
+ require_relative "base"
3
2
 
4
3
  module Suspenders
5
- class JobsGenerator < Rails::Generators::Base
6
- include Suspenders::Actions
7
-
8
- source_root(
9
- File.expand_path(
10
- File.join("..", "..", "..", "templates"),
11
- File.dirname(__FILE__),
12
- ),
13
- )
14
-
4
+ class JobsGenerator < Generators::Base
15
5
  def add_jobs_gem
16
6
  gem "delayed_job_active_record"
17
- Bundler.with_clean_env { run "bundle install" }
7
+ Bundler.with_unbundled_env { run "bundle install" }
18
8
  end
19
9
 
20
10
  def configure_background_jobs_for_rspec
@@ -1,20 +1,18 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class JsDriverGenerator < Rails::Generators::Base
5
- source_root File.expand_path(
6
- File.join("..", "..", "..", "templates"),
7
- File.dirname(__FILE__),
8
- )
9
-
4
+ class JsDriverGenerator < Generators::Base
10
5
  def add_gems
11
- gem "capybara-selenium", group: :test
12
- gem "chromedriver-helper", group: :test
13
- Bundler.with_clean_env { run "bundle install" }
6
+ gem "webdrivers", group: :test
7
+ Bundler.with_unbundled_env { run "bundle install" }
14
8
  end
15
9
 
16
- def configure_chromedriver
10
+ def configure_capybara
17
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
+ )
18
16
  end
19
17
  end
20
18
  end
@@ -1,10 +1,10 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class JsonGenerator < Rails::Generators::Base
4
+ class JsonGenerator < Generators::Base
5
5
  def add_oj
6
6
  gem "oj"
7
- Bundler.with_clean_env { run "bundle install" }
7
+ Bundler.with_unbundled_env { run "bundle install" }
8
8
  end
9
9
  end
10
10
  end
@@ -1,12 +1,7 @@
1
- require "rails/generators"
1
+ require_relative "base"
2
2
 
3
3
  module Suspenders
4
- class LintGenerator < Rails::Generators::Base
5
- source_root File.expand_path(
6
- File.join("..", "..", "..", "templates"),
7
- File.dirname(__FILE__),
8
- )
9
-
4
+ class LintGenerator < Generators::Base
10
5
  def set_up_hound
11
6
  copy_file "hound.yml", ".hound.yml"
12
7
  end
@@ -0,0 +1,122 @@
1
+ require_relative "base"
2
+
3
+ module Suspenders
4
+ class PreloaderGenerator < Generators::Base
5
+ def spring_config
6
+ template "spring.rb", "config/spring.rb", force: false, skip: true
7
+ end
8
+
9
+ def spring_gem
10
+ always_gsub_file("Gemfile", /# Spring speeds up development.*/, "")
11
+
12
+ gem_group :development do
13
+ gem "spring"
14
+ gem "spring-watcher-listen", "~> 2.0.0"
15
+ end
16
+
17
+ Bundler.with_unbundled_env { run "bundle install" }
18
+ end
19
+
20
+ def cache_classes_test
21
+ action UncacheClasses.new(self, "config/environments/test.rb")
22
+ end
23
+
24
+ def spring_binstubs
25
+ action SpringBinstubs.new(self)
26
+ end
27
+
28
+ class SpringBinstubs
29
+ def initialize(base)
30
+ @base = base
31
+ end
32
+
33
+ def invoke!
34
+ Bundler.with_unbundled_env do
35
+ @base.send(:always_run, "spring binstub --all")
36
+ end
37
+ end
38
+
39
+ def revoke!
40
+ Bundler.with_unbundled_env do
41
+ @base.send(:always_run, "spring binstub --remove --all")
42
+ end
43
+ end
44
+ end
45
+
46
+ class UncacheClasses
47
+ def initialize(base, config_file)
48
+ @base = base
49
+ @config_file = config_file
50
+ end
51
+
52
+ def invoke!
53
+ @base.send(
54
+ :always_gsub_file,
55
+ @config_file,
56
+ "config.cache_classes = true",
57
+ "config.cache_classes = false",
58
+ )
59
+ end
60
+
61
+ def revoke!
62
+ @base.send(
63
+ :always_gsub_file,
64
+ @config_file,
65
+ "config.cache_classes = false",
66
+ "config.cache_classes = true",
67
+ )
68
+ end
69
+ end
70
+
71
+ protected
72
+
73
+ def always_run(command, with: nil, verbose: true, env: nil, capture: nil,
74
+ abort_on_failure: nil)
75
+ destination = relative_to_original_destination_root(
76
+ destination_root,
77
+ false,
78
+ )
79
+ desc = "#{command} from #{destination.inspect}"
80
+
81
+ if with
82
+ desc = "#{File.basename(with.to_s)} #{desc}"
83
+ command = "#{with} #{command}"
84
+ end
85
+
86
+ say_status :run, desc, verbose
87
+
88
+ return if options[:pretend]
89
+
90
+ env_splat = [env] if env
91
+
92
+ if capture
93
+ result, status = Open3.capture2e(*env_splat, command.to_s)
94
+ success = status.success?
95
+ else
96
+ result = system(*env_splat, command.to_s)
97
+ success = result
98
+ end
99
+
100
+ if abort_on_failure.nil?
101
+ abort_on_failure = self.class.send(:exit_on_failure?)
102
+ end
103
+
104
+ if !success && abort_on_failure
105
+ abort
106
+ end
107
+
108
+ result
109
+ end
110
+
111
+ def always_gsub_file(path, flag, replacement, verbose: true)
112
+ path = File.expand_path(path, destination_root)
113
+ say_status :gsub, relative_to_original_destination_root(path), verbose
114
+
115
+ unless options[:pretend]
116
+ content = File.binread(path)
117
+ content.gsub!(flag, replacement)
118
+ File.open(path, "wb") { |file| file.write(content) }
119
+ end
120
+ end
121
+ end
122
+ end