MRSK hooks
Adds hooks to MRSK. Currently just two hooks, pre-build and post-push. We could break the build and push into two separate commands if we found the need for post-build and/or pre-push hooks. Hooks are stored in `.mrsk/hooks`. Running `mrsk init` will now create that folder and add sample hook scripts. Hooks returning non-zero exit codes will abort the current command. Further potential work here: - We could replace the audit broadcast command with a post-deploy/post-rollback hook or similar - Maybe provide pre-command/post-command hooks that run after every mrsk invocation - Also look for hooks in `~/.mrsk/hooks`
This commit is contained in:
@@ -2,12 +2,7 @@ require_relative "cli_test_case"
|
||||
|
||||
class CliAppTest < CliTestCase
|
||||
test "boot" do
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("123") # old version
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
||||
.returns("running") # health check
|
||||
|
||||
stub_running
|
||||
run_command("boot").tap do |output|
|
||||
assert_match "docker tag dhh/app:latest dhh/app:latest", output
|
||||
assert_match "docker run --detach --restart unless-stopped", output
|
||||
@@ -183,4 +178,12 @@ class CliAppTest < CliTestCase
|
||||
def run_command(*command, config: :with_accessories)
|
||||
stdouted { Mrsk::Cli::App.start([*command, "-c", "test/fixtures/deploy_#{config}.yml", "--hosts", "1.1.1.1"]) }
|
||||
end
|
||||
|
||||
def stub_running
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("123") # old version
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
||||
.returns("running") # health check
|
||||
end
|
||||
end
|
||||
|
||||
@@ -41,6 +41,22 @@ class CliBuildTest < CliTestCase
|
||||
assert_raises(Mrsk::Cli::Build::BuildError) { run_command("push") }
|
||||
end
|
||||
|
||||
test "push pre-build hook failure" do
|
||||
fail_hook("pre-build")
|
||||
|
||||
assert_raises(Mrsk::Cli::HookError) { run_command("push") }
|
||||
|
||||
assert @executions.none? { |args| args[0..2] == [:docker, :buildx, :build] }
|
||||
end
|
||||
|
||||
test "push post-push hook failure" do
|
||||
fail_hook("post-push")
|
||||
|
||||
assert_raises(Mrsk::Cli::HookError) { run_command("push") }
|
||||
|
||||
assert @executions.any? { |args| args[0..2] == [:docker, :buildx, :build] }
|
||||
end
|
||||
|
||||
test "pull" do
|
||||
run_command("pull").tap do |output|
|
||||
assert_match /docker image rm --force dhh\/app:999/, output
|
||||
@@ -93,4 +109,11 @@ class CliBuildTest < CliTestCase
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||
.with { |arg1, arg2| arg1 == :rm && arg2 == "mrsk_lock/details" }
|
||||
end
|
||||
|
||||
def stub_dependency_checks
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||
.with(:docker, "--version", "&&", :docker, :buildx, "version")
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||
.with { |*args| args[0..1] == [:docker, :buildx] }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,4 +14,17 @@ class CliTestCase < ActiveSupport::TestCase
|
||||
ENV.delete("MYSQL_ROOT_PASSWORD")
|
||||
ENV.delete("VERSION")
|
||||
end
|
||||
|
||||
private
|
||||
def fail_hook(hook)
|
||||
@executions = []
|
||||
Mrsk::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true)
|
||||
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||
.with { |*args| @executions << args; args != [".mrsk/hooks/#{hook}"] }
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||
.with { |*args| args.first == ".mrsk/hooks/#{hook}" }
|
||||
.raises(SSHKit::Command::Failed.new("failed"))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -235,9 +235,11 @@ class CliMainTest < CliTestCase
|
||||
end
|
||||
|
||||
test "init" do
|
||||
Pathname.any_instance.expects(:exist?).returns(false).twice
|
||||
Pathname.any_instance.expects(:exist?).returns(false).times(3)
|
||||
Pathname.any_instance.stubs(:mkpath)
|
||||
FileUtils.stubs(:mkdir_p)
|
||||
FileUtils.stubs(:cp_r)
|
||||
FileUtils.stubs(:cp)
|
||||
|
||||
run_command("init").tap do |output|
|
||||
assert_match /Created configuration file in config\/deploy.yml/, output
|
||||
@@ -246,7 +248,7 @@ class CliMainTest < CliTestCase
|
||||
end
|
||||
|
||||
test "init with existing config" do
|
||||
Pathname.any_instance.expects(:exist?).returns(true).twice
|
||||
Pathname.any_instance.expects(:exist?).returns(true).times(3)
|
||||
|
||||
run_command("init").tap do |output|
|
||||
assert_match /Config file already exists in config\/deploy.yml \(remove first to create a new one\)/, output
|
||||
@@ -254,9 +256,11 @@ class CliMainTest < CliTestCase
|
||||
end
|
||||
|
||||
test "init with bundle option" do
|
||||
Pathname.any_instance.expects(:exist?).returns(false).times(3)
|
||||
Pathname.any_instance.expects(:exist?).returns(false).times(4)
|
||||
Pathname.any_instance.stubs(:mkpath)
|
||||
FileUtils.stubs(:mkdir_p)
|
||||
FileUtils.stubs(:cp_r)
|
||||
FileUtils.stubs(:cp)
|
||||
|
||||
run_command("init", "--bundle").tap do |output|
|
||||
assert_match /Created configuration file in config\/deploy.yml/, output
|
||||
@@ -269,9 +273,11 @@ class CliMainTest < CliTestCase
|
||||
end
|
||||
|
||||
test "init with bundle option and existing binstub" do
|
||||
Pathname.any_instance.expects(:exist?).returns(true).times(3)
|
||||
Pathname.any_instance.expects(:exist?).returns(true).times(4)
|
||||
Pathname.any_instance.stubs(:mkpath)
|
||||
FileUtils.stubs(:mkdir_p)
|
||||
FileUtils.stubs(:cp_r)
|
||||
FileUtils.stubs(:cp)
|
||||
|
||||
run_command("init", "--bundle").tap do |output|
|
||||
assert_match /Config file already exists in config\/deploy.yml \(remove first to create a new one\)/, output
|
||||
@@ -321,7 +327,7 @@ class CliMainTest < CliTestCase
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with do |command, line, options, verbosity:|
|
||||
command == "bin/audit_broadcast" &&
|
||||
line =~ /\A'\[[^\]]+\] message'\z/ &&
|
||||
options[:env].keys == %w[ MRSK_RECORDED_AT MRSK_PERFORMER MRSK_EVENT ] &&
|
||||
options[:env].keys == %w[ MRSK_RECORDED_AT MRSK_PERFORMER MRSK_VERSION MRSK_EVENT ] &&
|
||||
verbosity == :debug
|
||||
end.returns("Broadcast audit message: message")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user