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
@@ -1,16 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.3.1
4
- before_script:
5
- - bundle exec hatchet ci:setup
6
- script: bundle exec parallel_test test/hatchet -n 11
7
- after_script: bundle exec rake hatchet:teardown_travis
8
- env:
9
- global:
10
- - HATCHET_BUILDPACK_BRANCH=master
11
- - HATCHET_RETRIES=3
12
- - HATCHET_APP_LIMIT=80
13
- - secure: KvuEChRTZYrWd1Q4PKt3YM5FkfuCAOtsKgjC4HDGjCYVNee3793XGwAr0e5LiQqrvHDmbJS7ZPelV3ptor2QJTdmZjPhu/tZKPMLQg7wm8vTcrJflkJDqJl6ECxd40zbUgmo+wSPSvx+K3ZGKqLF4D43vvFJaqBUoAVOGdt66c8=
14
- - secure: XuJ4XUraWzNlfY9a+6Mh9lVlLuRY988YAaA8LKQOe2KAT5MRqcZzqlKOwDeTWK0tas68bzK7T8RT/L+6/nck0u5VrPHMhkc8QDBSqcle8kFcBxf/64EnCzB40lZoxvcdQ3wm8E41DRwsI7hAHLdVVNXC8f1/wQOAm77nOEvPdvM=
15
- sudo: true
16
- dist: trusty
@@ -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,9 +0,0 @@
1
- require 'test_helper'
2
-
3
- class CIThreeTest < Minitest::Test
4
- def test_error_with_bad_app
5
- Hatchet::GitApp.new("rails5_ci_fails_no_database", allow_failure: true).run_ci do |test_run|
6
- assert_equal :errored, test_run.status
7
- end
8
- end
9
- 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,9 +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
- end