heroku_hatchet 5.0.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +69 -0
  3. data/.gitignore +2 -0
  4. data/CHANGELOG.md +32 -1
  5. data/Gemfile +0 -1
  6. data/README.md +772 -205
  7. data/bin/hatchet +11 -4
  8. data/etc/ci_setup.rb +21 -15
  9. data/etc/setup_heroku.sh +0 -2
  10. data/hatchet.gemspec +4 -5
  11. data/hatchet.json +6 -2
  12. data/hatchet.lock +12 -8
  13. data/lib/hatchet.rb +1 -2
  14. data/lib/hatchet/api_rate_limit.rb +13 -24
  15. data/lib/hatchet/app.rb +159 -53
  16. data/lib/hatchet/config.rb +1 -1
  17. data/lib/hatchet/git_app.rb +27 -1
  18. data/lib/hatchet/reaper.rb +159 -56
  19. data/lib/hatchet/reaper/app_age.rb +49 -0
  20. data/lib/hatchet/reaper/reaper_throttle.rb +55 -0
  21. data/lib/hatchet/shell_throttle.rb +71 -0
  22. data/lib/hatchet/test_run.rb +16 -9
  23. data/lib/hatchet/version.rb +1 -1
  24. data/{test → repo_fixtures}/different-folder-for-checked-in-repos/default_ruby/Gemfile +0 -0
  25. data/spec/hatchet/allow_failure_git_spec.rb +40 -0
  26. data/spec/hatchet/app_spec.rb +226 -0
  27. data/spec/hatchet/ci_spec.rb +67 -0
  28. data/spec/hatchet/config_spec.rb +34 -0
  29. data/spec/hatchet/edit_repo_spec.rb +17 -0
  30. data/spec/hatchet/git_spec.rb +9 -0
  31. data/spec/hatchet/heroku_api_spec.rb +30 -0
  32. data/spec/hatchet/local_repo_spec.rb +26 -0
  33. data/spec/hatchet/lock_spec.rb +30 -0
  34. data/spec/spec_helper.rb +25 -0
  35. data/spec/unit/reaper_spec.rb +153 -0
  36. data/spec/unit/shell_throttle.rb +28 -0
  37. metadata +57 -86
  38. data/.travis.yml +0 -16
  39. data/test/fixtures/buildpacks/null-buildpack/bin/compile +0 -4
  40. data/test/fixtures/buildpacks/null-buildpack/bin/detect +0 -5
  41. data/test/fixtures/buildpacks/null-buildpack/bin/release +0 -3
  42. data/test/fixtures/buildpacks/null-buildpack/hatchet.json +0 -4
  43. data/test/fixtures/buildpacks/null-buildpack/readme.md +0 -41
  44. data/test/hatchet/allow_failure_git_test.rb +0 -16
  45. data/test/hatchet/app_test.rb +0 -96
  46. data/test/hatchet/ci_four_test.rb +0 -19
  47. data/test/hatchet/ci_test.rb +0 -11
  48. data/test/hatchet/ci_three_test.rb +0 -9
  49. data/test/hatchet/ci_too_test.rb +0 -19
  50. data/test/hatchet/config_test.rb +0 -51
  51. data/test/hatchet/edit_repo_test.rb +0 -20
  52. data/test/hatchet/git_test.rb +0 -16
  53. data/test/hatchet/heroku_api_test.rb +0 -30
  54. data/test/hatchet/labs_test.rb +0 -20
  55. data/test/hatchet/local_repo_test.rb +0 -26
  56. data/test/hatchet/lock_test.rb +0 -9
  57. data/test/hatchet/multi_cmd_runner_test.rb +0 -30
  58. data/test/test_helper.rb +0 -28
@@ -46,7 +46,7 @@ class HatchetCLI < Thor
46
46
  Threaded.later do
47
47
  commit = lock_hash[directory]
48
48
  directory = File.expand_path(directory)
49
- if Dir[directory].present?
49
+ if !Dir[directory]&.empty?
50
50
  puts "== pulling '#{git_repo}' into '#{directory}'\n"
51
51
  pull(directory, git_repo)
52
52
  else
@@ -67,6 +67,7 @@ class HatchetCLI < Thor
67
67
  desc "locks to specific git commits", "updates hatchet.lock"
68
68
  def lock
69
69
  lock_hash = {}
70
+ lockfile_hash = load_lockfile
70
71
  dirs.map do |directory, git_repo|
71
72
  Threaded.later do
72
73
  puts "== locking #{directory}"
@@ -75,8 +76,14 @@ class HatchetCLI < Thor
75
76
  clone(directory, git_repo, quiet: false)
76
77
  end
77
78
 
78
- commit = commit_at_directory(directory)
79
- lock_hash[directory] = commit
79
+ if lockfile_hash[directory] == "master"
80
+ lock_hash[directory] = "master"
81
+ elsif lockfile_hash[directory] == "main"
82
+ lock_hash[directory] = "main"
83
+ else
84
+ commit = commit_at_directory(directory)
85
+ lock_hash[directory] = commit
86
+ end
80
87
  end
81
88
  end.map(&:join)
82
89
 
@@ -152,7 +159,7 @@ class HatchetCLI < Thor
152
159
  end
153
160
 
154
161
  def pull(path, git_repo, commit: false)
155
- cmd("cd #{path} && git pull --rebase #{git_repo} master --quiet")
162
+ cmd("cd #{path} && git pull --rebase #{git_repo} --quiet")
156
163
  end
157
164
 
158
165
  def clone(path, git_repo, quiet: true)
@@ -1,6 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
- require 'bundler'
3
2
  require 'shellwords'
3
+
4
+ STDOUT.sync = true
5
+
6
+ def run_cmd(command)
7
+ puts "== Running: #{command}"
8
+ result = `#{command}`
9
+ raise "Command failed: #{command.inspect}\nResult: #{result}" unless $?.success?
10
+ end
11
+
4
12
  puts "== Setting Up CI =="
5
13
 
6
14
  netrc_file = "#{ENV['HOME']}/.netrc"
@@ -8,22 +16,20 @@ unless File.exists?(netrc_file)
8
16
  File.open(netrc_file, 'w') do |file|
9
17
  file.write <<-EOF
10
18
  machine git.heroku.com
11
- login #{ENV.fetch('HEROKU_API_USER')}
12
- password #{ENV.fetch('HEROKU_API_KEY')}
19
+ login #{ENV.fetch('HEROKU_API_USER')}
20
+ password #{ENV.fetch('HEROKU_API_KEY')}
21
+ machine api.heroku.com
22
+ login #{ENV.fetch('HEROKU_API_USER')}
23
+ password #{ENV.fetch('HEROKU_API_KEY')}
13
24
  EOF
25
+ run_cmd 'chmod 0600 "$HOME/.netrc"'
14
26
  end
15
27
  end
16
28
 
17
- [
18
- "bundle exec hatchet ci:install_heroku",
19
- "bundle exec hatchet install",
20
- "git config --get user.email > /dev/null || git config --global user.email #{ENV.fetch('HEROKU_API_USER').shellescape}",
21
- "git config --get user.name > /dev/null || git config --global user.name 'BuildpackTester'",
22
- ].each do |command|
23
- puts "== Running: #{command}"
24
- Bundler.with_clean_env do
25
- result = `#{command}`
26
- raise "Command failed: #{command.inspect}\nResult: #{result}" unless $?.success?
27
- end
28
- end
29
+ run_cmd "bundle exec hatchet ci:install_heroku"
30
+ run_cmd "bundle exec hatchet install"
31
+ run_cmd "git config --get user.email > /dev/null || git config --global user.email #{ENV.fetch('HEROKU_API_USER').shellescape}"
32
+ run_cmd "git config --get user.name > /dev/null || git config --global user.name 'BuildpackTester'"
33
+
29
34
  puts "== Done =="
35
+
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
3
  set -euo pipefail
4
- sudo apt-get -qq update
5
- sudo apt-get install software-properties-common
6
4
  curl --fail --retry 3 --retry-delay 1 --connect-timeout 3 --max-time 30 https://cli-assets.heroku.com/install-ubuntu.sh | sh
@@ -18,17 +18,16 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.require_paths = ["lib"]
20
20
 
21
- gem.add_dependency "platform-api", "~> 2"
21
+ gem.add_dependency "platform-api", "~> 3"
22
22
  gem.add_dependency "rrrretry", "~> 1"
23
23
  gem.add_dependency "excon", "~> 0"
24
24
  gem.add_dependency "thor", "~> 0"
25
- gem.add_dependency "repl_runner", "~> 0.0.3"
26
25
  gem.add_dependency "threaded", "~> 0"
27
- gem.add_dependency 'minitest-retry', '~> 0.1.9'
28
26
 
29
- gem.add_development_dependency "minitest", ">= 5.1"
27
+ gem.add_development_dependency "rspec"
30
28
  gem.add_development_dependency "rake", ">= 10"
31
29
  gem.add_development_dependency "mocha", ">= 1"
32
- gem.add_development_dependency "parallel_tests", ">= 2"
30
+ gem.add_development_dependency "parallel_split_test"
33
31
  gem.add_development_dependency "travis", ">= 1"
32
+ gem.add_development_dependency "rspec-retry"
34
33
  end
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "hatchet": {
3
- "directory": "test/fixtures"
3
+ "directory": "repo_fixtures"
4
4
  },
5
5
  "rails3": ["sharpstone/rails3_mri_193"],
6
6
  "rails2": ["sharpstone/rails2blog"],
@@ -10,5 +10,9 @@
10
10
  "sharpstone/rails5_ruby_schema_format",
11
11
  "sharpstone/rails5_ci_fails_no_database"
12
12
  ],
13
- "lock": ["sharpstone/lock_fail"]
13
+ "lock": [
14
+ "sharpstone/lock_fail",
15
+ "sharpstone/lock_fail_master",
16
+ "sharpstone/lock_fail_main"
17
+ ]
14
18
  }
@@ -1,15 +1,19 @@
1
1
  ---
2
- - - test/fixtures/repos/bundler/no_lockfile
2
+ - - repo_fixtures/repos/bundler/no_lockfile
3
3
  - 1947ce9a9c276d5df1c323b2ad78d1d85c7ab4c0
4
- - - test/fixtures/repos/ci/rails5_ci_fails_no_database
4
+ - - repo_fixtures/repos/ci/rails5_ci_fails_no_database
5
5
  - 3044f05febdfbbe656f0f5113cf5968ca07e34fd
6
- - - test/fixtures/repos/ci/rails5_ruby_schema_format
7
- - 3e63c3e13f435cf4ab11265e9abd161cc28cc552
8
- - - test/fixtures/repos/default/default_ruby
6
+ - - repo_fixtures/repos/ci/rails5_ruby_schema_format
7
+ - d76be86c66ae8f45ec611fb2c4d8eb3adac0ad4b
8
+ - - repo_fixtures/repos/default/default_ruby
9
9
  - 6e642963acec0ff64af51bd6fba8db3c4176ed6e
10
- - - test/fixtures/repos/lock/lock_fail
10
+ - - repo_fixtures/repos/lock/lock_fail
11
11
  - da748a59340be8b950e7bbbfb32077eb67d70c3c
12
- - - test/fixtures/repos/rails2/rails2blog
12
+ - - repo_fixtures/repos/lock/lock_fail_main
13
+ - main
14
+ - - repo_fixtures/repos/lock/lock_fail_master
15
+ - master
16
+ - - repo_fixtures/repos/rails2/rails2blog
13
17
  - b37357a498ae5e8429f5601c5ab9524021dc2aaa
14
- - - test/fixtures/repos/rails3/rails3_mri_193
18
+ - - repo_fixtures/repos/rails3/rails3_mri_193
15
19
  - 88c5d0d067cfd11e4452633994a85b04627ae8c7
@@ -1,4 +1,3 @@
1
- require 'active_support/core_ext/object/blank'
2
1
  require 'rrrretry'
3
2
 
4
3
  require 'json'
@@ -8,7 +7,7 @@ require 'stringio'
8
7
  require 'date'
9
8
 
10
9
  module Hatchet
11
- APP_PREFIX = (ENV['HATCHET_APP_PREFIX'] || "hatchet-t-")
10
+ APP_PREFIX = (ENV['HATCHET_APP_PREFIX'] || "hatchet-t-")
12
11
  end
13
12
 
14
13
  require 'hatchet/version'
@@ -1,14 +1,11 @@
1
- # Wraps platform-api and adds API rate limits
1
+ # Legacy class
2
2
  #
3
- # Instead of:
4
- #
5
- # platform_api.pipeline.create(name: @name)
6
- #
7
- # Use:
8
- #
9
- # api_rate_limit = ApiRateLimit.new(platform_api)
10
- # api_rate_limit.call.pipeline.create(name: @name)
3
+ # Not needed since rate throttling went directly into the platform-api gem.
4
+ # This class is effectively now a no-op
11
5
  #
6
+ # It's being left in as it's interface was public and it's hard-ish to
7
+ # deprecate/remove. Since it's so small there's not much value in removal
8
+ # so it's probably fine to keep around for quite some time.
12
9
  class ApiRateLimit
13
10
  def initialize(platform_api)
14
11
  @platform_api = platform_api
@@ -16,24 +13,16 @@ class ApiRateLimit
16
13
  @called = 0
17
14
  end
18
15
 
19
-
20
- # Sleeps for progressively longer when api rate limit capacity
21
- # is lower.
22
- #
23
- # Unfortunatley `@platform_api.rate_limit` is an extra API
24
- # call, so by checking our limit, we also are using our limit 😬
25
- # to partially mitigate this, only check capacity every 5
26
- # api calls, or if the current capacity is under 1000
27
16
  def call
28
- @called += 1
17
+ # @called += 1
29
18
 
30
- if @called > 5 || @capacity < 1000
31
- @called = 0
32
- @capacity = @platform_api.rate_limit.info["remaining"]
33
- end
19
+ # if @called > 5 || @capacity < 1000
20
+ # @called = 0
21
+ # @capacity = @platform_api.rate_limit.info["remaining"]
22
+ # end
34
23
 
35
- sleep_time = (60/@capacity) if @capacity > 0.1 # no divide by zero
36
- sleep(sleep_time || 60)
24
+ # sleep_time = (60/@capacity) if @capacity > 0.1 # no divide by zero
25
+ # sleep(sleep_time || 60)
37
26
 
38
27
  return @platform_api
39
28
  end
@@ -9,14 +9,34 @@ module Hatchet
9
9
  HATCHET_BUILDPACK_BRANCH = -> { ENV['HATCHET_BUILDPACK_BRANCH'] || ENV['HEROKU_TEST_RUN_BRANCH'] || Hatchet.git_branch }
10
10
  BUILDPACK_URL = "https://github.com/heroku/heroku-buildpack-ruby.git"
11
11
 
12
- attr_reader :name, :stack, :directory, :repo_name, :app_config, :buildpacks
13
-
14
- class FailedDeploy < StandardError
15
- def initialize(app, output)
16
- msg = "Could not deploy '#{app.name}' (#{app.repo_name}) using '#{app.class}' at path: '#{app.directory}'\n" <<
17
- " if this was expected add `allow_failure: true` to your deploy hash.\n" <<
18
- "output:\n" <<
19
- "#{output}"
12
+ attr_reader :name, :stack, :directory, :repo_name, :app_config, :buildpacks, :reaper
13
+
14
+ class FailedDeploy < StandardError; end
15
+
16
+ class FailedDeployError < FailedDeploy
17
+ attr_reader :output
18
+
19
+ def initialize(app, message, output: )
20
+ @output = output
21
+ msg = "Could not deploy '#{app.name}' (#{app.repo_name}) using '#{app.class}' at path: '#{app.directory}'\n"
22
+ msg << "if this was expected add `allow_failure: true` to your deploy hash.\n"
23
+ msg << "#{message}\n"
24
+ msg << "output:\n"
25
+ msg << "#{output}"
26
+ super(msg)
27
+ end
28
+ end
29
+
30
+ class FailedReleaseError < FailedDeploy
31
+ attr_reader :output
32
+
33
+ def initialize(app, message, output: )
34
+ @output = output
35
+ msg = "Could not release '#{app.name}' (#{app.repo_name}) using '#{app.class}' at path: '#{app.directory}'\n"
36
+ msg << "if this was expected add `allow_failure: true` to your deploy hash.\n"
37
+ msg << "#{message}\n"
38
+ msg << "output:\n"
39
+ msg << "#{output}"
20
40
  super(msg)
21
41
  end
22
42
  end
@@ -34,6 +54,7 @@ module Hatchet
34
54
  buildpacks: nil,
35
55
  buildpack_url: nil,
36
56
  before_deploy: nil,
57
+ run_multi: ENV["HATCHET_RUN_MULTI"],
37
58
  config: {}
38
59
  )
39
60
  @repo_name = repo_name
@@ -46,6 +67,12 @@ module Hatchet
46
67
  @buildpacks = buildpack || buildpacks || buildpack_url || self.class.default_buildpack
47
68
  @buildpacks = Array(@buildpacks)
48
69
  @buildpacks.map! {|b| b == :default ? self.class.default_buildpack : b}
70
+ @run_multi = run_multi
71
+
72
+ if run_multi && !ENV["HATCHET_EXPENSIVE_MODE"]
73
+ raise "You're attempting to enable `run_multi: true` mode, but have not enabled `HATCHET_EXPENSIVE_MODE=1` env var to verify you understand the risks"
74
+ end
75
+ @run_multi_array = []
49
76
  @already_in_dir = nil
50
77
  @app_is_setup = nil
51
78
 
@@ -127,6 +154,22 @@ module Hatchet
127
154
  else
128
155
  command = command.to_s
129
156
  end
157
+
158
+ heroku_command = build_heroku_command(command, options)
159
+
160
+ allow_run_multi! if @run_multi
161
+
162
+ output = ""
163
+
164
+ ShellThrottle.new(platform_api: @platform_api).call do |throttle|
165
+ output = `#{heroku_command}`
166
+ throw(:throttle) if output.match?(/reached the API rate limit/)
167
+ end
168
+
169
+ return output
170
+ end
171
+
172
+ private def build_heroku_command(command, options = {})
130
173
  command = command.shellescape unless options.delete(:raw)
131
174
 
132
175
  default_options = { "app" => name, "exit-code" => nil }
@@ -136,16 +179,77 @@ module Hatchet
136
179
  arg << "=#{v.to_s.shellescape}" unless v.nil? # nil means we include the option without an argument
137
180
  arg
138
181
  end.join(" ")
139
- heroku_command = "heroku run #{heroku_options} -- #{command}"
140
182
 
141
- if block_given?
142
- STDERR.puts "Using App#run with a block is deprecated, support for ReplRunner is being removed.\n#{caller}"
143
- # When we deprecated this we can get rid of the "cmd_type" from the method signature
144
- require 'repl_runner'
145
- ReplRunner.new(cmd_type, heroku_command, options).run(&block)
146
- else
147
- `#{heroku_command}`
183
+ "heroku run #{heroku_options} -- #{command}"
184
+ end
185
+
186
+ private def allow_run_multi!
187
+ raise "Must explicitly enable the `run_multi: true` option. This requires scaling up a dyno and is not free, it may incur charges on your account" unless @run_multi
188
+
189
+ @run_multi_is_setup ||= platform_api.formation.update(name, "web", {"size" => "Standard-1X"})
190
+ end
191
+
192
+
193
+ # Allows multiple commands to be run concurrently in the background.
194
+ #
195
+ # WARNING! Using the feature requres that the underlying app is not on the "free" Heroku
196
+ # tier. This requires scaling up the dyno which is not free. If an app is
197
+ # scaled up and left in that state it can incur large costs.
198
+ #
199
+ # Enabling this feature should be done with extreme caution.
200
+ #
201
+ # Example:
202
+ #
203
+ # Hatchet::Runner.new("default_ruby", run_multi: true)
204
+ # app.run_multi("ls") { |out| expect(out).to include("Gemfile") }
205
+ # app.run_multi("ruby -v") { |out| expect(out).to include("ruby") }
206
+ # end
207
+ #
208
+ # This example will run `heroku run ls` as well as `ruby -v` at the same time in the background.
209
+ # The return result will be yielded to the block after they finish running.
210
+ #
211
+ # Order of execution is not guaranteed.
212
+ #
213
+ # If you need to assert a command was successful, you can yield a second status object like this:
214
+ #
215
+ # Hatchet::Runner.new("default_ruby", run_multi: true)
216
+ # app.run_multi("ls") do |out, status|
217
+ # expect(status.success?).to be_truthy
218
+ # expect(out).to include("Gemfile")
219
+ # end
220
+ # app.run_multi("ruby -v") do |out, status|
221
+ # expect(status.success?).to be_truthy
222
+ # expect(out).to include("ruby")
223
+ # end
224
+ # end
225
+ def run_multi(command, options = {}, &block)
226
+ raise "Block required" if block.nil?
227
+ allow_run_multi!
228
+
229
+ run_thread = Thread.new do
230
+ heroku_command = build_heroku_command(command, options)
231
+
232
+ out = nil
233
+ status = nil
234
+ ShellThrottle.new(platform_api: @platform_api).call do |throttle|
235
+ out = `#{heroku_command}`
236
+ throw(:throttle) if output.match?(/reached the API rate limit/)
237
+ status = $?
238
+ end
239
+
240
+ yield out, status
241
+
242
+ # if block.arity == 1
243
+ # block.call(out)
244
+ # else
245
+ # block.call(out, status)
246
+ # end
148
247
  end
248
+ run_thread.abort_on_exception = true
249
+
250
+ @run_multi_array << run_thread
251
+
252
+ true
149
253
  end
150
254
 
151
255
  # set debug: true when creating app if you don't want it to be
@@ -162,24 +266,26 @@ module Hatchet
162
266
  alias :no_debug? :not_debugging?
163
267
 
164
268
  def deployed?
165
- # !heroku.get_ps(name).body.detect {|ps| ps["process"].include?("web") }.nil?
166
269
  api_rate_limit.call.formation.list(name).detect {|ps| ps["type"] == "web"}
167
270
  end
168
271
 
169
272
  def create_app
170
273
  3.times.retry do
171
274
  begin
172
- # heroku.post_app({ name: name, stack: stack }.delete_if {|k,v| v.nil? })
173
275
  hash = { name: name, stack: stack }
174
276
  hash.delete_if { |k,v| v.nil? }
175
- api_rate_limit.call.app.create(hash)
277
+ heroku_api_create_app(hash)
176
278
  rescue => e
177
- @reaper.cycle
279
+ @reaper.cycle(app_exception_message: e.message)
178
280
  raise e
179
281
  end
180
282
  end
181
283
  end
182
284
 
285
+ private def heroku_api_create_app(hash)
286
+ api_rate_limit.call.app.create(hash)
287
+ end
288
+
183
289
  def update_stack(stack_name)
184
290
  @stack = stack_name
185
291
  api_rate_limit.call.app.update(name, build_stack: @stack)
@@ -219,11 +325,15 @@ module Hatchet
219
325
 
220
326
  def teardown!
221
327
  return false unless @app_is_setup
222
- if debugging?
223
- puts "Debugging App:#{name}"
224
- return false
328
+
329
+ if @run_multi_is_setup
330
+ @run_multi_array.map(&:join)
331
+ platform_api.formation.update(name, "web", {"size" => "free"})
225
332
  end
226
- @reaper.cycle
333
+
334
+ ensure
335
+ @app_update_info = platform_api.app.update(name, { maintenance: true }) if @app_is_setup
336
+ @reaper.cycle if @app_is_setup
227
337
  end
228
338
 
229
339
  def in_directory(directory = self.directory)
@@ -265,10 +375,6 @@ module Hatchet
265
375
  end
266
376
  end
267
377
 
268
- # creates a new app on heroku, "pushes" via anvil or git
269
- # then yields to self so you can call self.run or
270
- # self.deployed?
271
- # Allow deploy failures on CI server by setting ENV['HATCHET_RETRIES']
272
378
  def deploy(&block)
273
379
  in_directory do
274
380
  self.setup!
@@ -276,7 +382,7 @@ module Hatchet
276
382
  block.call(self, api_rate_limit.call, output) if block_given?
277
383
  end
278
384
  ensure
279
- self.teardown!
385
+ self.teardown! if block_given?
280
386
  end
281
387
 
282
388
  def push
@@ -315,31 +421,30 @@ module Hatchet
315
421
  end
316
422
 
317
423
  def run_ci(timeout: 300, &block)
318
- Hatchet::RETRIES.times.retry do
319
- result = create_pipeline
320
- @pipeline_id = result["id"]
321
- end
424
+ in_directory do
425
+ Hatchet::RETRIES.times.retry do
426
+ result = create_pipeline
427
+ @pipeline_id = result["id"]
428
+ end
322
429
 
323
- # when the CI run finishes, the associated ephemeral app created for the test run internally gets removed almost immediately
324
- # the system then sees a pipeline with no apps, and deletes it, also almost immediately
325
- # that would, with bad timing, mean our test run info poll in wait! would 403, and/or the delete_pipeline at the end
326
- # that's why we create an app explictly (or maybe it already exists), and then associate it with with the pipeline
327
- # the app will be auto cleaned up later
328
- self.setup!
329
- Hatchet::RETRIES.times.retry do
330
- couple_pipeline(@name, @pipeline_id)
331
- end
430
+ # when the CI run finishes, the associated ephemeral app created for the test run internally gets removed almost immediately
431
+ # the system then sees a pipeline with no apps, and deletes it, also almost immediately
432
+ # that would, with bad timing, mean our test run info poll in wait! would 403, and/or the delete_pipeline at the end
433
+ # that's why we create an app explictly (or maybe it already exists), and then associate it with with the pipeline
434
+ # the app will be auto cleaned up later
435
+ self.setup!
436
+ Hatchet::RETRIES.times.retry do
437
+ couple_pipeline(@name, @pipeline_id)
438
+ end
332
439
 
333
- test_run = TestRun.new(
334
- token: api_key,
335
- buildpacks: @buildpacks,
336
- timeout: timeout,
337
- app: self,
338
- pipeline: @pipeline_id,
339
- api_rate_limit: api_rate_limit
340
- )
341
- in_directory do
342
- call_before_deploy
440
+ test_run = TestRun.new(
441
+ token: api_key,
442
+ buildpacks: @buildpacks,
443
+ timeout: timeout,
444
+ app: self,
445
+ pipeline: @pipeline_id,
446
+ api_rate_limit: api_rate_limit
447
+ )
343
448
 
344
449
  Hatchet::RETRIES.times.retry do
345
450
  test_run.create_test_run
@@ -347,6 +452,7 @@ module Hatchet
347
452
  test_run.wait!(&block)
348
453
  end
349
454
  ensure
455
+ teardown! if block_given?
350
456
  delete_pipeline(@pipeline_id) if @pipeline_id
351
457
  @pipeline_id = nil
352
458
  end
@@ -382,7 +488,6 @@ module Hatchet
382
488
  end
383
489
 
384
490
  def platform_api
385
- puts "Deprecated: use `api_rate_limit.call` instead of platform_api"
386
491
  api_rate_limit
387
492
  return @platform_api
388
493
  end
@@ -434,3 +539,4 @@ module Hatchet
434
539
  end
435
540
  end
436
541
 
542
+ require_relative 'shell_throttle.rb'