heroku_hatchet 7.0.0 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +2 -0
- data/bin/hatchet +9 -4
- data/lib/hatchet/app.rb +14 -12
- data/lib/hatchet/git_app.rb +1 -0
- data/lib/hatchet/version.rb +1 -1
- data/spec/hatchet/allow_failure_git_spec.rb +19 -4
- data/spec/hatchet/lock_spec.rb +51 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8c7a94962a255edf58024ed43c7102fc7eb97e07a3d1127ccec6f1cb16c560b
|
4
|
+
data.tar.gz: 36c1999581499ba71e09c93376281bb57105be30d7c42637b1e38a29decdd602
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bbc833ba77cc7ce963795cc90ec282489b35a235e5c161e85704b15d2cd430a1a426906d26bdee3f00045a637b56eb31b11778beb220b459c7e79d2d87f1306a
|
7
|
+
data.tar.gz: a7c48cc4ce7103313cdfa8dcd5a27d519ade4fa02d328b837f1cd6c0d4f02af377ec2df764235af0d66316b535ea145716ff0974c797ee32b243ad415472db86
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## HEAD
|
2
2
|
|
3
|
+
## 7.1.0
|
4
|
+
|
5
|
+
- Initializing an `App` can now take a `retries` key to overload the global hatchet env var (https://github.com/heroku/hatchet/pull/119)
|
6
|
+
- Calling `App#commit!` now adds an empty commit if there is no changes on disk (https://github.com/heroku/hatchet/pull/119)
|
7
|
+
- Bugfix: Failed release phase in deploys can now be re-run (https://github.com/heroku/hatchet/pull/119)
|
8
|
+
- Bugfix: Allow `hatchet lock` to be run against new projects (https://github.com/heroku/hatchet/pull/118)
|
9
|
+
- Bugfix: Allow `hatchet.lock` file to lock a repo to a different branch than what is specified as default for GitHub (https://github.com/heroku/hatchet/pull/118)
|
10
|
+
|
3
11
|
## 7.0.0
|
4
12
|
|
5
13
|
- ActiveSupport's Object#blank? and Object#present? are no longer provided by default (https://github.com/heroku/hatchet/pull/107)
|
data/README.md
CHANGED
@@ -531,6 +531,8 @@ WARNING: Enabling `run_multi` setting on an app will charge your Heroku account
|
|
531
531
|
WARNING: Do not use `run_multi` if you're not using the `deploy` block syntax or manually call `teardown!` inside the text context [more info about how behavior does not work with the `after` block syntax in rspec](https://github.com/heroku/hatchet/issues/110).
|
532
532
|
WARNING: To work, `run_multi` requires your application to have a `web` process associated with it.
|
533
533
|
|
534
|
+
- `retries` (Integer): When passed in, this value will be used insead of the global `HATCHET_RETRIES` set via environment variable. When `allow_failures: true` is set as well as a retries value, then the application will not retry pushing to Heroku.
|
535
|
+
|
534
536
|
### App methods:
|
535
537
|
|
536
538
|
- `app.set_config()`: Updates the configuration on your app taking in a hash
|
data/bin/hatchet
CHANGED
@@ -67,7 +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
|
+
lockfile_hash = load_lockfile(create_if_does_not_exist: true)
|
71
71
|
dirs.map do |directory, git_repo|
|
72
72
|
Threaded.later do
|
73
73
|
puts "== locking #{directory}"
|
@@ -118,10 +118,15 @@ class HatchetCLI < Thor
|
|
118
118
|
end
|
119
119
|
|
120
120
|
private
|
121
|
-
def load_lockfile
|
121
|
+
def load_lockfile(create_if_does_not_exist: false)
|
122
122
|
return YAML.safe_load(File.read('hatchet.lock')).to_h
|
123
123
|
rescue Errno::ENOENT
|
124
|
-
|
124
|
+
if create_if_does_not_exist
|
125
|
+
FileUtils.touch('hatchet.lock')
|
126
|
+
{}
|
127
|
+
else
|
128
|
+
raise "No such file found `hatchet.lock` please run `$ bundle exec hatchet lock`"
|
129
|
+
end
|
125
130
|
end
|
126
131
|
|
127
132
|
def bad_repo?(url)
|
@@ -151,7 +156,7 @@ class HatchetCLI < Thor
|
|
151
156
|
end
|
152
157
|
|
153
158
|
def checkout_commit(directory, commit)
|
154
|
-
cmd("cd #{directory} && git reset --hard #{commit}")
|
159
|
+
cmd("cd #{directory} && git fetch origin #{commit} && git checkout #{commit} && git checkout - && git reset --hard #{commit}")
|
155
160
|
end
|
156
161
|
|
157
162
|
def commit_at_directory(directory)
|
data/lib/hatchet/app.rb
CHANGED
@@ -9,7 +9,7 @@ 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, :reaper
|
12
|
+
attr_reader :name, :stack, :directory, :repo_name, :app_config, :buildpacks, :reaper, :max_retries_count
|
13
13
|
|
14
14
|
class FailedDeploy < StandardError; end
|
15
15
|
|
@@ -55,6 +55,7 @@ module Hatchet
|
|
55
55
|
buildpack_url: nil,
|
56
56
|
before_deploy: nil,
|
57
57
|
run_multi: ENV["HATCHET_RUN_MULTI"],
|
58
|
+
retries: RETRIES,
|
58
59
|
config: {}
|
59
60
|
)
|
60
61
|
@repo_name = repo_name
|
@@ -68,6 +69,7 @@ module Hatchet
|
|
68
69
|
@buildpacks = Array(@buildpacks)
|
69
70
|
@buildpacks.map! {|b| b == :default ? self.class.default_buildpack : b}
|
70
71
|
@run_multi = run_multi
|
72
|
+
@max_retries_count = retries
|
71
73
|
|
72
74
|
if run_multi && !ENV["HATCHET_EXPENSIVE_MODE"]
|
73
75
|
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"
|
@@ -129,7 +131,7 @@ module Hatchet
|
|
129
131
|
end
|
130
132
|
|
131
133
|
def add_database(plan_name = 'heroku-postgresql:dev', match_val = "HEROKU_POSTGRESQL_[A-Z]+_URL")
|
132
|
-
|
134
|
+
max_retries_count.times.retry do
|
133
135
|
# heroku.post_addon(name, plan_name)
|
134
136
|
api_rate_limit.call.addon.create(name, plan: plan_name )
|
135
137
|
_, value = get_config.detect {|k, v| k.match(/#{match_val}/) }
|
@@ -316,7 +318,7 @@ module Hatchet
|
|
316
318
|
end
|
317
319
|
|
318
320
|
def commit!
|
319
|
-
local_cmd_exec!('git add .; git commit -m next')
|
321
|
+
local_cmd_exec!('git add .; git commit --allow-empty -m next')
|
320
322
|
end
|
321
323
|
|
322
324
|
def push_without_retry!
|
@@ -386,12 +388,12 @@ module Hatchet
|
|
386
388
|
end
|
387
389
|
|
388
390
|
def push
|
389
|
-
|
390
|
-
|
391
|
+
retry_count = allow_failure? ? 1 : max_retries_count
|
392
|
+
retry_count.times.retry do |attempt|
|
391
393
|
begin
|
392
394
|
@output = self.push_without_retry!
|
393
395
|
rescue StandardError => error
|
394
|
-
puts retry_error_message(error, attempt
|
396
|
+
puts retry_error_message(error, attempt) unless retry_count == 1
|
395
397
|
raise error
|
396
398
|
end
|
397
399
|
end
|
@@ -400,10 +402,10 @@ module Hatchet
|
|
400
402
|
alias :push_with_retry :push
|
401
403
|
alias :push_with_retry! :push_with_retry
|
402
404
|
|
403
|
-
def retry_error_message(error, attempt
|
405
|
+
def retry_error_message(error, attempt)
|
404
406
|
attempt += 1
|
405
|
-
return "" if attempt ==
|
406
|
-
msg = "\nRetrying failed Attempt ##{attempt}/#{
|
407
|
+
return "" if attempt == max_retries_count
|
408
|
+
msg = "\nRetrying failed Attempt ##{attempt}/#{max_retries_count} to push for '#{name}' due to error: \n"<<
|
407
409
|
"#{error.class} #{error.message}\n #{error.backtrace.join("\n ")}"
|
408
410
|
return msg
|
409
411
|
end
|
@@ -422,7 +424,7 @@ module Hatchet
|
|
422
424
|
|
423
425
|
def run_ci(timeout: 300, &block)
|
424
426
|
in_directory do
|
425
|
-
|
427
|
+
max_retries_count.times.retry do
|
426
428
|
result = create_pipeline
|
427
429
|
@pipeline_id = result["id"]
|
428
430
|
end
|
@@ -433,7 +435,7 @@ module Hatchet
|
|
433
435
|
# that's why we create an app explictly (or maybe it already exists), and then associate it with with the pipeline
|
434
436
|
# the app will be auto cleaned up later
|
435
437
|
self.setup!
|
436
|
-
|
438
|
+
max_retries_count.times.retry do
|
437
439
|
couple_pipeline(@name, @pipeline_id)
|
438
440
|
end
|
439
441
|
|
@@ -446,7 +448,7 @@ module Hatchet
|
|
446
448
|
api_rate_limit: api_rate_limit
|
447
449
|
)
|
448
450
|
|
449
|
-
|
451
|
+
max_retries_count.times.retry do
|
450
452
|
test_run.create_test_run
|
451
453
|
end
|
452
454
|
test_run.wait!(&block)
|
data/lib/hatchet/git_app.rb
CHANGED
@@ -33,6 +33,7 @@ module Hatchet
|
|
33
33
|
|
34
34
|
releases = platform_api.release.list(name)
|
35
35
|
if releases.last["status"] == "failed"
|
36
|
+
commit! # An empty commit allows us to deploy again
|
36
37
|
raise FailedReleaseError.new(self, "Buildpack: #{@buildpack.inspect}\nRepo: #{git_repo}", output: output)
|
37
38
|
end
|
38
39
|
|
data/lib/hatchet/version.rb
CHANGED
@@ -13,14 +13,29 @@ describe "AllowFailureGitTest" do
|
|
13
13
|
}
|
14
14
|
|
15
15
|
it "is marked as a failure if the release fails" do
|
16
|
+
app = Hatchet::GitApp.new("default_ruby", before_deploy: release_fail_proc, retries: 2)
|
17
|
+
def app.retry_error_message(*args); @test_attempts_count ||= 0; @test_attempts_count += 1; "" end
|
18
|
+
def app.test_attempts_count; @test_attempts_count ; end
|
19
|
+
|
16
20
|
expect {
|
17
|
-
|
18
|
-
}.to
|
21
|
+
app.deploy {}
|
22
|
+
}.to raise_error { |error|
|
23
|
+
expect(error).to be_a(Hatchet::App::FailedReleaseError)
|
24
|
+
expect(error.message).to_not match("Everything up-to-date")
|
25
|
+
}
|
26
|
+
|
27
|
+
expect(app.test_attempts_count).to eq(2)
|
19
28
|
end
|
20
29
|
|
21
30
|
it "works when failure is allowed" do
|
22
|
-
Hatchet::GitApp.new("default_ruby", before_deploy: release_fail_proc, allow_failure: true).
|
23
|
-
|
31
|
+
Hatchet::GitApp.new("default_ruby", before_deploy: release_fail_proc, allow_failure: true, retries: 3).tap do |app|
|
32
|
+
def app.retry_error_message(*args); @test_attempts_count ||= 0; @test_attempts_count += 1; "" end
|
33
|
+
def app.test_attempts_count; @test_attempts_count ; end
|
34
|
+
|
35
|
+
app.deploy do
|
36
|
+
expect(app.output).to match("failing on release")
|
37
|
+
expect(app.test_attempts_count).to eq(nil)
|
38
|
+
end
|
24
39
|
end
|
25
40
|
end
|
26
41
|
end
|
data/spec/hatchet/lock_spec.rb
CHANGED
@@ -28,3 +28,54 @@ describe "LockTest" do
|
|
28
28
|
expect(branch).to eq("main")
|
29
29
|
end
|
30
30
|
end
|
31
|
+
|
32
|
+
describe "isolated lock tests" do
|
33
|
+
it "works when there's no hatchet.lock" do
|
34
|
+
Dir.mktmpdir do |dir|
|
35
|
+
dir = Pathname.new(dir)
|
36
|
+
|
37
|
+
dir.join("hatchet.json").open("w+") do |f|
|
38
|
+
f.puts %Q{{ "foo": ["sharpstone/lock_fail_main_default_is_master"] }}
|
39
|
+
end
|
40
|
+
|
41
|
+
output = `cd #{dir} && hatchet lock 2>&1`
|
42
|
+
|
43
|
+
raise "Expected cmd `hatchet lock` to succeed, but it did not: #{output}" unless $?.success?
|
44
|
+
expect(output).to include("locking")
|
45
|
+
|
46
|
+
lockfile_contents = dir.join('hatchet.lock').read
|
47
|
+
expect(lockfile_contents).to include("repos/foo/lock_fail_main_default_is_master")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "works when a project is locked to main but the default branch is master" do
|
52
|
+
Dir.mktmpdir do |dir|
|
53
|
+
dir = Pathname.new(dir)
|
54
|
+
|
55
|
+
dir.join("hatchet.json").open("w+") do |f|
|
56
|
+
f.puts %Q{{ "foo": ["sharpstone/lock_fail_main_default_is_master"] }}
|
57
|
+
end
|
58
|
+
|
59
|
+
dir.join("hatchet.lock").open("w+") do |f|
|
60
|
+
f.puts <<~EOM
|
61
|
+
---
|
62
|
+
- - "./repos/foo/lock_fail_main_default_is_master"
|
63
|
+
- main
|
64
|
+
EOM
|
65
|
+
end
|
66
|
+
|
67
|
+
output = `cd #{dir} && hatchet install 2>&1`
|
68
|
+
|
69
|
+
raise "Expected cmd `hatchet install` to succeed, but it did not:\n#{output}" unless $?.success?
|
70
|
+
expect(output).to include("Installing")
|
71
|
+
|
72
|
+
lockfile_contents = dir.join('hatchet.lock').read
|
73
|
+
contents = YAML.safe_load(lockfile_contents).to_h
|
74
|
+
expect(contents).to eq({"./repos/foo/lock_fail_main_default_is_master" => "main"})
|
75
|
+
|
76
|
+
contents.each do |repo_dir, commit_or_branch|
|
77
|
+
expect(`cd #{dir.join(repo_dir)} && git describe --contains --all HEAD`).to match("main")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heroku_hatchet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Schneeman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-08-
|
11
|
+
date: 2020-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: platform-api
|