suspenders 1.54.1 → 1.56.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/NEWS.md +38 -1
  5. data/README.md +5 -12
  6. data/bin/suspenders +29 -2
  7. data/lib/suspenders/actions/strip_comments_action.rb +254 -0
  8. data/lib/suspenders/actions.rb +1 -1
  9. data/lib/suspenders/adapters/heroku.rb +16 -16
  10. data/lib/suspenders/app_builder.rb +49 -47
  11. data/lib/suspenders/exit_on_failure.rb +19 -0
  12. data/lib/suspenders/generators/advisories_generator.rb +1 -1
  13. data/lib/suspenders/generators/analytics_generator.rb +1 -1
  14. data/lib/suspenders/generators/app_generator.rb +30 -23
  15. data/lib/suspenders/generators/base.rb +3 -2
  16. data/lib/suspenders/generators/db_optimizations_generator.rb +2 -2
  17. data/lib/suspenders/generators/factories_generator.rb +1 -1
  18. data/lib/suspenders/generators/jobs_generator.rb +3 -3
  19. data/lib/suspenders/generators/js_driver_generator.rb +1 -1
  20. data/lib/suspenders/generators/json_generator.rb +4 -0
  21. data/lib/suspenders/generators/lint_generator.rb +5 -0
  22. data/lib/suspenders/generators/production/compression_generator.rb +1 -1
  23. data/lib/suspenders/generators/production/email_generator.rb +7 -7
  24. data/lib/suspenders/generators/production/manifest_generator.rb +8 -8
  25. data/lib/suspenders/generators/production/single_redirect.rb +1 -1
  26. data/lib/suspenders/generators/production/timeout_generator.rb +2 -2
  27. data/lib/suspenders/generators/profiler_generator.rb +4 -4
  28. data/lib/suspenders/generators/runner_generator.rb +4 -4
  29. data/lib/suspenders/generators/staging/pull_requests_generator.rb +2 -2
  30. data/lib/suspenders/generators/stylelint_generator.rb +2 -1
  31. data/lib/suspenders/generators/stylesheet_base_generator.rb +1 -1
  32. data/lib/suspenders/generators/testing_generator.rb +2 -3
  33. data/lib/suspenders/version.rb +5 -5
  34. data/lib/suspenders.rb +2 -1
  35. data/templates/capybara_silence_puma.rb +1 -1
  36. data/templates/descriptions/testing.md +1 -1
  37. data/templates/errors.rb +4 -3
  38. data/templates/hound.yml +1 -2
  39. data/templates/oj.rb +3 -0
  40. data/templates/partials/ci_simplecov.rb +0 -2
  41. data/templates/partials/email_smtp.rb +0 -1
  42. data/templates/partials/pull_requests_config.rb +4 -4
  43. data/templates/partials/runner_setup.rb +1 -2
  44. data/templates/postgresql_database.yml.erb +1 -0
  45. data/templates/spec_helper.rb +1 -1
  46. metadata +64 -89
  47. data/.gitignore +0 -5
  48. data/.travis.yml +0 -15
  49. data/Gemfile +0 -3
  50. data/Rakefile +0 -8
  51. data/USAGE +0 -13
  52. data/bin/rake +0 -16
  53. data/bin/rspec +0 -16
  54. data/bin/setup +0 -13
  55. data/lib/suspenders/generators/preloader_generator.rb +0 -122
  56. data/spec/adapters/heroku_spec.rb +0 -98
  57. data/spec/expand_json_spec.rb +0 -89
  58. data/spec/fakes/bin/heroku +0 -5
  59. data/spec/fakes/bin/hub +0 -5
  60. data/spec/features/advisories_spec.rb +0 -24
  61. data/spec/features/api_spec.rb +0 -18
  62. data/spec/features/ci_spec.rb +0 -31
  63. data/spec/features/cli_help_spec.rb +0 -36
  64. data/spec/features/db_optimizations_spec.rb +0 -19
  65. data/spec/features/github_spec.rb +0 -16
  66. data/spec/features/heroku_spec.rb +0 -64
  67. data/spec/features/inline_svg_spec.rb +0 -10
  68. data/spec/features/json_spec.rb +0 -15
  69. data/spec/features/new_project_spec.rb +0 -319
  70. data/spec/features/preloader_spec.rb +0 -25
  71. data/spec/features/production/compression_spec.rb +0 -23
  72. data/spec/features/production/deployment_spec.rb +0 -22
  73. data/spec/features/production/email_spec.rb +0 -47
  74. data/spec/features/production/manifest_spec.rb +0 -37
  75. data/spec/features/production/single_redirect_spec.rb +0 -25
  76. data/spec/features/profiler_spec.rb +0 -20
  77. data/spec/features/runner_spec.rb +0 -30
  78. data/spec/features/staging/pull_requests_spec.rb +0 -22
  79. data/spec/features/static_spec.rb +0 -17
  80. data/spec/features/stylelint_spec.rb +0 -60
  81. data/spec/spec_helper.rb +0 -21
  82. data/spec/support/be_executable_matcher.rb +0 -7
  83. data/spec/support/contain_json_matcher.rb +0 -30
  84. data/spec/support/exist_as_a_file_matcher.rb +0 -7
  85. data/spec/support/fake_github.rb +0 -21
  86. data/spec/support/fake_heroku.rb +0 -53
  87. data/spec/support/generators.rb +0 -5
  88. data/spec/support/match_contents_matcher.rb +0 -6
  89. data/spec/support/project_files.rb +0 -25
  90. data/spec/support/rails_template.rb +0 -1
  91. data/spec/support/suspenders.rb +0 -185
  92. data/suspenders.gemspec +0 -35
  93. data/templates/descriptions/preloader.md +0 -3
  94. data/templates/spring.rb +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1c3a5fd298d2c49ceed3d4b3c79d99590aae75259c0f4ec6f06bd6f244336d3
4
- data.tar.gz: c880d208a127a68da87b63a33da39fade1abf8e6c6d6b754806771be68e23e03
3
+ metadata.gz: 683a61a7377c93edb0f396688cd578f338bcdc5de7ffb28276165e1bb81edcc4
4
+ data.tar.gz: c5a8d3b44cd4c8f9277b0f7d4c223b034b4ae93d050830c3f8755eef1766814e
5
5
  SHA512:
6
- metadata.gz: 35d40b50ca80e2248efe6cc0c5ac5b87eff319aa6638e9293bafbb798081a1143b7a2d0e5907261bf68ceece79f482471c0762782a6d4cfebc69b0871fe8ea28
7
- data.tar.gz: d02195af5d9673603233ce092cae10b4a2e2cf49697d8129c808a378d743d008f9046787b53ec050ec9a4450433fb063a7fbc4308fb5c16efc17d3ed73de291a
6
+ metadata.gz: 7646058fca03e48da09e9a3a26ec4ca21f9e07a51ff2394f548b231c1b50d78ea514c27589473039ed9cb86e9fddb6614ca00bad68dbe19800590f56e6124c46
7
+ data.tar.gz: 67cffd8fa9c7fe841ec6595545bb200b38f500baef0036b9bf29be8c7950b59fb27ed8f2094933fd9d8b00760981a516bd17f6d5e83765290d0ba74fac44c73f
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.6.6
1
+ 2.7.4
data/CONTRIBUTING.md CHANGED
@@ -48,7 +48,7 @@ All new contributions must be within the generator framework, as described in
48
48
 
49
49
  ## Versions
50
50
 
51
- To update the Ruby version, change `.ruby-version` and `.travis.yml`.
51
+ To update the Ruby version, change `.ruby-version`.
52
52
 
53
53
  If you see this error while running tests:
54
54
 
data/NEWS.md CHANGED
@@ -1,4 +1,41 @@
1
- Unreleased
1
+ 1.56.1 (July 17, 2022)
2
+
3
+ Fixes a critical error with the previous release
4
+
5
+ * Run database migrations as the last step of bin/suspenders
6
+ * Fix bundler error on bin/suspenders script
7
+
8
+ 1.56.0 (July 4, 2022)
9
+
10
+ Maintenance release
11
+
12
+ * Fixed: Make Suspenders fail if running with an unsupported Rails version
13
+ * Added: Update default configuration to use request specs
14
+ * Added: Add missing Errno::ECONNREFUSED to HTTP_ERRORS
15
+ * Fixed: Drop use of git in gemspec
16
+ * Fixed: Enforce bundler >= 2.1.0
17
+ * Fixed: Make suspenders abort when something goes wrong
18
+ * Fixed: Reliability and aesthetics of the config files comment stripper
19
+ * Fixed: ActionMailer asset host in the production configuration
20
+ * Added: Configure the oj gem (fast JSON parsing) when generating a new application
21
+ * Fixed: Improve error message of the match_contents matcher
22
+ * Fixed: Convert generator tests to unit tests thus speeding up the test suite
23
+ * Removed: Preloader generator / spring
24
+ * Added: Pull in DATABASE_URL env var explicitly in database.yml
25
+ * Removed: Travis CI configuration
26
+ * Upgraded: Ruby to version 2.7.4
27
+ * Added: A GitHub Action for CI
28
+ * Fixed: Run bin/suspenders in both CLI and tests against a fixed Rails version
29
+
30
+ 1.55.1 (September 11, 2020)
31
+
32
+ * Fixed: Missing newline in generated development config
33
+
34
+ 1.55.0 (July 15, 2020)
35
+
36
+ * Changed: lint generator to install standard instead of RuboCop
37
+ * Changed: profile generator and timeout generator to write to `.sample.env`
38
+ instead of `.env`
2
39
 
3
40
  1.54.1 (June 30, 2020)
4
41
 
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
- # Suspenders [![Build Status](https://secure.travis-ci.org/thoughtbot/suspenders.svg?branch=master)](http://travis-ci.org/thoughtbot/suspenders) [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
1
+ # Suspenders
2
+
3
+ [![Build Status](https://github.com/thoughtbot/suspenders/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/thoughtbot/suspenders/actions)
4
+ [![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
2
5
 
3
6
  Suspenders is the base Rails application used at
4
7
  [thoughtbot](https://thoughtbot.com/).
@@ -64,8 +67,6 @@ And development gems like:
64
67
  unused eager loading
65
68
  * [Bundler Audit](https://github.com/rubysec/bundler-audit) for scanning the
66
69
  Gemfile for insecure dependencies based on published CVEs
67
- * [Spring](https://github.com/rails/spring) for fast Rails actions via
68
- pre-loading
69
70
  * [Web Console](https://github.com/rails/web-console) for better debugging via
70
71
  in-browser IRB consoles.
71
72
 
@@ -155,21 +156,13 @@ bypass this with the `--skip-git` option:
155
156
  You can optionally create a GitHub repository for the suspended Rails app. It
156
157
  requires that you have [Hub](https://github.com/github/hub) on your system:
157
158
 
158
- curl https://hub.github.com/standalone -sLo ~/bin/hub && chmod +x ~/bin/hub
159
+ brew install hub # macOS, for other systems see https://github.com/github/hub#installation
159
160
  suspenders app --github organization/project
160
161
 
161
162
  This has the same effect as running:
162
163
 
163
164
  hub create organization/project
164
165
 
165
- ## Spring
166
-
167
- Suspenders uses [spring](https://github.com/rails/spring) by default.
168
- It makes Rails applications load faster, but it might introduce confusing issues
169
- around stale code not being refreshed.
170
- If you think your application is running old code, run `spring stop`.
171
- And if you'd rather not use spring, add `DISABLE_SPRING=1` to your login file.
172
-
173
166
  ## Dependencies
174
167
 
175
168
  Suspenders requires the latest version of Ruby.
data/bin/suspenders CHANGED
@@ -4,14 +4,41 @@ require 'pathname'
4
4
  source_path = (Pathname.new(__FILE__).dirname + '../lib').expand_path
5
5
  $LOAD_PATH << source_path
6
6
 
7
- require 'suspenders'
7
+ activate_rails_version = ->(rails_version) do
8
+ rails_bin_path = Gem.activate_bin_path("railties", "rails", rails_version)
9
+ rails_path = File.expand_path("../..", rails_bin_path)
10
+ $LOAD_PATH.unshift(rails_path)
11
+ end
12
+
13
+ if str = ARGV.first
14
+ str = str.b[/\A_(.*)_\z/, 1]
15
+
16
+ if str && Gem::Version.correct?(str)
17
+ rails_version = str
18
+ ARGV.shift
19
+
20
+ begin
21
+ activate_rails_version.call(rails_version)
22
+ rescue Gem::GemNotFoundException
23
+ abort "Suspenders error: Unable to find Rails version #{rails_version}"
24
+ end
25
+ else
26
+ require "suspenders/version"
27
+
28
+ spec = Gem::Specification.find_by_name("rails", Suspenders::RAILS_VERSION)
29
+
30
+ activate_rails_version.call(spec.version.to_s)
31
+ end
32
+ end
33
+
34
+ require "suspenders"
8
35
 
9
36
  if ARGV.empty?
10
37
  puts "Please provide a path for the new application"
11
38
  puts
12
39
  puts "See --help for more info"
13
40
  exit 0
14
- elsif ['-v', '--version'].include? ARGV[0]
41
+ elsif ["-v", "--version"].include? ARGV[0]
15
42
  puts Suspenders::VERSION
16
43
  exit 0
17
44
  end
@@ -0,0 +1,254 @@
1
+ require "parser/current"
2
+
3
+ module Suspenders
4
+ module Actions
5
+ class StripCommentsAction
6
+ class << self
7
+ def call(source)
8
+ parser = Parser::CurrentRuby.new
9
+
10
+ source
11
+ .then { |s| strip_comments(s, parser) }
12
+ .then { |s| strip_trailing_whitespace(s) }
13
+ .then { |s| strip_dup_newlines(s) }
14
+ .then { |s| strip_leading_scope_newlines(s, parser) }
15
+ end
16
+
17
+ private
18
+
19
+ def strip_comments(source, parser)
20
+ StripComments.call(source, parser.reset)
21
+ end
22
+
23
+ def strip_trailing_whitespace(source)
24
+ source.gsub(/[[:blank:]]+$/, "")
25
+ end
26
+
27
+ def strip_dup_newlines(source)
28
+ source.gsub(/\n{2,}/, "\n\n")
29
+ end
30
+
31
+ def strip_leading_scope_newlines(source, parser)
32
+ StripLeadingScopeNewlines.call(source, parser.reset)
33
+ end
34
+ end
35
+
36
+ # Strips full-line and inline comments from a buffer but does
37
+ # not remove whitespaces or newlines after the fact. Example
38
+ # input:
39
+ #
40
+ # MyGem.application.configure do |config|
41
+ # # Full-line comment
42
+ # config.option1 = :value # Inline comment
43
+ # end
44
+ #
45
+ # The output is:
46
+ #
47
+ # MyGem.application.configure do |config|
48
+ #
49
+ # config.option1 = :value
50
+ # end
51
+ class StripComments
52
+ class << self
53
+ def call(source, parser)
54
+ buffer = Parser::Source::Buffer.new(nil, source: source)
55
+ rewriter = Parser::Source::TreeRewriter.new(buffer)
56
+
57
+ _, comments = parser.parse_with_comments(buffer)
58
+
59
+ comments.each do |comment|
60
+ strip_comment(comment, buffer, rewriter)
61
+ end
62
+
63
+ rewriter.process
64
+ end
65
+
66
+ private
67
+
68
+ def strip_comment(comment, buffer, rewriter)
69
+ expr = comment.location.expression
70
+
71
+ if full_line_comment?(expr)
72
+ expr = full_line_comment_expr(expr, buffer)
73
+ end
74
+
75
+ rewriter.remove(expr)
76
+ end
77
+
78
+ def full_line_comment_expr(expr, buffer)
79
+ pos = BackwardStringScanner.beginning_of_line_pos(expr, expr.begin_pos)
80
+
81
+ Parser::Source::Range.new(buffer, pos, expr.end_pos + 1)
82
+ end
83
+
84
+ def full_line_comment?(expr)
85
+ expr.source == expr.source_line.lstrip
86
+ end
87
+ end
88
+ end
89
+
90
+ # A tiny, non-stateful backward string scanner somewhat inspired
91
+ # by Ruby's StringScanner. Ruby's StringScanner is unable to
92
+ # seek backward on a string.
93
+ class BackwardStringScanner
94
+ def self.beginning_of_line_pos(expr, initial_pos)
95
+ skip_before(expr, initial_pos) { |char| char == "\n" }
96
+ end
97
+
98
+ def self.skip_before(expr, initial_pos, &block)
99
+ skip_until(expr, initial_pos, -1, &block)
100
+ end
101
+
102
+ def self.skip_until(expr, initial_pos, lookup_inc = 0)
103
+ pos = initial_pos
104
+
105
+ loop do
106
+ break if pos.zero?
107
+ char = expr.source_buffer.source[pos + lookup_inc]
108
+ break if yield(char)
109
+ pos -= 1
110
+ end
111
+
112
+ pos
113
+ end
114
+ end
115
+
116
+ # The intent of this class is purely aesthetic: remove leading
117
+ # newlines inside of code scopes like blocks and begin/end.
118
+ # Example input:
119
+ #
120
+ # module MyGem
121
+ #
122
+ # MyGem.application.configure do |config|
123
+ #
124
+ # config.option1 = true
125
+ #
126
+ # config.option2 = false
127
+ # end
128
+ # end
129
+ #
130
+ # The output is:
131
+ #
132
+ # module MyGem
133
+ # MyGem.application.configure do |config|
134
+ # config.option1 = true
135
+ #
136
+ # config.option2 = false
137
+ # end
138
+ # end
139
+ class StripLeadingScopeNewlines
140
+ def self.call(source, parser)
141
+ buffer = Parser::Source::Buffer.new(nil, source: source)
142
+ ast = parser.parse(buffer)
143
+
144
+ LeadingNewlineStripRewriter.new.rewrite(buffer, ast).lstrip
145
+ end
146
+
147
+ class LeadingNewlineStripRewriter < Parser::TreeRewriter
148
+ def on_module(node)
149
+ strip_newline_before(node.children[1])
150
+ strip_newline_after(node.children.last)
151
+
152
+ super
153
+ end
154
+
155
+ def on_class(node)
156
+ strip_newline_before(node.children[2])
157
+ strip_newline_after(node.children.last)
158
+
159
+ super
160
+ end
161
+
162
+ def on_begin(node)
163
+ handle_begin(node)
164
+
165
+ super
166
+ end
167
+
168
+ def on_kwbegin(node)
169
+ strip_newline_before(node.children[0])
170
+ strip_newline_after(node.children.last)
171
+
172
+ handle_begin(node)
173
+
174
+ super
175
+ end
176
+
177
+ def on_block(node)
178
+ strip_newline_before(node.children[2])
179
+ strip_newline_after(node.children.last)
180
+
181
+ super
182
+ end
183
+
184
+ private
185
+
186
+ def handle_begin(node)
187
+ strip_blank_lines_between_setter_calls(node.children)
188
+
189
+ node.children.each do |child_node|
190
+ send("on_#{child_node.type}", child_node)
191
+ end
192
+ end
193
+
194
+ def strip_blank_lines_between_setter_calls(children)
195
+ pairs = children.each_cons(2).to_a
196
+
197
+ pairs.each do |(node_before, node_after)|
198
+ if setter_call?(node_before) && setter_call?(node_after)
199
+ strip_newline_before(node_after)
200
+ end
201
+ end
202
+ end
203
+
204
+ def setter_call?(node)
205
+ node.children[1].to_s.end_with?("=")
206
+ end
207
+
208
+ def strip_newline_before(node)
209
+ return if node.nil?
210
+
211
+ expr = node.location.expression
212
+ end_pos = find_end_pos(expr, expr.begin_pos)
213
+ begin_pos = find_begin_pos(expr, end_pos)
214
+
215
+ strip_source_range(expr, begin_pos, end_pos)
216
+ end
217
+
218
+ def strip_newline_after(node)
219
+ return if node.nil?
220
+
221
+ expr = node.location.expression
222
+ source = expr.source_buffer.source
223
+
224
+ if source[expr.end_pos + 1] == "\n"
225
+ strip_source_range(expr, expr.end_pos, expr.end_pos + 1)
226
+ end
227
+ end
228
+
229
+ def find_end_pos(expr, begin_pos)
230
+ BackwardStringScanner.skip_until(expr, begin_pos) do |char|
231
+ char == "\n"
232
+ end
233
+ end
234
+
235
+ def find_begin_pos(expr, end_pos)
236
+ BackwardStringScanner.skip_before(expr, end_pos) do |char|
237
+ char != "\n" && char != " "
238
+ end
239
+ end
240
+
241
+ def strip_source_range(expr, begin_pos, end_pos)
242
+ remove(
243
+ Parser::Source::Range.new(
244
+ expr.source_buffer,
245
+ begin_pos,
246
+ end_pos
247
+ )
248
+ )
249
+ end
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
@@ -6,7 +6,7 @@ module Suspenders
6
6
  unless contents.gsub!(find, replace)
7
7
  raise "#{find.inspect} not found in #{relative_path}"
8
8
  end
9
- File.open(path, "w") { |file| file.write(contents) }
9
+ File.write(path, contents)
10
10
  end
11
11
 
12
12
  def action_mailer_host(rails_env, host)
@@ -7,8 +7,8 @@ module Suspenders
7
7
 
8
8
  def set_heroku_remotes
9
9
  remotes = <<~SHELL
10
- #{command_to_join_heroku_app('staging')}
11
- #{command_to_join_heroku_app('production')}
10
+ #{command_to_join_heroku_app("staging")}
11
+ #{command_to_join_heroku_app("production")}
12
12
 
13
13
  git config heroku.remote staging
14
14
  SHELL
@@ -29,28 +29,28 @@ module Suspenders
29
29
  end
30
30
 
31
31
  def set_heroku_rails_secrets
32
- %w(staging production).each do |environment|
32
+ %w[staging production].each do |environment|
33
33
  run_toolbelt_command(
34
34
  "config:add SECRET_KEY_BASE=#{generate_secret}",
35
- environment,
35
+ environment
36
36
  )
37
37
  end
38
38
  end
39
39
 
40
40
  def set_heroku_honeybadger_env
41
- %w(staging production).each do |environment|
41
+ %w[staging production].each do |environment|
42
42
  run_toolbelt_command(
43
43
  "config:add HONEYBADGER_ENV=#{environment}",
44
- environment,
44
+ environment
45
45
  )
46
46
  end
47
47
  end
48
48
 
49
49
  def set_heroku_backup_schedule
50
- %w(staging production).each do |environment|
50
+ %w[staging production].each do |environment|
51
51
  run_toolbelt_command(
52
52
  "pg:backups:schedule DATABASE_URL --at '10:00 UTC'",
53
- environment,
53
+ environment
54
54
  )
55
55
  end
56
56
  end
@@ -65,34 +65,34 @@ module Suspenders
65
65
  run_toolbelt_command(
66
66
  "pipelines:create #{heroku_app_name} \
67
67
  -a #{heroku_app_name}-staging --stage staging",
68
- "staging",
68
+ "staging"
69
69
  )
70
70
 
71
71
  run_toolbelt_command(
72
72
  "pipelines:add #{heroku_app_name} \
73
73
  -a #{heroku_app_name}-production --stage production",
74
- "production",
74
+ "production"
75
75
  )
76
76
  end
77
77
 
78
78
  def set_heroku_application_host
79
- %w(staging production).each do |environment|
79
+ %w[staging production].each do |environment|
80
80
  run_toolbelt_command(
81
81
  "config:add APPLICATION_HOST=#{heroku_app_name}-#{environment}.herokuapp.com",
82
- environment,
82
+ environment
83
83
  )
84
84
  end
85
85
  end
86
86
 
87
87
  def set_heroku_buildpacks
88
- %w(staging production).each do |environment|
88
+ %w[staging production].each do |environment|
89
89
  run_toolbelt_command(
90
90
  "buildpacks:add --index 1 heroku/nodejs",
91
- environment,
91
+ environment
92
92
  )
93
93
  run_toolbelt_command(
94
94
  "buildpacks:add --index 2 heroku/ruby",
95
- environment,
95
+ environment
96
96
  )
97
97
  end
98
98
  end
@@ -128,7 +128,7 @@ module Suspenders
128
128
 
129
129
  def run_toolbelt_command(command, environment)
130
130
  app_builder.run(
131
- "heroku #{command} --remote #{environment}",
131
+ "heroku #{command} --remote #{environment}"
132
132
  )
133
133
  end
134
134
  end