From 19f0f40adf444c4314af055a3815aeb4564b51d5 Mon Sep 17 00:00:00 2001 From: Donal McBreen Date: Tue, 23 May 2023 15:56:47 +0100 Subject: [PATCH] Add skip_hooks option --- README.md | 2 ++ lib/mrsk/cli/base.rb | 4 ++- test/cli/app_test.rb | 2 +- test/cli/main_test.rb | 57 +++++++++++++++++++++---------------------- 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index d0279942..ca550b15 100644 --- a/README.md +++ b/README.md @@ -909,6 +909,8 @@ That'll post a line like follows to a preconfigured chatbot in Basecamp: [My App] [dhh] Rolled back to version d264c4e92470ad1bd18590f04466787262f605de ``` +Set `--skip_hooks` to avoid running the hooks. + ## Stage of development This is beta software. Commands may still move around. But we're live in production at [37signals](https://37signals.com). diff --git a/lib/mrsk/cli/base.rb b/lib/mrsk/cli/base.rb index 6e158920..395df4cc 100644 --- a/lib/mrsk/cli/base.rb +++ b/lib/mrsk/cli/base.rb @@ -20,6 +20,8 @@ module Mrsk::Cli class_option :config_file, aliases: "-c", default: "config/deploy.yml", desc: "Path to config file" class_option :destination, aliases: "-d", desc: "Specify destination to be used for config file (staging -> deploy.staging.yml)" + class_option :skip_hooks, aliases: "-H", type: :boolean, default: false, desc: "Don't run hooks" + def initialize(*) super load_envs @@ -130,7 +132,7 @@ module Mrsk::Cli end def run_hook(hook, **details) - if MRSK.hook.hook_exists?(hook) + if !options[:skip_hooks] && MRSK.hook.hook_exists?(hook) say "Running the #{hook} hook...", :magenta run_locally do MRSK.with_verbosity(:debug) { execute *MRSK.hook.run(hook, **details) } diff --git a/test/cli/app_test.rb b/test/cli/app_test.rb index 5ac35909..806c8afe 100644 --- a/test/cli/app_test.rb +++ b/test/cli/app_test.rb @@ -46,7 +46,7 @@ class CliAppTest < CliTestCase end test "boot errors leave lock in place" do - invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "skip_broadcast" => false, "version" => "999" } + invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999" } Mrsk::Cli::App.any_instance.expects(:using_version).raises(RuntimeError) diff --git a/test/cli/main_test.rb b/test/cli/main_test.rb index 050becc5..b2884b4e 100644 --- a/test/cli/main_test.rb +++ b/test/cli/main_test.rb @@ -10,7 +10,7 @@ class CliMainTest < CliTestCase end test "deploy" do - invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999" } + invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false } Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:deliver", [], invoke_options) @@ -20,8 +20,7 @@ class CliMainTest < CliTestCase Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:app:boot", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:prune:all", [], invoke_options) - stub_locking - ensure_hook_runs("post-deploy") + Mrsk::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true) run_command("deploy").tap do |output| assert_match /Log into image registry/, output @@ -30,11 +29,12 @@ class CliMainTest < CliTestCase assert_match /Ensure app can pass healthcheck/, output assert_match /Detect stale containers/, output assert_match /Prune old containers and images/, output + assert_match /Running the post-deploy hook.../, output end end test "deploy with skip_push" do - invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999" } + invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false } Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:pull", [], invoke_options) @@ -84,7 +84,7 @@ class CliMainTest < CliTestCase end test "deploy errors during outside section leave remove lock" do - invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999" } + invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false } Mrsk::Cli::Main.any_instance.expects(:invoke) .with("mrsk:cli:registry:login", [], invoke_options) @@ -97,25 +97,41 @@ class CliMainTest < CliTestCase assert !MRSK.holding_lock? end + test "deploy with skipped hooks" do + invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => true } + + Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:registry:login", [], invoke_options) + Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:deliver", [], invoke_options) + Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:traefik:boot", [], invoke_options) + Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options) + Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:app:stale_containers", [], invoke_options) + Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:app:boot", [], invoke_options) + Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:prune:all", [], invoke_options) + + run_command("deploy", "--skip_hooks") do + refute_match /Running the post-deploy hook.../, output + end + end + test "redeploy" do - invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999" } + invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false } Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:deliver", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:app:stale_containers", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:app:boot", [], invoke_options) - stub_locking - ensure_hook_runs("post-deploy") + Mrsk::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true) run_command("redeploy").tap do |output| assert_match /Build and push app image/, output assert_match /Ensure app can pass healthcheck/, output + assert_match /Running the post-deploy hook.../, output end end test "redeploy with skip_push" do - invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999" } + invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false } Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:build:pull", [], invoke_options) Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:healthcheck:perform", [], invoke_options) @@ -155,11 +171,14 @@ class CliMainTest < CliTestCase .returns("running").at_least_once # health check end + Mrsk::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true) + run_command("rollback", "123", config_file: "deploy_with_accessories").tap do |output| assert_match "Start container with version 123", output assert_match "docker tag dhh/app:123 dhh/app:latest", output assert_match "docker start app-web-123", output assert_match "docker container ls --all --filter name=^app-web-version-to-rollback$ --quiet | xargs docker stop", output, "Should stop the container that was previously running" + assert_match "Running the post-deploy hook...", output end end @@ -185,26 +204,6 @@ class CliMainTest < CliTestCase end end - test "rollback runs post deploy hook" do - Mrsk::Cli::Main.any_instance.stubs(:container_available?).returns(true) - - Mrsk::Utils::HealthcheckPoller.stubs(:sleep) - - SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :container, :ls, "--filter", "name=^app-web-123$", "--quiet", raise_on_non_zero_exit: false) - .returns("").at_least_once - SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :ps, "--filter", "label=service=app", "--filter", "label=role=web", "--filter", "status=running", "--latest", "--format", "\"{{.Names}}\"", "|", "grep -oE \"\\-[^-]+$\"", "|", "cut -c 2-", raise_on_non_zero_exit: false) - .returns("").at_least_once - SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) - .with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-123$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'") - .returns("running").at_least_once # health check - - ensure_hook_runs("post-deploy") - - run_command("rollback", "123") - end - test "details" do Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:traefik:details") Mrsk::Cli::Main.any_instance.expects(:invoke).with("mrsk:cli:app:details")