heroku_hatchet 7.0.0 → 7.1.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/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
|