diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml index 1a40cb0..f9ff3bf 100644 --- a/.github/workflows/ruby.yml +++ b/.github/workflows/ruby.yml @@ -7,11 +7,7 @@ name: Tests -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] +on: [push, pull_request] permissions: contents: read @@ -23,13 +19,14 @@ jobs: strategy: matrix: ruby-version: ['3.1', '3.2', '3.3'] + rails-version: ['gemfiles/rails_7.0.gemfile', 'gemfiles/rails_7.1.gemfile'] + + env: + BUNDLE_GEMFILE: ${{ matrix.rails-version }} steps: - uses: actions/checkout@v3 - name: Set up Ruby - # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, - # change this to (see https://github.com/ruby/setup-ruby#versioning): - # uses: ruby/setup-ruby@v1 uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} diff --git a/Appraisals b/Appraisals new file mode 100644 index 0000000..6548bad --- /dev/null +++ b/Appraisals @@ -0,0 +1,7 @@ +appraise "rails-7.0" do + gem "rails", "~> 7.0.0" +end + +appraise "rails-7.1" do + gem "rails", "~> 7.1.0" +end diff --git a/Gemfile b/Gemfile index f1fe10a..e231bf5 100644 --- a/Gemfile +++ b/Gemfile @@ -12,3 +12,5 @@ gem "sqlite3" gem "debug", ">= 1.0.0" gem "rails-dom-testing" +gem "appraisal" + diff --git a/README.md b/README.md index 36b5bf1..ea12783 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Add the gem: ```bash -bundle add email_error_reporter && bundle install +bundle add email_error_reporter ``` and configure the email addresses that should receive an email in the case of an exception: @@ -28,16 +28,37 @@ All exceptions are reported automatically. No additional code required. Please consult the [official guides](https://guides.rubyonrails.org/error_reporting.html) for an introduction to the error reporting API. +## Optional configuration + +Set a custom from address. + +```ruby +# default: "no-reply@example.com" +config.email_error_reporter.from = "your-custom-email@example.com" +``` + +--- + +Disables the email reports for specific environments. + +```ruby +# e.g. in development.rb +# default: true +config.email_error_reporter.enabled = false +``` + ## Test your setup You can use the built-in rake task `rake email_error_reporter:check` to check if everything works correctly in your setup. If you're using Kamal, you can run the following command to test the setup in production: -``` +```sh kamal app exec -p 'bundle exec rake email_error_reporter:test_email' ``` +If everything is setup correctly, this rake task will send a demo email to your configured `to` address with a sample exception. + ## License The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). diff --git a/email_error_reporter.gemspec b/email_error_reporter.gemspec index 72c9a47..a10548b 100644 --- a/email_error_reporter.gemspec +++ b/email_error_reporter.gemspec @@ -22,5 +22,6 @@ Gem::Specification.new do |spec| Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] end - spec.add_dependency "rails", ">= 7.1.2" + spec.required_ruby_version = '>= 3.1.0' + spec.add_dependency "rails", ">= 7.0.0" end diff --git a/gemfiles/rails_7.0.gemfile b/gemfiles/rails_7.0.gemfile new file mode 100644 index 0000000..ec6188e --- /dev/null +++ b/gemfiles/rails_7.0.gemfile @@ -0,0 +1,12 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "puma" +gem "sqlite3" +gem "debug", ">= 1.0.0" +gem "rails-dom-testing" +gem "appraisal", group: :development +gem "rails", "~> 7.0.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.1.gemfile b/gemfiles/rails_7.1.gemfile new file mode 100644 index 0000000..1cce9dc --- /dev/null +++ b/gemfiles/rails_7.1.gemfile @@ -0,0 +1,12 @@ +# This file was generated by Appraisal + +source "https://rubygems.org/" + +gem "puma" +gem "sqlite3" +gem "debug", ">= 1.0.0" +gem "rails-dom-testing" +gem "appraisal", group: :development +gem "rails", "~> 7.1.0" + +gemspec path: "../" diff --git a/lib/email_error_reporter/engine.rb b/lib/email_error_reporter/engine.rb index b914d07..d6a2ea4 100644 --- a/lib/email_error_reporter/engine.rb +++ b/lib/email_error_reporter/engine.rb @@ -4,9 +4,13 @@ class Engine < ::Rails::Engine config.email_error_reporter = ActiveSupport::OrderedOptions.new config.email_error_reporter.to = [] + config.email_error_reporter.from = "no-reply@example.com" + config.email_error_reporter.enabled = true - initializer "email_error_reporter.error_subscribe" do - Rails.error.subscribe(Subscriber.new) + initializer "email_error_reporter.error_subscribe" do |app| + if app.config.email_error_reporter.enabled + Rails.error.subscribe(Subscriber.new) + end end # ActiveJob cannot (de)-serialize exceptions by default diff --git a/lib/email_error_reporter/error_mailer.rb b/lib/email_error_reporter/error_mailer.rb index c560523..0df2c2a 100644 --- a/lib/email_error_reporter/error_mailer.rb +++ b/lib/email_error_reporter/error_mailer.rb @@ -17,6 +17,7 @@ def error(error, handled:, severity:, context:, source: nil) mail( subject: "#{severity_to_emoji.fetch(@severity)} #{error.class}", + from: Rails.application.config.email_error_reporter.from, to: Rails.application.config.email_error_reporter.to ) end diff --git a/lib/email_error_reporter/version.rb b/lib/email_error_reporter/version.rb index b0651e7..917bf46 100644 --- a/lib/email_error_reporter/version.rb +++ b/lib/email_error_reporter/version.rb @@ -1,3 +1,3 @@ module EmailErrorReporter - VERSION = "0.1.0.pre" + VERSION = "0.3.0" end diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 5295e62..8dfe5e0 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -13,7 +13,8 @@ class Application < Rails::Application # Please, add to the `ignore` list any other `lib` subdirectories that do # not contain `.rb` files, or that should not be reloaded or eager loaded. # Common ones are `templates`, `generators`, or `middleware`, for example. - config.autoload_lib(ignore: %w(assets tasks)) + + # config.autoload_lib(ignore: %w(assets tasks)) # Configuration for the application, engines, and railties goes here. # diff --git a/test/dummy/config/environments/development.rb b/test/dummy/config/environments/development.rb index 84e2859..21a448d 100644 --- a/test/dummy/config/environments/development.rb +++ b/test/dummy/config/environments/development.rb @@ -72,7 +72,7 @@ # config.action_cable.disable_request_forgery_protection = true # Raise error when a before_action's only/except options reference missing actions - config.action_controller.raise_on_missing_callback_actions = true + # config.action_controller.raise_on_missing_callback_actions = true config.email_error_reporter.to = ["test@example.com"] end diff --git a/test/dummy/config/environments/test.rb b/test/dummy/config/environments/test.rb index ee40759..afe54f6 100644 --- a/test/dummy/config/environments/test.rb +++ b/test/dummy/config/environments/test.rb @@ -60,7 +60,7 @@ # config.action_view.annotate_rendered_view_with_filenames = true # Raise error when a before_action's only/except options reference missing actions - config.action_controller.raise_on_missing_callback_actions = true + # config.action_controller.raise_on_missing_callback_actions = true config.email_error_reporter.to = ["test@example.com"] end diff --git a/test/subscriber_test.rb b/test/subscriber_test.rb index c9c4fbd..ce3df2c 100644 --- a/test/subscriber_test.rb +++ b/test/subscriber_test.rb @@ -11,13 +11,53 @@ class SubscriberTest < ActiveSupport::TestCase end rescue TestError => e - assert_enqueued_email_with EmailErrorReporter::ErrorMailer, :error, args: ->(args) { - # TODO: find out, why args.first == e is false - [ - args.first.message == e.message, - args.first.backtrace == e.backtrace, - args.first.class == e.class - ].all? - } + # matcher + assert_enqueued_with( + job: ActionMailer::MailDeliveryJob, + args: ->(j) { + [ + "EmailErrorReporter::ErrorMailer" == j[0], + "error" == j[1], + "deliver_now" == j[2], + e.class == j[3][:args][0].class, + { handled: false, context: {}, severity: :error, source: rails_default_source } == j[3][:args][1], + ].all? + } + ) + end + + test "enqueues no mail if disabled" do + old_config = Rails.application.config.email_error_reporter.enabled + Rails.application.config.email_error_reporter.enabled = false + Rails.error.record(TestError) do + raise TestError + end + + rescue TestError => e + # matcher + assert_enqueued_with( + job: ActionMailer::MailDeliveryJob, + args: ->(j) { + [ + "EmailErrorReporter::ErrorMailer" == j[0], + "error" == j[1], + "deliver_now" == j[2], + e.class == j[3][:args][0].class, + { handled: false, context: {}, severity: :error, source: rails_default_source } == j[3][:args][1], + ].all? + } + ) + ensure + Rails.application.config.email_error_reporter.enabled = old_config + end + + private + + def rails_default_source + if Gem::Version.new(Rails.version) >= Gem::Version.new("7.1.0") + "application" + else + nil + end end end