diff --git a/CHANGELOG.md b/CHANGELOG.md index 35a6062..0205827 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +## [3.6.0] - 2022-05-27 +### Added +- Added `notification_prefix` and `notification_suffix` to configuration options +- Linked to docs/usage.md in README + +### Changed +- Refactored `Patches::Notifier` +- `Patches::Notifier.append_tenant_message` effectively replaced by `tenant_suffix` + ## [3.5.0] - 2020-07-22 ### Added - Enable application version constraint support on `Patches::TenantWorker` diff --git a/README.md b/README.md index 6ba9c4d..9820f08 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ A simple gem for one off tasks ## Version 2.0 -Please note the breaking change release around deployment. See docs/usage.md for the full change. +Please note the breaking change release around deployment. See [docs/usage.md](docs/usage.md) for the full change. TL;DR You need to manually declare the patches task to run in your deploy.rb @@ -32,7 +32,7 @@ Or install it yourself as: ## Usage -see `docs/usage.md` +see [docs/usage.md](docs/usage.md) ## Development diff --git a/docs/usage.md b/docs/usage.md index 6cd8bf4..7ccc040 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -39,6 +39,15 @@ Patches::Config.configure do |config| end ``` +Additionally, you can override the default prefix and suffix of the +notification message in the patches config: + +```ruby + # for example + config.notification_prefix = "#{Tenant.current.name}-#{Rails.env}" # => [READYTECH-STAGING] + config.notification_suffix = Tenant.current.name # => ... patches succeeded for Readytech +``` + ### Running patches in parallel for tenants If you are using the Apartment gem, you can run the patches for each tenant in parallel. diff --git a/lib/patches/config.rb b/lib/patches/config.rb index c307898..4a08776 100644 --- a/lib/patches/config.rb +++ b/lib/patches/config.rb @@ -16,6 +16,8 @@ def configure class Configuration attr_accessor \ :application_version, + :notification_prefix, + :notification_suffix, :retry_after_version_mismatch_in, :sidekiq_options, :sidekiq_parallel, diff --git a/lib/patches/notifier.rb b/lib/patches/notifier.rb index 2f84bc1..f2ec0ef 100644 --- a/lib/patches/notifier.rb +++ b/lib/patches/notifier.rb @@ -11,23 +11,32 @@ def notify_failure(patch_path, error) end def success_message(patches) - message = "#{environment_prefix}#{patches.count} patches succeeded" - append_tenant_message(message) + message(patches.count, "patches succeeded") end def failure_message(patch_path, error) - details = "#{Pathname.new(patch_path).basename} failed with error: #{error}" - message = "#{environment_prefix}Error applying patch: #{details}" - append_tenant_message(message) + message("Error applying patch:", Pathname.new(patch_path).basename, "failed with error:", error) + end + + def message(*args) + [notification_prefix, *args, notification_suffix].compact.join(" ") + end + + def notification_prefix + prefix = config.notification_prefix.presence || environment_prefix + "[#{prefix}]" if prefix.present? end def environment_prefix - "[#{Rails.env.upcase}] " if defined?(Rails) + Rails.env.upcase if defined?(Rails) + end + + def notification_suffix + config.notification_suffix.presence || tenant_suffix end - def append_tenant_message(message) - message = message + " for tenant: #{Apartment::Tenant.current}" if defined?(Apartment) - message + def tenant_suffix + "for tenant: #{Apartment::Tenant.current}" if defined?(Apartment) end def send_slack_message(message, color) diff --git a/lib/patches/version.rb b/lib/patches/version.rb index 38b94bc..00a4729 100644 --- a/lib/patches/version.rb +++ b/lib/patches/version.rb @@ -1,6 +1,6 @@ module Patches MAJOR = 3 - MINOR = 5 + MINOR = 6 PATCH = 0 VERSION = [MAJOR, MINOR, PATCH].compact.join(".").freeze end diff --git a/spec/notifier_spec.rb b/spec/notifier_spec.rb index c50a71e..5a1f8a5 100644 --- a/spec/notifier_spec.rb +++ b/spec/notifier_spec.rb @@ -4,12 +4,173 @@ let(:notifier) { described_class } let(:message) { 'This is a message' } - describe '#send_slack_message' do - let(:options) { 'good' } + let(:dummy_tenant_class) do + Class.new do + def self.current + "generic tenant" + end + end + end + + before do + stub_const("Apartment::Tenant", dummy_tenant_class) + Patches::Config.configuration = nil + end + + describe ".notify_success" do + subject { notifier.notify_success(patches) } + + let(:patches) { %w(one two three) } + let(:message) { "[DEVELOPMENT] 3 patches succeeded for tenant: generic tenant" } + + before do + allow(notifier).to receive(:send_slack_message) + end + + it "sends successful slack message" do + subject + expect(notifier).to have_received(:send_slack_message).with(message, "good") + end + end + + describe ".notify_failure" do + subject { notifier.notify_failure(patch_path, error) } + + let(:patch_path) { "/path/to/my_special_patch.rb" } + let(:error) { "Something crazy" } + let(:message) { "[DEVELOPMENT] Error applying patch: my_special_patch.rb failed with error: Something crazy for tenant: generic tenant" } + + before do + allow(notifier).to receive(:send_slack_message) + end + + it "sends failure slack message" do + subject + expect(notifier).to have_received(:send_slack_message).with(message, "danger") + end + end + + describe ".success_message" do + subject { notifier.success_message(patches) } + + let(:patches) { %w(one two three) } + let(:message) { "[DEVELOPMENT] 3 patches succeeded for tenant: generic tenant" } + + it "generates success message" do + expect(subject).to eq(message) + end + end + + describe ".failure_message" do + subject { notifier.failure_message(patch_path, error) } + + let(:patch_path) { "/path/to/my_special_patch.rb" } + let(:error) { "Something crazy" } + let(:message) { "[DEVELOPMENT] Error applying patch: my_special_patch.rb failed with error: Something crazy for tenant: generic tenant" } + + it "generates failure message" do + expect(subject).to eq(message) + end + end + + describe ".message" do + subject { notifier.message(arg_1, arg_2, agr_3) } + + let(:arg_1) { "This" } + let(:arg_2) { "is a" } + let(:agr_3) { "message" } + + before do + allow(notifier).to receive(:notification_prefix).and_return(notification_prefix) + allow(notifier).to receive(:notification_suffix).and_return(notification_suffix) + end + + context "without notification_prefix" do + let(:notification_prefix) { nil } + let(:notification_suffix) { "[SUFFIX]" } + + it "joins all elements except the prefix" do + expect(subject).to eq("This is a message [SUFFIX]") + end + end + + context "without notification_suffix" do + let(:notification_prefix) { "[PREFIX]" } + let(:notification_suffix) { nil } + + it "joins all elements except the suffix" do + expect(subject).to eq("[PREFIX] This is a message") + end + end + + context "with notification_prefix and notification_suffix" do + let(:notification_prefix) { "[PREFIX]" } + let(:notification_suffix) { "[SUFFIX]" } + + it "joins all elements" do + expect(subject).to eq("[PREFIX] This is a message [SUFFIX]") + end + end + end + + describe ".notification_prefix" do + subject { notifier.notification_prefix } + + before do + Patches::Config.configure do |config| + config.notification_prefix = notification_prefix + end + end + + context "where notification_prefix config specified" do + let(:notification_prefix) { "Explicit Prefix" } + + it "is that prefix" do + expect(subject).to eq("[Explicit Prefix]") + end + end + + context "where notification_prefix config not specified" do + let(:notification_prefix) { nil } + + it "defaults to Rails.env" do + expect(subject).to eq("[DEVELOPMENT]") + end + end + end + + describe ".notification_suffix" do + subject { notifier.notification_suffix } + + before do + Patches::Config.configure do |config| + config.notification_suffix = notification_suffix + end + end + + context "where notification_suffix config specified" do + let(:notification_suffix) { "Explicit suffix" } + + it "is that suffix" do + expect(subject).to eq("Explicit suffix") + end + end + + context "where notification_suffix config not specified" do + let(:notification_suffix) { nil } + + it "defaults to tenant suffix" do + expect(subject).to eq("for tenant: generic tenant") + end + end + end + + describe '.send_slack_message' do subject { notifier.send_slack_message(message, options) } + let(:options) { 'good' } + before do - Patches::Config.configuration = nil Patches::Config.configure do |config| config.use_slack = use_slack config.slack_options = { diff --git a/spec/runner_spec.rb b/spec/runner_spec.rb index 9eb62b2..8c37f15 100644 --- a/spec/runner_spec.rb +++ b/spec/runner_spec.rb @@ -18,7 +18,7 @@ expect(Patches::Notifier).to receive(:notify_failure) expect { Patches::Runner.new.perform - }.to raise_error + }.to raise_error(RuntimeError) end end diff --git a/spec/tenant_runner_spec.rb b/spec/tenant_runner_spec.rb index cdba9c2..c456732 100644 --- a/spec/tenant_runner_spec.rb +++ b/spec/tenant_runner_spec.rb @@ -14,6 +14,7 @@ module Tenant let(:application_version) { 'd8f190c' } before do + Patches::Config.configuration = nil Sidekiq::Testing.fake! allow(Patches).to receive(:default_path).and_return('') allow(Patches::Config.configuration).to receive(:application_version) { application_version }