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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +69 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +32 -1
- data/Gemfile +0 -1
- data/README.md +772 -205
- data/bin/hatchet +11 -4
- data/etc/ci_setup.rb +21 -15
- data/etc/setup_heroku.sh +0 -2
- data/hatchet.gemspec +4 -5
- data/hatchet.json +6 -2
- data/hatchet.lock +12 -8
- data/lib/hatchet.rb +1 -2
- data/lib/hatchet/api_rate_limit.rb +13 -24
- data/lib/hatchet/app.rb +159 -53
- data/lib/hatchet/config.rb +1 -1
- data/lib/hatchet/git_app.rb +27 -1
- data/lib/hatchet/reaper.rb +159 -56
- data/lib/hatchet/reaper/app_age.rb +49 -0
- data/lib/hatchet/reaper/reaper_throttle.rb +55 -0
- data/lib/hatchet/shell_throttle.rb +71 -0
- data/lib/hatchet/test_run.rb +16 -9
- data/lib/hatchet/version.rb +1 -1
- data/{test → repo_fixtures}/different-folder-for-checked-in-repos/default_ruby/Gemfile +0 -0
- data/spec/hatchet/allow_failure_git_spec.rb +40 -0
- data/spec/hatchet/app_spec.rb +226 -0
- data/spec/hatchet/ci_spec.rb +67 -0
- data/spec/hatchet/config_spec.rb +34 -0
- data/spec/hatchet/edit_repo_spec.rb +17 -0
- data/spec/hatchet/git_spec.rb +9 -0
- data/spec/hatchet/heroku_api_spec.rb +30 -0
- data/spec/hatchet/local_repo_spec.rb +26 -0
- data/spec/hatchet/lock_spec.rb +30 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/unit/reaper_spec.rb +153 -0
- data/spec/unit/shell_throttle.rb +28 -0
- metadata +57 -86
- data/.travis.yml +0 -16
- data/test/fixtures/buildpacks/null-buildpack/bin/compile +0 -4
- data/test/fixtures/buildpacks/null-buildpack/bin/detect +0 -5
- data/test/fixtures/buildpacks/null-buildpack/bin/release +0 -3
- data/test/fixtures/buildpacks/null-buildpack/hatchet.json +0 -4
- data/test/fixtures/buildpacks/null-buildpack/readme.md +0 -41
- data/test/hatchet/allow_failure_git_test.rb +0 -16
- data/test/hatchet/app_test.rb +0 -96
- data/test/hatchet/ci_four_test.rb +0 -19
- data/test/hatchet/ci_test.rb +0 -11
- data/test/hatchet/ci_three_test.rb +0 -9
- data/test/hatchet/ci_too_test.rb +0 -19
- data/test/hatchet/config_test.rb +0 -51
- data/test/hatchet/edit_repo_test.rb +0 -20
- data/test/hatchet/git_test.rb +0 -16
- data/test/hatchet/heroku_api_test.rb +0 -30
- data/test/hatchet/labs_test.rb +0 -20
- data/test/hatchet/local_repo_test.rb +0 -26
- data/test/hatchet/lock_test.rb +0 -9
- data/test/hatchet/multi_cmd_runner_test.rb +0 -30
- data/test/test_helper.rb +0 -28
data/.travis.yml
DELETED
@@ -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,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
|
data/test/hatchet/app_test.rb
DELETED
@@ -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
|
data/test/hatchet/ci_test.rb
DELETED
@@ -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
|
data/test/hatchet/ci_too_test.rb
DELETED
@@ -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
|
data/test/hatchet/config_test.rb
DELETED
@@ -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
|
-
|
data/test/hatchet/git_test.rb
DELETED
@@ -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
|
data/test/hatchet/labs_test.rb
DELETED
@@ -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
|