heroku_hatchet 5.0.0 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
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'