heroku_hatchet 5.0.3 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +19 -1
  3. data/.gitignore +2 -0
  4. data/CHANGELOG.md +4 -0
  5. data/etc/ci_setup.rb +16 -12
  6. data/etc/setup_heroku.sh +0 -2
  7. data/hatchet.gemspec +4 -5
  8. data/hatchet.json +1 -1
  9. data/hatchet.lock +9 -9
  10. data/lib/hatchet/api_rate_limit.rb +7 -7
  11. data/lib/hatchet/test_run.rb +15 -9
  12. data/lib/hatchet/version.rb +1 -1
  13. data/{test → repo_fixtures}/different-folder-for-checked-in-repos/default_ruby/Gemfile +0 -0
  14. data/spec/hatchet/allow_failure_git_spec.rb +15 -0
  15. data/spec/hatchet/app_spec.rb +87 -0
  16. data/spec/hatchet/ci_spec.rb +58 -0
  17. data/spec/hatchet/config_spec.rb +34 -0
  18. data/spec/hatchet/edit_repo_spec.rb +17 -0
  19. data/spec/hatchet/git_spec.rb +9 -0
  20. data/spec/hatchet/heroku_api_spec.rb +30 -0
  21. data/spec/hatchet/local_repo_spec.rb +26 -0
  22. data/spec/hatchet/lock_spec.rb +19 -0
  23. data/spec/spec_helper.rb +25 -0
  24. metadata +35 -71
  25. data/test/fixtures/buildpacks/null-buildpack/bin/compile +0 -4
  26. data/test/fixtures/buildpacks/null-buildpack/bin/detect +0 -5
  27. data/test/fixtures/buildpacks/null-buildpack/bin/release +0 -3
  28. data/test/fixtures/buildpacks/null-buildpack/hatchet.json +0 -4
  29. data/test/fixtures/buildpacks/null-buildpack/readme.md +0 -41
  30. data/test/hatchet/allow_failure_git_test.rb +0 -16
  31. data/test/hatchet/app_test.rb +0 -96
  32. data/test/hatchet/ci_four_test.rb +0 -19
  33. data/test/hatchet/ci_test.rb +0 -11
  34. data/test/hatchet/ci_three_test.rb +0 -20
  35. data/test/hatchet/ci_too_test.rb +0 -19
  36. data/test/hatchet/config_test.rb +0 -51
  37. data/test/hatchet/edit_repo_test.rb +0 -20
  38. data/test/hatchet/git_test.rb +0 -16
  39. data/test/hatchet/heroku_api_test.rb +0 -30
  40. data/test/hatchet/labs_test.rb +0 -20
  41. data/test/hatchet/local_repo_test.rb +0 -26
  42. data/test/hatchet/lock_test.rb +0 -18
  43. data/test/hatchet/multi_cmd_runner_test.rb +0 -30
  44. data/test/test_helper.rb +0 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aaba14f0335f61010579c2a28cebb4ddc3745673cd2bf9e60a79b9b77772fba1
4
- data.tar.gz: 46d867946f075054f67d2a5a1262ef203cfe20e19f6f025b2761f76a65b5b886
3
+ metadata.gz: ce2fc5243218285fa0505cf41a9fc51d1f7cdfd3cb69ff57e83c11be6137f57e
4
+ data.tar.gz: f61248e6cfd590ce04ca68b0a5233336a56bb3b1f135580eb10ff5016b59b36b
5
5
  SHA512:
6
- metadata.gz: c241f9a5422e4fba52afa9bb86c2e593452ab021bf111707deea9f6a132d7b4ea3afcba69b95575b82628838e5433e502ba9f64cf1cda8beaa8c764eb56dbd29
7
- data.tar.gz: b65f318865923df9da5aeb17e86bb39a1633b787b0497a5d991361650d816925accb986a2c0b015d6b67c949fc0cf67408a83373810a46328c9c353e0203af8e
6
+ metadata.gz: 269805f1a98ccf64e772e66a503ad9e0558635eca7a7c04b12567b1335f059b7dfa17e4e704b8fca1c088d38672eafce1bd8f290c564a62d44911059f5eb7700
7
+ data.tar.gz: f0d1d0a640b5de56214acd122aaa918e3038ecc65ceef526c86c44585cd5ad253061f05252c40154c7edac57aa84d038a8216843198373c7a9b1d67b1662fb12
@@ -3,7 +3,16 @@ references:
3
3
  unit: &unit
4
4
  run:
5
5
  name: Run test suite
6
- command: bundle exec parallel_test test/hatchet -n 11
6
+ command: PARALLEL_SPLIT_TEST_PROCESSES=25 bundle exec parallel_split_test spec/
7
+ restore: &restore
8
+ restore_cache:
9
+ keys:
10
+ - v1_bundler_deps-{{ .Environment.CIRCLE_JOB }}
11
+ save: &save
12
+ save_cache:
13
+ paths:
14
+ - ./vendor/bundle
15
+ key: v1_bundler_deps-{{ .Environment.CIRCLE_JOB }} # CIRCLE_JOB e.g. "ruby-2.5"
7
16
  hatchet_setup: &hatchet_setup
8
17
  run:
9
18
  name: Hatchet setup
@@ -14,31 +23,40 @@ references:
14
23
  name: install dependencies
15
24
  command: |
16
25
  bundle install --jobs=4 --retry=3 --path vendor/bundle
26
+ bundle update
27
+ bundle clean
28
+
17
29
  jobs:
18
30
  "ruby-2.5":
19
31
  docker:
20
32
  - image: circleci/ruby:2.5
21
33
  steps:
22
34
  - checkout
35
+ - <<: *restore
23
36
  - <<: *bundle
24
37
  - <<: *hatchet_setup
25
38
  - <<: *unit
39
+ - <<: *save
26
40
  "ruby-2.6":
27
41
  docker:
28
42
  - image: circleci/ruby:2.6
29
43
  steps:
30
44
  - checkout
45
+ - <<: *restore
31
46
  - <<: *bundle
32
47
  - <<: *hatchet_setup
33
48
  - <<: *unit
49
+ - <<: *save
34
50
  "ruby-2.7":
35
51
  docker:
36
52
  - image: circleci/ruby:2.7
37
53
  steps:
38
54
  - checkout
55
+ - <<: *restore
39
56
  - <<: *bundle
40
57
  - <<: *hatchet_setup
41
58
  - <<: *unit
59
+ - <<: *save
42
60
 
43
61
  workflows:
44
62
  version: 2
data/.gitignore CHANGED
@@ -1,8 +1,10 @@
1
1
  .DS_Store
2
2
  test/fixtures/repos/*
3
+ repo_fixtures/repos/*
3
4
  *.gem
4
5
 
5
6
 
6
7
  Gemfile.lock
7
8
  debug.rb
8
9
  .ruby-version
10
+ .rspec_status
@@ -1,5 +1,9 @@
1
1
  ## HEAD
2
2
 
3
+ ## 6.0.0
4
+
5
+ - Rate throttling is now provided directly by `platform-api` (https://github.com/heroku/hatchet/pull/82)
6
+
3
7
  ## 5.0.3
4
8
 
5
9
  - Allow repos to be "locked" to master instead of a specific commit (https://github.com/heroku/hatchet/pull/80)
@@ -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"
@@ -14,18 +22,14 @@ machine api.heroku.com
14
22
  login #{ENV.fetch('HEROKU_API_USER')}
15
23
  password #{ENV.fetch('HEROKU_API_KEY')}
16
24
  EOF
17
- `chmod 0600 "$HOME/.netrc"`
25
+ run_cmd 'chmod 0600 "$HOME/.netrc"'
18
26
  end
19
27
  end
20
28
 
21
- [
22
- "bundle exec hatchet ci:install_heroku",
23
- "bundle exec hatchet install",
24
- "git config --get user.email > /dev/null || git config --global user.email #{ENV.fetch('HEROKU_API_USER').shellescape}",
25
- "git config --get user.name > /dev/null || git config --global user.name 'BuildpackTester'",
26
- ].each do |command|
27
- puts "== Running: #{command}"
28
- result = `#{command}`
29
- raise "Command failed: #{command.inspect}\nResult: #{result}" unless $?.success?
30
- 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
+
31
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,18 +18,17 @@ 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.0.0.pre.1 "
22
22
  gem.add_dependency "rrrretry", "~> 1"
23
23
  gem.add_dependency "excon", "~> 0"
24
24
  gem.add_dependency "thor", "~> 0"
25
25
  gem.add_dependency "repl_runner", "~> 0.0.3"
26
26
  gem.add_dependency "threaded", "~> 0"
27
- gem.add_dependency 'minitest-retry', '~> 0.1.9'
28
27
 
29
- gem.add_development_dependency "minitest", ">= 5.1"
28
+ gem.add_development_dependency "rspec"
30
29
  gem.add_development_dependency "rake", ">= 10"
31
30
  gem.add_development_dependency "mocha", ">= 1"
32
- gem.add_development_dependency "parallel_tests", ">= 2"
31
+ gem.add_development_dependency "parallel_split_test"
33
32
  gem.add_development_dependency "travis", ">= 1"
34
- gem.add_development_dependency "m"
33
+ gem.add_development_dependency "rspec-retry"
35
34
  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"],
@@ -1,17 +1,17 @@
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/lock/lock_fail_master
12
+ - - repo_fixtures/repos/lock/lock_fail_master
13
13
  - master
14
- - - test/fixtures/repos/rails2/rails2blog
14
+ - - repo_fixtures/repos/rails2/rails2blog
15
15
  - b37357a498ae5e8429f5601c5ab9524021dc2aaa
16
- - - test/fixtures/repos/rails3/rails3_mri_193
16
+ - - repo_fixtures/repos/rails3/rails3_mri_193
17
17
  - 88c5d0d067cfd11e4452633994a85b04627ae8c7
@@ -25,15 +25,15 @@ class ApiRateLimit
25
25
  # to partially mitigate this, only check capacity every 5
26
26
  # api calls, or if the current capacity is under 1000
27
27
  def call
28
- @called += 1
28
+ # @called += 1
29
29
 
30
- if @called > 5 || @capacity < 1000
31
- @called = 0
32
- @capacity = @platform_api.rate_limit.info["remaining"]
33
- end
30
+ # if @called > 5 || @capacity < 1000
31
+ # @called = 0
32
+ # @capacity = @platform_api.rate_limit.info["remaining"]
33
+ # end
34
34
 
35
- sleep_time = (60/@capacity) if @capacity > 0.1 # no divide by zero
36
- sleep(sleep_time || 60)
35
+ # sleep_time = (60/@capacity) if @capacity > 0.1 # no divide by zero
36
+ # sleep(sleep_time || 60)
37
37
 
38
38
  return @platform_api
39
39
  end
@@ -181,10 +181,11 @@ module Hatchet
181
181
 
182
182
  source_put_url = @app.create_source
183
183
  Hatchet::RETRIES.times.retry do
184
- @api_rate_limit.call
185
- Excon.put(source_put_url,
186
- expects: [200],
187
- body: File.read('slug.tgz'))
184
+ PlatformAPI.rate_throttle.call do
185
+ Excon.put(source_put_url,
186
+ expects: [200],
187
+ body: File.read('slug.tgz'))
188
+ end
188
189
  end
189
190
  end
190
191
  return @app.source_get_url
@@ -192,8 +193,11 @@ module Hatchet
192
193
 
193
194
  private
194
195
  def get_contents_or_whatever(url)
195
- @api_rate_limit.call
196
- Excon.get(url, read_timeout: @pause).body
196
+ response = PlatformAPI.rate_throttle.call do
197
+ Excon.get(url, read_timeout: @pause)
198
+ end
199
+
200
+ return response.body
197
201
  rescue Excon::Error::Timeout
198
202
  ""
199
203
  end
@@ -216,9 +220,11 @@ module Hatchet
216
220
  options[:body] = JSON.generate(options[:body]) if options[:body]
217
221
 
218
222
  Hatchet::RETRIES.times.retry do
219
- @api_rate_limit.call
220
- connection = Excon.new("https://api.heroku.com")
221
- return connection.request(options)
223
+ PlatformAPI.rate_throttle.call do
224
+ connection = Excon.new("https://api.heroku.com")
225
+
226
+ return connection.request(options)
227
+ end
222
228
  end
223
229
  end
224
230
  end
@@ -1,3 +1,3 @@
1
1
  module Hatchet
2
- VERSION = "5.0.3"
2
+ VERSION = "6.0.0"
3
3
  end
@@ -0,0 +1,15 @@
1
+ require("spec_helper")
2
+
3
+ describe "AllowFailureGitTest" do
4
+ it "allowed failure" do
5
+ Hatchet::GitApp.new("no_lockfile", allow_failure: true).deploy do |app|
6
+ puts app.output
7
+ expect(app.deployed?).to be_falsey
8
+ expect(app.output).to match("Gemfile.lock required")
9
+ end
10
+ end
11
+
12
+ it "failure with no flag" do
13
+ expect { Hatchet::GitApp.new("no_lockfile").deploy }.to(raise_error(Hatchet::App::FailedDeploy))
14
+ end
15
+ end
@@ -0,0 +1,87 @@
1
+ require("spec_helper")
2
+
3
+ describe "AppTest" do
4
+ it "app with default" do
5
+ app = Hatchet::App.new("default_ruby", buildpacks: [:default])
6
+ expect(app.buildpacks.first).to match("https://github.com/heroku/heroku-buildpack-ruby")
7
+ end
8
+
9
+ it "create app with stack" do
10
+ stack = "heroku-16"
11
+ app = Hatchet::App.new("default_ruby", stack: stack)
12
+ app.create_app
13
+ expect(app.platform_api.app.info(app.name)["build_stack"]["name"]).to eq(stack)
14
+ end
15
+
16
+ it "before deploy" do
17
+ @called = false
18
+ @dir = false
19
+ app = Hatchet::App.new("default_ruby")
20
+ def app.push_with_retry!
21
+ # do nothing
22
+ end
23
+ app.before_deploy do
24
+ @called = true
25
+ @dir = Dir.pwd
26
+ end
27
+ app.deploy do
28
+ expect(@called).to eq(true)
29
+ expect(@dir).to eq(Dir.pwd)
30
+ end
31
+ expect(@dir).to_not eq(Dir.pwd)
32
+ end
33
+
34
+ it "auto commits code" do
35
+ string = "foo#{SecureRandom.hex}"
36
+ app = Hatchet::App.new("default_ruby")
37
+ def app.push_with_retry!
38
+ # do nothing
39
+ end
40
+ app.before_deploy do |app|
41
+ expect(app.send(:needs_commit?)).to eq(false)
42
+ `echo "#{string}" > Gemfile`
43
+ expect(app.send(:needs_commit?)).to eq(true)
44
+ end
45
+ app.deploy do
46
+ expect(File.read("Gemfile").chomp).to eq(string)
47
+ expect(app.send(:needs_commit?)).to eq(false)
48
+ end
49
+ end
50
+
51
+ it "nested in directory" do
52
+ string = "foo#{SecureRandom.hex}"
53
+ app = Hatchet::App.new("default_ruby")
54
+ def app.push_with_retry!
55
+ # do nothing
56
+ end
57
+ app.in_directory do
58
+ `echo "#{string}" > Gemfile`
59
+ dir = Dir.pwd
60
+ app.deploy do
61
+ expect(File.read("Gemfile").chomp).to eq(string)
62
+ expect(dir).to eq(Dir.pwd)
63
+ end
64
+ end
65
+ end
66
+
67
+ it "run" do
68
+ app = Hatchet::GitApp.new("default_ruby")
69
+ app.deploy do
70
+ expect(app.run("ls -a Gemfile 'foo bar #baz'")).to match(/ls: cannot access 'foo bar #baz': No such file or directory\s+Gemfile/)
71
+ expect((0 != $?.exitstatus)).to be_truthy
72
+ sleep(4)
73
+ app.run("ls erpderp", heroku: ({ "exit-code" => (Hatchet::App::SkipDefaultOption) }))
74
+ expect((0 == $?.exitstatus)).to be_truthy
75
+ sleep(4)
76
+ app.run("ls erpderp", heroku: ({ "no-tty" => nil }))
77
+ expect((0 != $?.exitstatus)).to be_truthy
78
+ sleep(4)
79
+ expect(app.run("echo \\$HELLO \\$NAME", raw: true, heroku: ({ "env" => "HELLO=ohai;NAME=world" }))).to match(/ohai world/)
80
+ sleep(4)
81
+ expect(app.run("echo \\$HELLO \\$NAME", raw: true, heroku: ({ "env" => "" }))).to_not match(/ohai world/)
82
+ sleep(4)
83
+ random_name = SecureRandom.hex
84
+ expect(app.run("mkdir foo; touch foo/#{random_name}; ls foo/")).to match(/#{random_name}/)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,58 @@
1
+ require "spec_helper"
2
+
3
+ describe "CIFourTest" do
4
+ it "error with bad app" do
5
+ string = SecureRandom.hex
6
+
7
+ Hatchet::GitApp.new("default_ruby").run_ci do |test_run|
8
+ expect(test_run.output).to_not match(string)
9
+ expect(test_run.output).to match("Installing rake")
10
+
11
+ run!("echo 'puts \"#{string}\"' >> Rakefile")
12
+ test_run.run_again
13
+
14
+ expect(test_run.output).to match(string)
15
+ expect(test_run.output).to match("Using rake")
16
+ expect(test_run.output).to_not match("Installing rake")
17
+ end
18
+ end
19
+
20
+ it "error with bad app" do
21
+ expect {
22
+ Hatchet::GitApp.new("rails5_ci_fails_no_database").run_ci { }
23
+ }.to raise_error(/PG::ConnectionBad: could not connect to server/)
24
+ end
25
+
26
+ it "error with bad app" do
27
+ @before_deploy_called = false
28
+ @before_deploy_dir_pwd = nil
29
+
30
+ before_deploy = -> do
31
+ @before_deploy_called = true
32
+ @before_deploy_dir_pwd = Dir.pwd
33
+ end
34
+
35
+ Hatchet::GitApp.new("rails5_ci_fails_no_database", allow_failure: true, before_deploy: before_deploy).run_ci do |test_run|
36
+ expect(test_run.status).to eq(:errored)
37
+ expect(@before_deploy_dir_pwd).to eq(Dir.pwd)
38
+ expect(@before_deploy_called).to be_truthy
39
+ end
40
+
41
+ expect(@before_deploy_dir_pwd).to_not eq(Dir.pwd)
42
+ end
43
+
44
+ it "ci create app with stack" do
45
+ app = Hatchet::GitApp.new("rails5_ruby_schema_format")
46
+ app.run_ci do |test_run|
47
+ expect(test_run.output).to match("Ruby buildpack tests completed successfully")
48
+ expect(test_run.status).to eq(:succeeded)
49
+ expect(app.pipeline_id).to_not be_nil
50
+
51
+ api_rate_limit = app.api_rate_limit.call
52
+ couplings = api_rate_limit.pipeline_coupling.list_by_pipeline(app.pipeline_id)
53
+ coupled_app = api_rate_limit.app.info(couplings.first["app"]["id"])
54
+ expect(coupled_app["name"]).to eq(app.name)
55
+ end
56
+ expect(app.pipeline_id).to be_nil
57
+ end
58
+ end
@@ -0,0 +1,34 @@
1
+ require("spec_helper")
2
+ describe "ConfigTest" do
3
+ before { @config = Hatchet::Config.new }
4
+
5
+ it("config path for name") do
6
+ expect(@config.path_for_name("rails3_mri_193")).to(eq("repo_fixtures/repos/rails3/rails3_mri_193"))
7
+ end
8
+
9
+ it("config dirs") do
10
+ { "repo_fixtures/repos/bundler/no_lockfile" => "https://github.com/sharpstone/no_lockfile.git", "repo_fixtures/repos/default/default_ruby" => "https://github.com/sharpstone/default_ruby.git", "repo_fixtures/repos/rails2/rails2blog" => "https://github.com/sharpstone/rails2blog.git", "repo_fixtures/repos/rails3/rails3_mri_193" => "https://github.com/sharpstone/rails3_mri_193.git" }.each do |key, value|
11
+ assert_include(key, value, @config.dirs)
12
+ end
13
+ end
14
+
15
+ it("config repos") do
16
+ { "default_ruby" => "repo_fixtures/repos/default/default_ruby", "no_lockfile" => "repo_fixtures/repos/bundler/no_lockfile", "rails2blog" => "repo_fixtures/repos/rails2/rails2blog", "rails3_mri_193" => "repo_fixtures/repos/rails3/rails3_mri_193" }.each do |key, value|
17
+ assert_include(key, value, @config.repos)
18
+ end
19
+ end
20
+
21
+ it("no internal config raises no errors") do
22
+ @config.send(:set_internal_config!, {})
23
+ expect(@config.repo_directory_path).to(eq("./repos"))
24
+ end
25
+
26
+ it("github shortcuts") do
27
+ @config.send(:init_config!, "foo" => (["schneems/sextant"]))
28
+ expect(@config.dirs["./repos/foo/sextant"]).to(eq("https://github.com/schneems/sextant.git"))
29
+ end
30
+
31
+ private def assert_include(key, value, actual)
32
+ expect(actual[key]).to eq(value), "Expected #{actual.inspect} to include #{{ key => value }} but it did not"
33
+ end
34
+ end