heroku_hatchet 5.0.3 → 7.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +21 -1
  3. data/.gitignore +2 -0
  4. data/CHANGELOG.md +36 -1
  5. data/README.md +774 -174
  6. data/bin/hatchet +13 -6
  7. data/etc/ci_setup.rb +16 -12
  8. data/etc/setup_heroku.sh +0 -2
  9. data/hatchet.gemspec +4 -6
  10. data/hatchet.json +3 -2
  11. data/hatchet.lock +11 -9
  12. data/lib/hatchet.rb +1 -2
  13. data/lib/hatchet/api_rate_limit.rb +13 -24
  14. data/lib/hatchet/app.rb +150 -41
  15. data/lib/hatchet/config.rb +1 -1
  16. data/lib/hatchet/git_app.rb +29 -2
  17. data/lib/hatchet/reaper.rb +159 -56
  18. data/lib/hatchet/reaper/app_age.rb +49 -0
  19. data/lib/hatchet/reaper/reaper_throttle.rb +55 -0
  20. data/lib/hatchet/shell_throttle.rb +71 -0
  21. data/lib/hatchet/test_run.rb +16 -9
  22. data/lib/hatchet/version.rb +1 -1
  23. data/{test → repo_fixtures}/different-folder-for-checked-in-repos/default_ruby/Gemfile +0 -0
  24. data/spec/hatchet/allow_failure_git_spec.rb +55 -0
  25. data/spec/hatchet/app_spec.rb +226 -0
  26. data/spec/hatchet/ci_spec.rb +67 -0
  27. data/spec/hatchet/config_spec.rb +34 -0
  28. data/spec/hatchet/edit_repo_spec.rb +17 -0
  29. data/spec/hatchet/git_spec.rb +9 -0
  30. data/spec/hatchet/heroku_api_spec.rb +30 -0
  31. data/spec/hatchet/local_repo_spec.rb +26 -0
  32. data/spec/hatchet/lock_spec.rb +81 -0
  33. data/spec/spec_helper.rb +25 -0
  34. data/spec/unit/reaper_spec.rb +169 -0
  35. data/spec/unit/shell_throttle.rb +28 -0
  36. metadata +43 -86
  37. data/test/fixtures/buildpacks/null-buildpack/bin/compile +0 -4
  38. data/test/fixtures/buildpacks/null-buildpack/bin/detect +0 -5
  39. data/test/fixtures/buildpacks/null-buildpack/bin/release +0 -3
  40. data/test/fixtures/buildpacks/null-buildpack/hatchet.json +0 -4
  41. data/test/fixtures/buildpacks/null-buildpack/readme.md +0 -41
  42. data/test/hatchet/allow_failure_git_test.rb +0 -16
  43. data/test/hatchet/app_test.rb +0 -96
  44. data/test/hatchet/ci_four_test.rb +0 -19
  45. data/test/hatchet/ci_test.rb +0 -11
  46. data/test/hatchet/ci_three_test.rb +0 -20
  47. data/test/hatchet/ci_too_test.rb +0 -19
  48. data/test/hatchet/config_test.rb +0 -51
  49. data/test/hatchet/edit_repo_test.rb +0 -20
  50. data/test/hatchet/git_test.rb +0 -16
  51. data/test/hatchet/heroku_api_test.rb +0 -30
  52. data/test/hatchet/labs_test.rb +0 -20
  53. data/test/hatchet/local_repo_test.rb +0 -26
  54. data/test/hatchet/lock_test.rb +0 -18
  55. data/test/hatchet/multi_cmd_runner_test.rb +0 -30
  56. data/test/test_helper.rb +0 -28
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env bash
2
- # bin/compile <build-dir> <cache-dir>
3
-
4
- echo "-----> Nothing to do."
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env bash
2
- # bin/detect <build-dir>
3
-
4
- echo "Null"
5
- exit 0
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- echo "--- {}"
@@ -1,4 +0,0 @@
1
- {
2
- "hatchet": {"directory": "../.."},
3
- "rails3": ["sharpstone/rails3_mri_193"]
4
- }
@@ -1,41 +0,0 @@
1
- # Heroku Buildpack: Ø
2
-
3
- Use Ø if you need Heroku to execute a binary.
4
-
5
- ## Usage
6
-
7
- Create a directory for our Heroku app:
8
-
9
- ```bash
10
- $ mkdir -p myapp/bin
11
- $ cd myapp
12
- ```
13
-
14
- Here is an example of an executable that will run on 64bit linux machine:
15
-
16
- ```bash
17
- $ echo -e "#\!/usr/bin/env bash\n echo hello world" > ./bin/program
18
- $ echo -e "program: bin/program" > Procfile
19
- $ chmod +x ./bin/program
20
- $ ./bin/program
21
- hello world
22
- ```
23
-
24
- Push the app to Heroku and run our executable:
25
-
26
- ```bash
27
- $ git init; git add .; git commit -am 'init'
28
- $ heroku create --buildpack http://github.com/ryandotsmith/null-buildpack.git
29
- $ git push heroku master
30
- $ heroku run program
31
- Running `program` attached to terminal... up, run.8663
32
- hello world
33
- ```
34
-
35
- ## Motivation
36
-
37
- I wanted to run various executables (e.g. [log-shuttle](https://github.com/ryandotsmith/log-shuttle)) on Heroku without compiling them on Heroku. Thus, I compile programs on my linux 64 machine, or fetch the binary from the project, commit them to a repo and then run them on Heroku with the Ø buildpack.
38
-
39
- ## Issues
40
-
41
- You will need to make sure that a 64bit linux machine can execute the binary.
@@ -1,16 +0,0 @@
1
- require 'test_helper'
2
-
3
- class AllowFailureGitTest < Minitest::Test
4
- def test_allowed_failure
5
- Hatchet::GitApp.new("no_lockfile", allow_failure: true).deploy do |app|
6
- refute app.deployed?
7
- assert_match "Gemfile.lock required", app.output
8
- end
9
- end
10
-
11
- def test_failure_with_no_flag
12
- assert_raise(Hatchet::App::FailedDeploy) do
13
- Hatchet::GitApp.new("no_lockfile").deploy
14
- end
15
- end
16
- end
@@ -1,96 +0,0 @@
1
- require 'test_helper'
2
-
3
- class AppTest < Minitest::Test
4
- def test_app_with_default
5
- app = Hatchet::App.new("default_ruby", buildpacks: [:default])
6
- assert_match "https://github.com/heroku/heroku-buildpack-ruby", app.buildpacks.first
7
- end
8
-
9
- def test_create_app_with_stack
10
- stack = "heroku-16"
11
- app = Hatchet::App.new("default_ruby", stack: stack)
12
- app.create_app
13
- assert_equal stack, app.platform_api.app.info(app.name)["build_stack"]["name"]
14
- end
15
-
16
- def test_before_deploy
17
- @called = false
18
- @dir = false
19
-
20
- app = Hatchet::App.new("default_ruby")
21
- def app.push_with_retry!; end # Don't actually deploy
22
-
23
- app.before_deploy do
24
- @called = true
25
- @dir = Dir.pwd
26
- end
27
-
28
- app.deploy do
29
- assert_equal true, @called
30
- assert_equal Dir.pwd, @dir
31
- end
32
-
33
- refute_equal Dir.pwd, @dir
34
- end
35
-
36
- def test_auto_commits_code
37
- string = "foo#{SecureRandom.hex}"
38
-
39
- app = Hatchet::App.new("default_ruby")
40
- def app.push_with_retry!; end # Don't actually deploy
41
-
42
- app.before_deploy do |app|
43
- assert_equal false, app.send(:needs_commit?)
44
- `echo "#{string}" > Gemfile`
45
- assert_equal true, app.send(:needs_commit?)
46
- end
47
- app.deploy do
48
- assert_equal string, File.read("Gemfile").chomp
49
- assert_equal false, app.send(:needs_commit?)
50
- end
51
- end
52
-
53
-
54
- def test_nested_in_directory
55
- string = "foo#{SecureRandom.hex}"
56
-
57
- app = Hatchet::App.new("default_ruby")
58
- def app.push_with_retry!; end # Don't actually deploy
59
-
60
- app.in_directory do
61
- `echo "#{string}" > Gemfile`
62
- dir = Dir.pwd
63
-
64
- app.deploy do
65
- assert_equal string, File.read("Gemfile").chomp
66
- assert_equal Dir.pwd, dir
67
- end
68
- end
69
- end
70
-
71
- def test_run
72
- app = Hatchet::GitApp.new("default_ruby")
73
- app.deploy do
74
- assert_match(/ls: cannot access 'foo bar #baz': No such file or directory\s+Gemfile/, app.run("ls -a Gemfile 'foo bar #baz'"))
75
- assert (0 != $?.exitstatus) # $? is from the app.run use of backticks
76
- sleep(4) # Dynos don't exit right away and free dynos can't have more than one running at a time, wait before calling `run` again
77
-
78
- app.run("ls erpderp", { :heroku => { "exit-code" => Hatchet::App::SkipDefaultOption } } )
79
- assert (0 == $?.exitstatus) # $? is from the app.run use of backticks, but we asked the CLI not to return the program exit status by skipping the default "exit-code" option
80
- sleep(4)
81
-
82
- app.run("ls erpderp", { :heroku => { "no-tty" => nil } } )
83
- assert (0 != $?.exitstatus) # $? is from the app.run use of backticks
84
- sleep(4)
85
-
86
- assert_match(/ohai world/, app.run('echo \$HELLO \$NAME', { raw: true, :heroku => { "env" => "HELLO=ohai;NAME=world" } } ))
87
- sleep(4)
88
-
89
- refute_match(/ohai world/, app.run('echo \$HELLO \$NAME', { raw: true, :heroku => { "env" => "" } } ))
90
- sleep(4)
91
-
92
- random_name = SecureRandom.hex
93
- assert_match(/#{random_name}/, app.run("mkdir foo; touch foo/#{random_name}; ls foo/"))
94
- end
95
- end
96
- end
@@ -1,19 +0,0 @@
1
- require 'test_helper'
2
-
3
- class CIFourTest < Minitest::Test
4
- def test_error_with_bad_app
5
- string = SecureRandom.hex
6
- Hatchet::GitApp.new("default_ruby").run_ci do |test_run|
7
- refute_match(string, test_run.output)
8
- assert_match("Installing rake" , test_run.output)
9
-
10
- run!(%Q{echo 'puts "#{string}"' >> Rakefile})
11
- test_run.run_again
12
-
13
- assert_match(string, test_run.output)
14
- assert_match("Using rake" , test_run.output)
15
-
16
- refute_match("Installing rake" , test_run.output)
17
- end
18
- end
19
- end
@@ -1,11 +0,0 @@
1
- require 'test_helper'
2
-
3
- class CITest < Minitest::Test
4
- def test_error_with_bad_app
5
- error = assert_raise(Hatchet::FailedTestError) do
6
- Hatchet::GitApp.new("rails5_ci_fails_no_database").run_ci {}
7
- end
8
-
9
- assert_match "PG::ConnectionBad: could not connect to server", error.message
10
- end
11
- end
@@ -1,20 +0,0 @@
1
- require 'test_helper'
2
-
3
- class CIThreeTest < Minitest::Test
4
- def test_error_with_bad_app
5
- @before_deploy_called = false
6
- @before_deploy_dir_pwd = nil
7
- before_deploy = -> {
8
- @before_deploy_called = true
9
- @before_deploy_dir_pwd = Dir.pwd
10
- }
11
- Hatchet::GitApp.new("rails5_ci_fails_no_database", allow_failure: true, before_deploy: before_deploy).run_ci do |test_run|
12
- assert_equal :errored, test_run.status
13
- assert_equal Dir.pwd, @before_deploy_dir_pwd
14
-
15
- assert @before_deploy_called
16
- end
17
-
18
- refute_equal Dir.pwd, @before_deploy_dir_pwd
19
- end
20
- end
@@ -1,19 +0,0 @@
1
- require 'test_helper'
2
-
3
- # Split out to be faster
4
- class CITestToo < Minitest::Test
5
- def test_ci_create_app_with_stack
6
- app = Hatchet::GitApp.new("rails5_ruby_schema_format")
7
- app.run_ci do |test_run|
8
- assert_match "Ruby buildpack tests completed successfully", test_run.output
9
- assert_equal :succeeded, test_run.status
10
- refute_nil app.pipeline_id
11
-
12
- api_rate_limit = app.api_rate_limit.call
13
- couplings = api_rate_limit.pipeline_coupling.list_by_pipeline(app.pipeline_id)
14
- coupled_app = api_rate_limit.app.info(couplings.first["app"]["id"])
15
- assert_equal app.name, coupled_app["name"]
16
- end
17
- assert_nil app.pipeline_id
18
- end
19
- end
@@ -1,51 +0,0 @@
1
- require 'test_helper'
2
-
3
- class ConfigTest < Minitest::Test
4
-
5
- def setup
6
- @config = Hatchet::Config.new
7
- end
8
-
9
- def test_config_path_for_name
10
- assert_equal 'test/fixtures/repos/rails3/rails3_mri_193', @config.path_for_name('rails3_mri_193')
11
- end
12
-
13
- def test_config_dirs
14
- {
15
- "test/fixtures/repos/bundler/no_lockfile" => "https://github.com/sharpstone/no_lockfile.git",
16
- "test/fixtures/repos/default/default_ruby" => "https://github.com/sharpstone/default_ruby.git",
17
- "test/fixtures/repos/rails2/rails2blog" => "https://github.com/sharpstone/rails2blog.git",
18
- "test/fixtures/repos/rails3/rails3_mri_193" => "https://github.com/sharpstone/rails3_mri_193.git"
19
- }.each do |key, value|
20
- assert_include(key, value, @config.dirs)
21
- end
22
- end
23
-
24
- def test_config_repos
25
- {
26
- "default_ruby" => "test/fixtures/repos/default/default_ruby",
27
- "no_lockfile" => "test/fixtures/repos/bundler/no_lockfile",
28
- "rails2blog" => "test/fixtures/repos/rails2/rails2blog",
29
- "rails3_mri_193" => "test/fixtures/repos/rails3/rails3_mri_193"
30
- }.each do |key, value|
31
- assert_include(key, value, @config.repos)
32
- end
33
- end
34
-
35
- def test_no_internal_config_raises_no_errors
36
- # assert no_raise
37
- @config.send :set_internal_config!, {}
38
- assert_equal './repos', @config.repo_directory_path
39
- end
40
-
41
- def test_github_shortcuts
42
- @config.send :init_config!, {"foo" => ["schneems/sextant"]}
43
- assert_equal("https://github.com/schneems/sextant.git", @config.dirs["./repos/foo/sextant"])
44
- end
45
- private
46
-
47
- def assert_include(key, value, actual)
48
- assert_equal value, actual[key], "Expected #{actual.inspect} to include #{ {key => value } } but it did not"
49
- end
50
- end
51
-
@@ -1,20 +0,0 @@
1
- require 'test_helper'
2
-
3
- class EditRepoTest < Minitest::Test
4
- def test_can_deploy_git_app
5
- Hatchet::GitApp.new("default_ruby").in_directory do |app|
6
- msg = `touch foo`
7
- assert $?.success?, msg
8
-
9
- msg = `git add .; git commit -m foo`
10
- assert $?.success?, msg
11
-
12
- assert_match "foo", `ls`
13
- end
14
-
15
- Hatchet::GitApp.new("default_ruby").in_directory do |app|
16
- refute_match(/foo/, `ls`)
17
- end
18
- end
19
- end
20
-
@@ -1,16 +0,0 @@
1
- require 'test_helper'
2
-
3
- class GitAppTest < Minitest::Test
4
- def test_can_deploy_git_app
5
- Hatchet::GitApp.new("rails5_ruby_schema_format").deploy do |app|
6
- assert true
7
- assert_match '2.4.1', app.run("ruby -v")
8
-
9
- app.run("bash") do |cmd|
10
- # cmd.run("cd public/assets")
11
- cmd.run("ls public/") {|r| assert_match("assets", r) }
12
- end
13
- end
14
- end
15
- end
16
-
@@ -1,30 +0,0 @@
1
- require 'test_helper'
2
-
3
- class HerokuApiTest < Minitest::Test
4
-
5
- def test_config_vars
6
- runner = Hatchet::Runner.new("no_lockfile").setup!
7
- expected = {}
8
- actual = runner.get_config
9
- actual.delete("BUILDPACK_URL")
10
- assert_equal expected, actual
11
-
12
- runner.set_config("foo" => "bar")
13
- expected = {"foo" => "bar"}
14
- actual = runner.get_config
15
- actual.delete("BUILDPACK_URL")
16
- assert_equal expected, actual
17
- ensure
18
- runner.teardown! if runner
19
- end
20
-
21
-
22
- def test_config_vars_in_init
23
- runner = Hatchet::Runner.new("no_lockfile", config: { foo: "bar"}).setup!
24
- actual = runner.get_config
25
- expected = {"foo" => "bar"}
26
- assert_equal expected, actual
27
- ensure
28
- runner.teardown! if runner
29
- end
30
- end
@@ -1,20 +0,0 @@
1
- require 'test_helper'
2
-
3
- class LabsTest < Minitest::Test
4
- def setup
5
- @buildpack_path = File.expand_path 'test/fixtures/buildpacks/heroku-buildpack-ruby'
6
- end
7
-
8
- def test_can_deploy_git_app
9
- # You can't enable preboot on a free app.
10
- # BUT you can't make an app hobby until you've deploy once
11
- # Catch-22
12
- # lab_name = "preboot"
13
- # app = Hatchet::App.new("rails3_mri_193", labs: lab_name, buildpack: @buildpack_path)
14
- # app.setup!
15
- # assert(app.lab_is_installed?(lab_name), "Expected #{app.get_labs.inspect} to include {'name' => '#{lab_name}' } but it did not")
16
- assert(true)
17
- # ensure
18
- # app.teardown! if app
19
- end
20
- end
@@ -1,26 +0,0 @@
1
- require 'test_helper'
2
-
3
- class LocalRepoTest < Minitest::Test
4
- def test_in_directory_fork
5
- env_name = SecureRandom.hex
6
- ENV[env_name] = env_name
7
-
8
- Hatchet::App.new("default_ruby").in_directory_fork do
9
- ENV.delete(env_name)
10
- assert_nil ENV[env_name]
11
- end
12
-
13
- assert_equal env_name, ENV[env_name]
14
- end
15
-
16
- def test_repos_checked_into_git
17
- app = Hatchet::App.new("test/different-folder-for-checked-in-repos/default_ruby")
18
- app.in_directory do
19
- assert_equal false, Dir.exist?(".git")
20
- app.setup!
21
- assert_equal true, Dir.exist?(".git")
22
- end
23
- ensure
24
- app.teardown! if app
25
- end
26
- end
@@ -1,18 +0,0 @@
1
- require 'test_helper'
2
-
3
- class LockTest < Minitest::Test
4
- def test_app_with_failure_can_be_locked_to_prior_commit
5
- Hatchet::GitApp.new("lock_fail").deploy do |app|
6
- assert app.deployed?
7
- end
8
- end
9
-
10
- def test_app_with_failure_can_be_locked_to_master
11
- puts `bundle exec hatchet lock`
12
-
13
- lock = YAML.load_file("hatchet.lock")
14
- name, branch = lock.select {|k,v| k.end_with?("lock_fail_master") }.first
15
- assert_equal "test/fixtures/repos/lock/lock_fail_master", name
16
- assert_equal "master", branch
17
- end
18
- end