diff --git a/.coveralls.yml b/.coveralls.yml deleted file mode 100644 index 901a8ae..0000000 --- a/.coveralls.yml +++ /dev/null @@ -1,2 +0,0 @@ -service_name: travis-pro -repo_token: gNB8KeAdYQKNW2YC4uut6Zh2ToBnPyMqB diff --git a/.github/workflows/actionlint.yml b/.github/workflows/actionlint.yml new file mode 100644 index 0000000..cd283b5 --- /dev/null +++ b/.github/workflows/actionlint.yml @@ -0,0 +1,39 @@ +name: Action Lint + +on: + push: + branches: + - master + pull_request: + branches: + - master + schedule: + - cron: "0 21 * * 6" + +permissions: + contents: read + +jobs: + actionlint: + runs-on: ubuntu-24.04 + + steps: + - uses: actions/checkout@v4 + + - uses: raven-actions/actionlint@v2 + id: actionlint + with: + pyflakes: false + + - name: actionlint Summary + if: ${{ steps.actionlint.outputs.exit-code != 0 }} + run: | + echo "Used actionlint version ${{ steps.actionlint.outputs.version-semver }}" + echo "Used actionlint release ${{ steps.actionlint.outputs.version-tag }}" + echo "actionlint ended with ${{ steps.actionlint.outputs.exit-code }} exit code" + echo "actionlint ended because '${{ steps.actionlint.outputs.exit-message }}'" + echo "actionlint found ${{ steps.actionlint.outputs.total-errors }} errors" + echo "actionlint checked ${{ steps.actionlint.outputs.total-files }} files" + echo "actionlint cache used: ${{ steps.actionlint.outputs.cache-hit }}" + # shellcheck disable=SC2242 + exit ${{ steps.actionlint.outputs.exit-code }} diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml new file mode 100644 index 0000000..ef1c6a0 --- /dev/null +++ b/.github/workflows/rspec.yml @@ -0,0 +1,34 @@ +name: RSpec + +on: + push: + branches: + - master + pull_request: + branches: + - master + schedule: + - cron: "0 21 * * 6" + +jobs: + rspec: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + ruby: ["3.1", "3.2", "3.3", "3.4"] + + steps: + - uses: actions/checkout@v4 + - run: rm -f Gemfile.lock + - run: rm -f .ruby-version + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + rubygems: latest + bundler: latest + bundler-cache: true + + - run: bundle exec rspec diff --git a/.gitignore b/.gitignore index 9c779e8..9863661 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ .bundle .config .yardoc -Gemfile.lock InstalledFiles _yardoc coverage @@ -15,9 +14,6 @@ spec/reports test/tmp test/version_tmp tmp -.ruby-version -# YARD artifacts -.yardoc -_yardoc -doc/ +.idea +.rspec_status diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..6c6110e --- /dev/null +++ b/.rspec @@ -0,0 +1,4 @@ +--format documentation +--color +--require spec_helper +--order random diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..e29afdd --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,15 @@ +AllCops: + TargetRubyVersion: 3.1 + NewCops: enable + +Style/StringLiterals: + Enabled: true + EnforcedStyle: double_quotes + ConsistentQuotesInMultiline: false + +Bundler/OrderedGems: + Enabled: false + +Style/SingleLineMethods: + Enabled: true + AllowIfMethodIsEmpty: false diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..9cec716 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.1.6 diff --git a/.standard.yml b/.standard.yml new file mode 100644 index 0000000..72b2693 --- /dev/null +++ b/.standard.yml @@ -0,0 +1 @@ +ruby_version: 3.1 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b41822f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: ruby -env: - - COVERAGE=true -before_install: - - gem install bundler -script: bundle exec rspec spec -rvm: - - 2.1 - - 2.2 - - 2.3.0 - - rbx-2 - - ruby-head -matrix: - allow_failures: - - rvm: ruby-head diff --git a/Gemfile b/Gemfile index 7eb2841..e92d854 100644 --- a/Gemfile +++ b/Gemfile @@ -1,9 +1,11 @@ -source 'https://rubygems.org' +# frozen_string_literal: true + +source "https://rubygems.org" # Specify your gem's dependencies in errbit_plugin.gemspec gemspec -gem 'rspec' -gem 'guard' -gem 'guard-rspec' -gem 'coveralls', :require => false +gem "rake" +gem "rspec" +gem "standard" +gem "simplecov", require: false diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..a154c18 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,251 @@ +PATH + remote: . + specs: + errbit_plugin (0.7.0) + railties (>= 6.1.0) + +GEM + remote: https://rubygems.org/ + specs: + actionpack (7.2.2.1) + actionview (= 7.2.2.1) + activesupport (= 7.2.2.1) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4, < 3.2) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actionview (7.2.2.1) + activesupport (= 7.2.2.1) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activesupport (7.2.2.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + ast (2.4.2) + base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.9) + builder (3.3.0) + concurrent-ruby (1.3.5) + connection_pool (2.5.0) + crass (1.0.6) + date (3.4.1) + diff-lcs (1.6.0) + docile (1.4.1) + drb (2.2.1) + erubi (1.13.1) + i18n (1.14.7) + concurrent-ruby (~> 1.0) + io-console (0.8.0) + irb (1.15.1) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + json (2.10.2) + language_server-protocol (3.17.0.4) + lint_roller (1.1.0) + logger (1.6.6) + loofah (2.24.0) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + minitest (5.25.5) + nokogiri (1.18.5-arm64-darwin) + racc (~> 1.4) + parallel (1.26.3) + parser (3.3.7.1) + ast (~> 2.4.1) + racc + pp (0.6.2) + prettyprint + prettyprint (0.2.0) + psych (5.2.3) + date + stringio + racc (1.8.1) + rack (3.1.12) + rack-session (2.1.0) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) + rackup (2.2.1) + rack (>= 3) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.2) + loofah (~> 2.21) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) + irb (~> 1.13) + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) + rainbow (3.1.1) + rake (13.2.1) + rdoc (6.12.0) + psych (>= 4.0.0) + regexp_parser (2.10.0) + reline (0.6.0) + io-console (~> 0.5) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.3) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.2) + rubocop (1.73.2) + json (~> 2.3) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.1.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.38.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.39.0) + parser (>= 3.3.1.0) + rubocop-performance (1.24.0) + lint_roller (~> 1.1) + rubocop (>= 1.72.1, < 2.0) + rubocop-ast (>= 1.38.0, < 2.0) + ruby-progressbar (1.13.0) + securerandom (0.4.1) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.13.1) + simplecov_json_formatter (0.1.4) + standard (1.47.0) + language_server-protocol (~> 3.17.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.73.0) + standard-custom (~> 1.0.0) + standard-performance (~> 1.7) + standard-custom (1.0.2) + lint_roller (~> 1.0) + rubocop (~> 1.50) + standard-performance (1.7.0) + lint_roller (~> 1.1) + rubocop-performance (~> 1.24.0) + stringio (3.1.5) + thor (1.3.2) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) + useragent (0.16.11) + zeitwerk (2.6.18) + +PLATFORMS + arm64-darwin + +DEPENDENCIES + errbit_plugin! + rake + rspec + simplecov + standard + +CHECKSUMS + actionpack (7.2.2.1) sha256=17b2160a7bcbd5a569d06b1ae54a4bb5ccc7ba0815d73ff5768100a79dc1f734 + actionview (7.2.2.1) sha256=69fc880cf3d8b1baf21b048cf7bb68f1eef08760ff8104d7d60a6a1be8b359a5 + activesupport (7.2.2.1) sha256=842bcbf8a92977f80fb4750661a237cf5dd4fdd442066b3c35e88afb488647f5 + ast (2.4.2) sha256=1e280232e6a33754cde542bc5ef85520b74db2aac73ec14acef453784447cc12 + base64 (0.2.0) sha256=0f25e9b21a02a0cc0cea8ef92b2041035d39350946e8789c562b2d1a3da01507 + benchmark (0.4.0) sha256=0f12f8c495545e3710c3e4f0480f63f06b4c842cc94cec7f33a956f5180e874a + bigdecimal (3.1.9) sha256=2ffc742031521ad69c2dfc815a98e426a230a3d22aeac1995826a75dabfad8cc + builder (3.3.0) sha256=497918d2f9dca528fdca4b88d84e4ef4387256d984b8154e9d5d3fe5a9c8835f + concurrent-ruby (1.3.5) sha256=813b3e37aca6df2a21a3b9f1d497f8cbab24a2b94cab325bffe65ee0f6cbebc6 + connection_pool (2.5.0) sha256=233b92f8d38e038c1349ccea65dd3772727d669d6d2e71f9897c8bf5cd53ebfc + crass (1.0.6) sha256=dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d + date (3.4.1) sha256=bf268e14ef7158009bfeaec40b5fa3c7271906e88b196d958a89d4b408abe64f + diff-lcs (1.6.0) sha256=a1e7f7b272962f8fc769358ad00001b87cdcf32ba349d6c70c6b544613d2da2e + docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e + drb (2.2.1) sha256=e9d472bf785f558b96b25358bae115646da0dbfd45107ad858b0bc0d935cb340 + errbit_plugin (0.7.0) + erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9 + i18n (1.14.7) sha256=ceba573f8138ff2c0915427f1fc5bdf4aa3ab8ae88c8ce255eb3ecf0a11a5d0f + io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2 + irb (1.15.1) sha256=d9bca745ac4207a8b728a52b98b766ca909b86ff1a504bcde3d6f8c84faae890 + json (2.10.2) sha256=34e0eada93022b2a0a3345bb0b5efddb6e9ff5be7c48e409cfb54ff8a36a8b06 + language_server-protocol (3.17.0.4) sha256=c484626478664fd13482d8180947c50a8590484b1258b99b7aedb3b69df89669 + lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87 + logger (1.6.6) sha256=dd618d24e637715472732e7eed02e33cfbdf56deaad225edd0f1f89d38024017 + loofah (2.24.0) sha256=61e6a710883abb8210887f3dc868cf3ed66594c509d9ff6987621efa6651ee1e + minitest (5.25.5) sha256=391b6c6cb43a4802bfb7c93af1ebe2ac66a210293f4a3fb7db36f2fc7dc2c756 + nokogiri (1.18.5-arm64-darwin) sha256=df7731e550a7653c003ed142cc8bc3c611c15fae3b7be4ff317b61dfe32842d9 + parallel (1.26.3) sha256=d86babb7a2b814be9f4b81587bf0b6ce2da7d45969fab24d8ae4bf2bb4d4c7ef + parser (3.3.7.1) sha256=7dbe61618025519024ac72402a6677ead02099587a5538e84371b76659e6aca1 + pp (0.6.2) sha256=947ec3120c6f92195f8ee8aa25a7b2c5297bb106d83b41baa02983686577b6ff + prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193 + psych (5.2.3) sha256=84a54bb952d14604fea22d99938348814678782f58b12648fcdfa4d2fce859ee + racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f + rack (3.1.12) sha256=00d83055c89273eb13679ab562767b8826955aa6c4371d7d161deb975c50c540 + rack-session (2.1.0) sha256=437c3916535b58ef71c816ce4a2dee0a01c8a52ae6077dc2b6cd19085760a290 + rack-test (2.2.0) sha256=005a36692c306ac0b4a9350355ee080fd09ddef1148a5f8b2ac636c720f5c463 + rackup (2.2.1) sha256=f737191fd5c5b348b7f0a4412a3b86383f88c43e13b8217b63d4c8d90b9e798d + rails-dom-testing (2.2.0) sha256=e515712e48df1f687a1d7c380fd7b07b8558faa26464474da64183a7426fa93b + rails-html-sanitizer (1.6.2) sha256=35fce2ca8242da8775c83b6ba9c1bcaad6751d9eb73c1abaa8403475ab89a560 + railties (7.2.2.1) sha256=e3f11bf116dd6d0d874522843ccc70ec0f89fbfed3e9c2ee48a4778cd042fe1f + rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a + rake (13.2.1) sha256=46cb38dae65d7d74b6020a4ac9d48afed8eb8149c040eccf0523bec91907059d + rdoc (6.12.0) sha256=7d6f706e070bffa5d18a448f24076cbfb34923a99c1eab842aa18e6ca69f56e0 + regexp_parser (2.10.0) sha256=cb6f0ddde88772cd64bff1dbbf68df66d376043fe2e66a9ef77fcb1b0c548c61 + reline (0.6.0) sha256=57620375dcbe56ec09bac7192bfb7460c716bbf0054dc94345ecaa5438e539d2 + rspec (3.13.0) sha256=d490914ac1d5a5a64a0e1400c1d54ddd2a501324d703b8cfe83f458337bab993 + rspec-core (3.13.3) sha256=25136507f4f9cf2e8977a2851e64e438b4331646054e345998714108745cdfe4 + rspec-expectations (3.13.3) sha256=0e6b5af59b900147698ea0ff80456c4f2e69cac4394fbd392fbd1ca561f66c58 + rspec-mocks (3.13.2) sha256=2327335def0e1665325a9b617e3af9ae20272741d80ac550336309a7c59abdef + rspec-support (3.13.2) sha256=cea3a2463fd9b84b9dcc9685efd80ea701aa8f7b3decb3b3ce795ed67737dbec + rubocop (1.73.2) sha256=35cd1b1365ba97234323fe771abcecd09c9b77098464cd726c76aa7d9bc12b5d + rubocop-ast (1.39.0) sha256=b6ba0f677ceced033b81c69405ac8931f4963116c572b8da5e15a03619a8236c + rubocop-performance (1.24.0) sha256=e5bd39ff3e368395b9af886927cc37f5892f43db4bd6c8526594352d5b4440b5 + ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33 + securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1 + simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5 + simplecov-html (0.13.1) sha256=5dab0b7ee612e60e9887ad57693832fdf4695b4c0c859eaea5f95c18791ef10b + simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428 + standard (1.47.0) sha256=b0da6b71d8dec53e760c7216b723e3507ebdcd6962f7ce7c37c016a36c7cc190 + standard-custom (1.0.2) sha256=424adc84179a074f1a2a309bb9cf7cd6bfdb2b6541f20c6bf9436c0ba22a652b + standard-performance (1.7.0) sha256=c46a9aef3348c0cfc03053ed9a1c1f73b967f7e4edcdf30dac0101b143897314 + stringio (3.1.5) sha256=bca92461515a131535743bc81d5559fa1de7d80cff9a654d6c0af6f9f27e35c8 + thor (1.3.2) sha256=eef0293b9e24158ccad7ab383ae83534b7ad4ed99c09f96f1a6b036550abbeda + tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b + unicode-display_width (3.1.4) sha256=8caf2af1c0f2f07ec89ef9e18c7d88c2790e217c482bfc78aaa65eadd5415ac1 + unicode-emoji (4.0.4) sha256=2c2c4ef7f353e5809497126285a50b23056cc6e61b64433764a35eff6c36532a + useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844 + zeitwerk (2.6.18) sha256=bd2d213996ff7b3b364cd342a585fbee9797dbc1c0c6d868dc4150cc75739781 + +BUNDLED WITH + 2.6.6 diff --git a/Guardfile b/Guardfile deleted file mode 100644 index 3a3ce84..0000000 --- a/Guardfile +++ /dev/null @@ -1,8 +0,0 @@ -# A sample Guardfile -# More info at https://github.com/guard/guard#readme - -guard 'rspec' do - watch(%r{^spec/.+_spec\.rb$}) - watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } - watch('spec/spec_helper.rb') { "spec" } -end diff --git a/README.md b/README.md index d575f0e..b586790 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ -# ErrbitPlugin [![Build Status](https://travis-ci.org/errbit/errbit_plugin.svg?branch=master)](https://travis-ci.org/errbit/errbit_plugin) +# ErrbitPlugin + ErrbitPlugin provides a set of base classes that you can extend to create Errbit plugins. ## Creating plugins + ErrbitPlugins are Ruby gems that extend the functionality of Errbit. To get started, create a Ruby gem and add 'errbit_plugin' as a dependency in your gem's gemspec. @@ -11,28 +13,29 @@ Now you can start adding plugins. At the moment, there is only one kind of plugin you can create, and that is the issue tracker. ### Issue Trackers + An issue tracker plugin is a Ruby class that enables you to link errors within -errbit to an issue in an external issue tracker like Github. An app within +errbit to an issue in an external issue tracker like GitHub. An app within errbit can be associated an issue tracker or not. When there is an association, errbit users can choose 'create issue' from an error page which will both create an issue on the external issue tracker out of the given error and link that issue to the errbit error. Likewise, a user can also choose 'close issue' -to close the issue on the external issue tracker, if your plugin provides a +to close the issue on the external issue tracker, if your plugin provides a method to do so. Your issue tracker plugin is responsible for providing the interface defined by ErrbitPlugin::IssueTracker. All of the required methods must be implemented and the class must extend ErrbitPlugin::IssueTracker. Here's an example: + ```ruby class MyIssueTracker < ErrbitPlugin::IssueTracker - # A unique label for your tracker plugin used internally by errbit def self.label - 'my-tracker' + "my-tracker" end def self.note - 'a note about this tracker that users will see' + "a note about this tracker that users will see" end # Form fields that will be presented to the administrator when setting up @@ -56,9 +59,9 @@ class MyIssueTracker < ErrbitPlugin::IssueTracker # and the binary icon data. def self.icons @icons ||= { - create: [ 'image/png', File.read('./path/to/create.png') ], - goto: [ 'image/png', File.read('./path/to/goto.png') ], - inactive: [ 'image/png', File.read('./path/to/inactive.png') ], + create: ["image/png", File.read("./path/to/create.png")], + goto: ["image/png", File.read("./path/to/goto.png")], + inactive: ["image/png", File.read("./path/to/inactive.png")], } end @@ -76,7 +79,7 @@ class MyIssueTracker < ErrbitPlugin::IssueTracker if options[:username] {} else - { field_one: 'username must be present' } + {field_one: "username must be present"} end end @@ -88,7 +91,7 @@ class MyIssueTracker < ErrbitPlugin::IssueTracker def create_issue(title, body, user: {}) # Create an issue! Then update the problem to link it. - 'http://sometracker.com/my/issue/123' + "https://sometracker.com/my/issue/123" end # This method is optional. Errbit will create body text for your issue by @@ -103,7 +106,7 @@ class MyIssueTracker < ErrbitPlugin::IssueTracker # @see http://apidock.com/rails/ActionController/Base/render_to_string def render_body_args # In this example, we want to render a special file - ['/path/to/some/template', formats: [:rdoc]] + ["/path/to/some/template", formats: [:rdoc]] end # This method is optional, and is where you actually go close the issue on @@ -117,14 +120,12 @@ class MyIssueTracker < ErrbitPlugin::IssueTracker # The URL for your remote issue tracker def url - 'http://some-remote-tracker.com' + "https://some-remote-tracker.com" end end ``` - - ## Contributing Discuss any changes you'd like to make with the authors on the mailing list, or -by opening a github issue. +by opening a GitHub issue. diff --git a/Rakefile b/Rakefile index 2995527..5263b58 100644 --- a/Rakefile +++ b/Rakefile @@ -1 +1,3 @@ +# frozen_string_literal: true + require "bundler/gem_tasks" diff --git a/app/assets/config/errbit_plugin.js b/app/assets/config/errbit_plugin.js new file mode 100644 index 0000000..ac907b3 --- /dev/null +++ b/app/assets/config/errbit_plugin.js @@ -0,0 +1 @@ +//= link_tree ../images diff --git a/static/fake_create.png b/app/assets/images/errbit_plugin/fake_create.png similarity index 100% rename from static/fake_create.png rename to app/assets/images/errbit_plugin/fake_create.png diff --git a/static/fake_inactive.png b/app/assets/images/errbit_plugin/fake_inactive.png similarity index 100% rename from static/fake_inactive.png rename to app/assets/images/errbit_plugin/fake_inactive.png diff --git a/static/none_create.png b/app/assets/images/errbit_plugin/none_create.png similarity index 100% rename from static/none_create.png rename to app/assets/images/errbit_plugin/none_create.png diff --git a/static/none_inactive.png b/app/assets/images/errbit_plugin/none_inactive.png similarity index 100% rename from static/none_inactive.png rename to app/assets/images/errbit_plugin/none_inactive.png diff --git a/errbit_plugin.gemspec b/errbit_plugin.gemspec index c1ae05b..d48478c 100644 --- a/errbit_plugin.gemspec +++ b/errbit_plugin.gemspec @@ -1,23 +1,41 @@ -# coding: utf-8 -lib = File.expand_path('../lib', __FILE__) +# frozen_string_literal: true + +lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'errbit_plugin/version' +require "errbit_plugin/version" Gem::Specification.new do |spec| - spec.name = "errbit_plugin" - spec.version = ErrbitPlugin::VERSION - spec.authors = ["Stephen Crosby"] - spec.email = ["stevecrozz@gmail.com"] - spec.description = %q{Base to create an errbit plugin} - spec.summary = %q{Base to create an errbit plugin} - spec.homepage = "http://github.com/errbit/errbit" - spec.license = "MIT" + spec.name = "errbit_plugin" + spec.version = ErrbitPlugin::VERSION + spec.authors = ["Stephen Crosby"] + spec.email = ["stevecrozz@gmail.com"] + + spec.description = "Base to create an Errbit plugin" + spec.summary = "Base to create an Errbit plugin" + spec.homepage = "https://github.com/errbit/errbit_plugin" + spec.license = "MIT" + + spec.required_ruby_version = ">= 3.1.0" + + spec.metadata["rubygems_mfa_required"] = "true" + spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues" + spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md" + spec.metadata["documentation_uri"] = "#{spec.homepage}/blob/master/README.md" + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = spec.homepage - spec.files = `git ls-files`.split($/) - spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } - spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + # Specify which files should be added to the gem when it is released. + # The `git ls-files -z` loads the files in the RubyGem that have been added into git. + gemspec = File.basename(__FILE__) + spec.files = IO.popen(%w[git ls-files -z], chdir: __dir__, err: IO::NULL) do |ls| + ls.readlines("\x0", chomp: true).reject do |f| + (f == gemspec) || + f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile]) + end + end + spec.bindir = "exe" + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - spec.add_development_dependency "bundler", "~> 1.3" - spec.add_development_dependency "rake" + spec.add_dependency "railties", ">= 6.1.0" end diff --git a/lib/errbit_plugin.rb b/lib/errbit_plugin.rb index fb7699b..1225c9d 100644 --- a/lib/errbit_plugin.rb +++ b/lib/errbit_plugin.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + require "errbit_plugin/version" +require "errbit_plugin/engine" require "errbit_plugin/registry" require "errbit_plugin/issue_tracker" -require "errbit_plugin/validate_issue_tracker" -require "errbit_plugin/issue_trackers/none" +require "errbit_plugin/issue_tracker_validator" +require "errbit_plugin/none_issue_tracker" diff --git a/lib/errbit_plugin/engine.rb b/lib/errbit_plugin/engine.rb new file mode 100644 index 0000000..6b3a5b2 --- /dev/null +++ b/lib/errbit_plugin/engine.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require "rails/engine" + +module ErrbitPlugin + class Engine < Rails::Engine + # :nocov: + initializer :assets do + Rails.application.config.assets.paths << root.join("app", "assets", "images", "errbit_plugin") + end + # :nocov: + end +end diff --git a/lib/errbit_plugin/issue_tracker.rb b/lib/errbit_plugin/issue_tracker.rb index 83b5131..78d4ced 100644 --- a/lib/errbit_plugin/issue_tracker.rb +++ b/lib/errbit_plugin/issue_tracker.rb @@ -1,10 +1,50 @@ +# frozen_string_literal: true + module ErrbitPlugin - # abstract class for issue trackers + # Abstract class for issue trackers class IssueTracker attr_reader :options def initialize(options) @options = options end + + def configured? + raise NoMethodError, "The ErrbitPlugin::IssueTracker#configured? method is abstract, an implementation of it must be provided in the subclass" + end + + def errors + raise NoMethodError, "The ErrbitPlugin::IssueTracker#errors method is abstract, an implementation of it must be provided in the subclass" + end + + def create_issue + raise NoMethodError, "The ErrbitPlugin::IssueTracker#create_issue method is abstract, an implementation of it must be provided in the subclass" + end + + def close_issue + raise NoMethodError, "The ErrbitPlugin::IssueTracker#close_issue method is abstract, an implementation of it must be provided in the subclass" + end + + def url + raise NoMethodError, "The ErrbitPlugin::IssueTracker#url method is abstract, an implementation of it must be provided in the subclass" + end + + class << self + def label + raise NoMethodError, "The ErrbitPlugin::IssueTracker.label method is abstract, an implementation of it must be provided in the subclass" + end + + def note + raise NoMethodError, "The ErrbitPlugin::IssueTracker.note method is abstract, an implementation of it must be provided in the subclass" + end + + def fields + raise NoMethodError, "The ErrbitPlugin::IssueTracker.fields method is abstract, an implementation of it must be provided in the subclass" + end + + def icons + raise NoMethodError, "The ErrbitPlugin::IssueTracker.icons method is abstract, an implementation of it must be provided in the subclass" + end + end end end diff --git a/lib/errbit_plugin/validate_issue_tracker.rb b/lib/errbit_plugin/issue_tracker_validator.rb similarity index 73% rename from lib/errbit_plugin/validate_issue_tracker.rb rename to lib/errbit_plugin/issue_tracker_validator.rb index 246934d..b811e44 100644 --- a/lib/errbit_plugin/validate_issue_tracker.rb +++ b/lib/errbit_plugin/issue_tracker_validator.rb @@ -1,10 +1,13 @@ +# frozen_string_literal: true + module ErrbitPlugin - class ValidateIssueTracker + class IssueTrackerValidator + attr_reader :errors + def initialize(klass) @klass = klass @errors = [] end - attr_reader :errors def valid? valid_inherit = good_inherit? @@ -17,20 +20,22 @@ def valid? private def good_inherit? - unless @klass.ancestors.include?(ErrbitPlugin::IssueTracker) + if @klass.ancestors.include?(ErrbitPlugin::IssueTracker) + true + else add_errors(:not_inherited) + false - else - true end end def implements_instance_methods? - impl = [:configured?, :errors, :create_issue, :url].map do |method| - if instance.respond_to?(method) + impl = [:configured?, :errors, :create_issue, :close_issue, :url].map do |method| + if @klass.instance_methods(false).include?(method) true else add_errors(:instance_method_missing, method) + false end end @@ -40,10 +45,11 @@ def implements_instance_methods? def implements_class_methods? impl = [:label, :fields, :note, :icons].map do |method| - if @klass.respond_to?(method) + if @klass.methods(false).include?(method) true else add_errors(:class_method_missing, method) + false end end @@ -51,11 +57,7 @@ def implements_class_methods? impl.all? { |value| value == true } end - def instance - @instance ||= @klass.new({}) - end - - def add_errors(key, value=nil) + def add_errors(key, value = nil) @errors << [key, value].compact end end diff --git a/lib/errbit_plugin/issue_trackers/none.rb b/lib/errbit_plugin/issue_trackers/none.rb deleted file mode 100644 index 6726ea5..0000000 --- a/lib/errbit_plugin/issue_trackers/none.rb +++ /dev/null @@ -1,31 +0,0 @@ -module ErrbitPlugin - class NoneIssueTracker < IssueTracker - def self.label; 'none'; end - def self.note - 'When no issue tracker has been configured, you will be able to ' << - 'leave comments on errors.' - end - def self.fields; {}; end - def self.icons - @icons ||= { - create: ['image/png', read_static_file('none_create.png')], - goto: ['image/png', read_static_file('none_create.png')], - inactive: ['image/png', read_static_file('none_inactive.png')], - } - end - def self.read_static_file(file) - File.read(File.expand_path(File.join( - File.dirname(__FILE__), '..', '..', '..', 'static', file))) - end - ## - # The NoneIssueTracker is mark like configured? false because it not valid - # like a real IssueTracker - def configured?; false; end - def errors; {}; end - def url; ''; end - def create_issue(*); false; end - def close_issue(*); false; end - end -end - -ErrbitPlugin::Registry.add_issue_tracker(ErrbitPlugin::NoneIssueTracker) diff --git a/lib/errbit_plugin/none_issue_tracker.rb b/lib/errbit_plugin/none_issue_tracker.rb new file mode 100644 index 0000000..8ccf249 --- /dev/null +++ b/lib/errbit_plugin/none_issue_tracker.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module ErrbitPlugin + class NoneIssueTracker < IssueTracker + def self.label + "none" + end + + def self.note + "When no issue tracker has been configured, you will be able to leave comments on errors." + end + + def self.fields + {} + end + + def self.icons + { + create: "none_create.png", + goto: "none_create.png", + inactive: "none_inactive.png" + } + end + + ## + # The NoneIssueTracker is mark like configured? false because it not valid + # like a real IssueTracker + def configured? + false + end + + def errors + {} + end + + def url + "" + end + + def create_issue(*) + false + end + + def close_issue(*) + false + end + end +end + +ErrbitPlugin::Registry.add_issue_tracker(ErrbitPlugin::NoneIssueTracker) diff --git a/lib/errbit_plugin/registry.rb b/lib/errbit_plugin/registry.rb index 1ab9519..083f928 100644 --- a/lib/errbit_plugin/registry.rb +++ b/lib/errbit_plugin/registry.rb @@ -1,6 +1,11 @@ +# frozen_string_literal: true + module ErrbitPlugin - class IncompatibilityError < StandardError; end - class AlreadyRegisteredError < StandardError; end + class IncompatibilityError < StandardError + end + + class AlreadyRegisteredError < StandardError + end module Registry @issue_trackers = {} @@ -13,12 +18,12 @@ def self.add_issue_tracker(klass) "issue_tracker '#{key}' already registered" end - validate = ValidateIssueTracker.new(klass) + validator = IssueTrackerValidator.new(klass) - if validate.valid? + if validator.valid? @issue_trackers[key] = klass else - raise IncompatibilityError.new(validate.errors.join('; ')) + raise IncompatibilityError.new(validator.errors.join("; ")) end end diff --git a/lib/errbit_plugin/version.rb b/lib/errbit_plugin/version.rb index 8729aef..9762eac 100644 --- a/lib/errbit_plugin/version.rb +++ b/lib/errbit_plugin/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ErrbitPlugin - VERSION = '0.6.0' + VERSION = "0.7.0" end diff --git a/spec/errbit_plugin/engine_spec.rb b/spec/errbit_plugin/engine_spec.rb new file mode 100644 index 0000000..07951ca --- /dev/null +++ b/spec/errbit_plugin/engine_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe ErrbitPlugin::Engine do + it { expect(described_class.ancestors).to include(Rails::Engine) } +end diff --git a/spec/errbit_plugin/issue_tracker_spec.rb b/spec/errbit_plugin/issue_tracker_spec.rb new file mode 100644 index 0000000..4aec2bc --- /dev/null +++ b/spec/errbit_plugin/issue_tracker_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe ErrbitPlugin::IssueTracker do + let(:options) { {} } + + subject { described_class.new(options) } + + describe "#options" do + it { expect(subject.options).to eq({}) } + end + + describe "#configured?" do + let(:message) { "The ErrbitPlugin::IssueTracker#configured? method is abstract, an implementation of it must be provided in the subclass" } + + it { expect { subject.configured? }.to raise_error(NoMethodError, message) } + end + + describe "#errors" do + let(:message) { "The ErrbitPlugin::IssueTracker#errors method is abstract, an implementation of it must be provided in the subclass" } + + it { expect { subject.errors }.to raise_error(NoMethodError, message) } + end + + describe "#create_issue" do + let(:message) { "The ErrbitPlugin::IssueTracker#create_issue method is abstract, an implementation of it must be provided in the subclass" } + + it { expect { subject.create_issue }.to raise_error(NoMethodError, message) } + end + + describe "#close_issue" do + let(:message) { "The ErrbitPlugin::IssueTracker#close_issue method is abstract, an implementation of it must be provided in the subclass" } + + it { expect { subject.close_issue }.to raise_error(NoMethodError, message) } + end + + describe "#url" do + let(:message) { "The ErrbitPlugin::IssueTracker#url method is abstract, an implementation of it must be provided in the subclass" } + + it { expect { subject.url }.to raise_error(NoMethodError, message) } + end + + describe ".label" do + let(:message) { "The ErrbitPlugin::IssueTracker.label method is abstract, an implementation of it must be provided in the subclass" } + + it { expect { described_class.label }.to raise_error(NoMethodError, message) } + end + + describe ".note" do + let(:message) { "The ErrbitPlugin::IssueTracker.note method is abstract, an implementation of it must be provided in the subclass" } + + it { expect { described_class.note }.to raise_error(NoMethodError, message) } + end + + describe ".fields" do + let(:message) { "The ErrbitPlugin::IssueTracker.fields method is abstract, an implementation of it must be provided in the subclass" } + + it { expect { described_class.fields }.to raise_error(NoMethodError, message) } + end + + describe ".icons" do + let(:message) { "The ErrbitPlugin::IssueTracker.icons method is abstract, an implementation of it must be provided in the subclass" } + + it { expect { described_class.icons }.to raise_error(NoMethodError, message) } + end +end diff --git a/spec/errbit_plugin/issue_tracker_validator_spec.rb b/spec/errbit_plugin/issue_tracker_validator_spec.rb new file mode 100644 index 0000000..63eff1c --- /dev/null +++ b/spec/errbit_plugin/issue_tracker_validator_spec.rb @@ -0,0 +1,538 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe ErrbitPlugin::IssueTrackerValidator do + describe "#valid?" do + context "with a complete class" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.label + "foo" + end + + def self.note + "foo" + end + + def self.fields + ["foo"] + end + + def self.icons + {} + end + + def configured? + true + end + + def errors + true + end + + def create_issue + "http" + end + + def close_issue + "http" + end + + def url + "http" + end + end + + it "is valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(true) + end + end + + context "with class not inherit from ErrbitPlugin::IssueTracker" do + klass = Class.new do + def self.label + "foo" + end + + def self.note + "foo" + end + + def self.fields + ["foo"] + end + + def self.icons + {} + end + + def initialize(*) + end + + def configured? + true + end + + def errors + true + end + + def create_issue + "http" + end + + def close_issue + "http" + end + + def url + "http" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "says :not_inherited" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:not_inherited]]) + end + end + + context "without #configured? method" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.label + "foo" + end + + def self.note + "foo" + end + + def self.fields + ["foo"] + end + + def self.icons + {} + end + + def errors + true + end + + def create_issue + "http" + end + + def close_issue + "http" + end + + def url + "http" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "say not implement configured? method" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:instance_method_missing, :configured?]]) + end + end + + context "without #errors method" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.label + "foo" + end + + def self.note + "foo" + end + + def self.fields + ["foo"] + end + + def self.icons + {} + end + + def configured? + true + end + + def create_issue + "http" + end + + def close_issue + "http" + end + + def url + "http" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "say not implement errors method" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:instance_method_missing, :errors]]) + end + end + + context "without #create_issue method" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.label + "foo" + end + + def self.note + "foo" + end + + def self.fields + ["foo"] + end + + def self.icons + {} + end + + def configured? + true + end + + def errors + true + end + + def close_issue + "http" + end + + def url + "http" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "say not implement create_issue method" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:instance_method_missing, :create_issue]]) + end + end + + context "without #close_issue method" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.label + "foo" + end + + def self.note + "foo" + end + + def self.fields + ["foo"] + end + + def self.icons + {} + end + + def configured? + true + end + + def errors + true + end + + def create_issue + "http" + end + + def url + "http" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "say not implement close_issue method" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:instance_method_missing, :close_issue]]) + end + end + + context "without #url method" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.label + "foo" + end + + def self.note + "foo" + end + + def self.fields + ["foo"] + end + + def self.icons + {} + end + + def configured? + true + end + + def errors + true + end + + def create_issue + "http" + end + + def close_issue + "http" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "say not implement url method" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:instance_method_missing, :url]]) + end + end + + context "without .label method" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.note + "foo" + end + + def self.fields + ["foo"] + end + + def self.icons + {} + end + + def configured? + true + end + + def errors + true + end + + def create_issue + "http" + end + + def close_issue + "http" + end + + def url + "http" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "say not implement label method" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:class_method_missing, :label]]) + end + end + + context "without .note method" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.label + "foo" + end + + def self.fields + ["foo"] + end + + def self.icons + {} + end + + def configured? + true + end + + def errors + true + end + + def create_issue + "http" + end + + def close_issue + "http" + end + + def url + "foo" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "say not implement note method" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:class_method_missing, :note]]) + end + end + + context "without .fields method" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.label + "foo" + end + + def self.note + "foo" + end + + def self.icons + {} + end + + def configured? + true + end + + def errors + true + end + + def create_issue + "http" + end + + def close_issue + "http" + end + + def url + "http" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "say not implement fields method" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:class_method_missing, :fields]]) + end + end + + context "without .icons method" do + klass = Class.new(ErrbitPlugin::IssueTracker) do + def self.note + "foo" + end + + def self.fields + ["foo"] + end + + def self.label + "alabel" + end + + def configured? + true + end + + def errors + true + end + + def create_issue + "http" + end + + def close_issue + "http" + end + + def url + "http" + end + end + + it "is not valid" do + expect(ErrbitPlugin::IssueTrackerValidator.new(klass).valid?).to eq(false) + end + + it "say not implement icons method" do + validator = ErrbitPlugin::IssueTrackerValidator.new(klass) + + validator.valid? + + expect(validator.errors).to eq([[:class_method_missing, :icons]]) + end + end + end +end diff --git a/spec/errbit_plugin/none_issue_tracker_spec.rb b/spec/errbit_plugin/none_issue_tracker_spec.rb new file mode 100644 index 0000000..150a047 --- /dev/null +++ b/spec/errbit_plugin/none_issue_tracker_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe ErrbitPlugin::NoneIssueTracker do + let(:options) { {} } + + subject { described_class.new(options) } + + it { expect(subject).to be_an(ErrbitPlugin::IssueTracker) } + + it { expect(subject.configured?).to eq(false) } + + it { expect(subject.errors).to eq({}) } + + it { expect(subject.url).to eq("") } + + it { expect(subject.create_issue).to eq(false) } + + it { expect(subject.close_issue).to eq(false) } + + it { expect(described_class.label).to eq("none") } + + it { expect(described_class.note).to eq("When no issue tracker has been configured, you will be able to leave comments on errors.") } + + it { expect(described_class.fields).to eq({}) } + + it do + expect(described_class.icons).to eq({ + create: "none_create.png", + goto: "none_create.png", + inactive: "none_inactive.png" + }) + end +end diff --git a/spec/errbit_plugin/registry_spec.rb b/spec/errbit_plugin/registry_spec.rb index 982b193..4ed8099 100644 --- a/spec/errbit_plugin/registry_spec.rb +++ b/spec/errbit_plugin/registry_spec.rb @@ -1,64 +1,130 @@ -require 'spec_helper' +# frozen_string_literal: true -describe ErrbitPlugin::Registry do - before do - ErrbitPlugin::Registry.clear_issue_trackers - end +require "spec_helper" + +RSpec.describe ErrbitPlugin::Registry do + before { ErrbitPlugin::Registry.clear_issue_trackers } - let(:tracker) { - tracker = Class.new(ErrbitPlugin::IssueTracker) do + let(:tracker) do + Class.new(ErrbitPlugin::IssueTracker) do def self.label - 'something' + "something" end - end - tracker - } - describe ".add_issue_tracker" do - context "with issue_tracker class valid" do - before do - allow(ErrbitPlugin::ValidateIssueTracker) - .to receive(:new) - .with(tracker) - .and_return(double(:valid? => true, :message => '')) + def self.note + "note" + end + + def self.fields + ["foo"] end - it 'add new issue_tracker plugin' do - ErrbitPlugin::Registry.add_issue_tracker(tracker) - expect(ErrbitPlugin::Registry.issue_trackers).to eq({ - 'something' => tracker - }) + + def self.icons + {} + end + + def configured? + true + end + + def errors + true end - context "with already issue_tracker with this key" do - it 'raise ErrbitPlugin::AlreadyRegisteredError' do + + def create_issue + "http" + end + + def close_issue + "http" + end + + def url + "http" + end + end + end + + describe ".add_issue_tracker" do + context "when issue tracker is valid" do + context "when issue tracker is not registered" do + let(:issue_tracker_validator) do + instance_double(ErrbitPlugin::IssueTrackerValidator, + valid?: true, + errors: []) + end + + before do + expect(ErrbitPlugin::IssueTrackerValidator) + .to receive(:new) + .with(tracker) + .and_return(issue_tracker_validator) + end + + it "add new issue_tracker plugin" do ErrbitPlugin::Registry.add_issue_tracker(tracker) - expect { + + expect(ErrbitPlugin::Registry.issue_trackers).to eq({"something" => tracker}) + end + end + + context "when issue tracker is already registered" do + let(:issue_tracker_validator) do + instance_double(ErrbitPlugin::IssueTrackerValidator, + valid?: true, + errors: []) + end + + before { ErrbitPlugin::Registry.add_issue_tracker(tracker) } + + it "raise ErrbitPlugin::AlreadyRegisteredError" do + expect do ErrbitPlugin::Registry.add_issue_tracker(tracker) - }.to raise_error(ErrbitPlugin::AlreadyRegisteredError) + end.to raise_error(ErrbitPlugin::AlreadyRegisteredError) end end end - context "with an IssueTracker not valid" do - it 'raise an IncompatibilityError' do - allow(ErrbitPlugin::ValidateIssueTracker) - .to receive(:new) - .with(tracker) - .and_return(double(:valid? => false, :message => 'foo', :errors => [])) - expect { - ErrbitPlugin::Registry.add_issue_tracker(tracker) - }.to raise_error(ErrbitPlugin::IncompatibilityError) + context "when issue tracker is not valid" do + context "raise IncompatibilityError" do + let(:issue_tracker_validator) do + instance_double(ErrbitPlugin::IssueTrackerValidator, + valid?: false, + errors: []) + end + + before do + expect(ErrbitPlugin::IssueTrackerValidator) + .to receive(:new) + .with(tracker) + .and_return(issue_tracker_validator) + end + + it "raise an IncompatibilityError" do + expect do + ErrbitPlugin::Registry.add_issue_tracker(tracker) + end.to raise_error(ErrbitPlugin::IncompatibilityError) + end end - it 'puts the errors in the exception message' do - allow(ErrbitPlugin::ValidateIssueTracker) - .to receive(:new) - .with(tracker) - .and_return(double(:valid? => false, :message => 'foo', :errors => ['one', 'two'])) + context "show errors in the exception message" do + let(:issue_tracker_validator) do + instance_double(ErrbitPlugin::IssueTrackerValidator, + valid?: false, + errors: ["one", "two"]) + end + + before do + expect(ErrbitPlugin::IssueTrackerValidator) + .to receive(:new) + .with(tracker) + .and_return(issue_tracker_validator) + end - begin + it "puts the errors in the exception message" do ErrbitPlugin::Registry.add_issue_tracker(tracker) rescue ErrbitPlugin::IncompatibilityError => e - expect(e.message).to eq('one; two') + expect(e.message).to eq("one; two") end end end diff --git a/spec/errbit_plugin/validate_issue_tracker_spec.rb b/spec/errbit_plugin/validate_issue_tracker_spec.rb deleted file mode 100644 index 1b73870..0000000 --- a/spec/errbit_plugin/validate_issue_tracker_spec.rb +++ /dev/null @@ -1,255 +0,0 @@ -require 'spec_helper' - -describe ErrbitPlugin::ValidateIssueTracker do - describe "#valid?" do - - context "with a complete class" do - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.label; 'foo'; end - def self.note; 'foo'; end - def self.fields; ['foo']; end - def self.icons; {}; end - def configured?; true; end - def errors; true; end - def create_issue; 'http'; end - def close_issue; 'http'; end - def url; 'http'; end - end - - it 'valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be true - end - end - - context "with class not inherit from ErrbitPlugin::IssueTracker" do - klass = Class.new do - def self.label; 'foo'; end - def self.note; 'foo'; end - def self.fields; ['foo']; end - def self.icons; {}; end - def initialize(params); end - def configured?; true; end - def errors; true; end - def create_issue; 'http'; end - def close_issue; 'http'; end - def url; 'http'; end - end - - it 'not valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be false - end - - it 'says :not_inherited' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).to eql [[:not_inherited]] - end - end - - context "with no label method" do - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.note; 'foo'; end - def self.fields; ['foo']; end - def self.icons; {}; end - def configured?; true; end - def errors; true; end - def create_issue; 'http'; end - def close_issue; 'http'; end - def url; 'http'; end - end - - it 'not valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be false - end - - it 'say not implement label method' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).to eql [[:class_method_missing, :label]] - end - end - - context "with no icons method" do - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.note; 'foo'; end - def self.fields; ['foo']; end - def self.label; 'alabel'; end - def configured?; true; end - def errors; true; end - def create_issue; 'http'; end - def close_issue; 'http'; end - def url; 'http'; end - end - - it 'not valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be false - end - - it 'say not implement icons method' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).to eql [[:class_method_missing, :icons]] - end - end - - context "without fields method" do - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.label; 'foo'; end - def self.note; 'foo'; end - def self.icons; {}; end - def configured?; true; end - def errors; true; end - def create_issue; 'http'; end - def close_issue; 'http'; end - def url; 'http'; end - end - - it 'not valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be false - end - - it 'say not implement fields method' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).to eql [[:class_method_missing, :fields]] - end - end - - context "without configured? method" do - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.label; 'foo'; end - def self.note; 'foo'; end - def self.fields; ['foo']; end - def self.icons; {}; end - def errors; true; end - def create_issue; 'http'; end - def close_issue; 'http'; end - def url; 'http'; end - end - - it 'not valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be false - end - - it 'say not implement configured? method' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).to eql [[:instance_method_missing, :configured?]] - end - end - - context "without errors method" do - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.label; 'foo'; end - def self.note; 'foo'; end - def self.fields; ['foo']; end - def self.icons; {}; end - def configured?; true; end - def create_issue; 'http'; end - def close_issue; 'http'; end - def url; 'http'; end - end - - it 'not valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be false - end - - it 'say not implement errors method' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).to eql [[:instance_method_missing, :errors]] - end - end - - context "without create_issue method" do - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.label; 'foo'; end - def self.note; 'foo'; end - def self.fields; ['foo']; end - def self.icons; {}; end - def configured?; true; end - def errors; true; end - def close_issue; 'http'; end - def url; 'http'; end - end - - it 'not valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be false - end - it 'say not implement create_issue method' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).to eql [[:instance_method_missing, :create_issue]] - end - end - - context "without close_issue method" do - # this is an optional method - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.label; 'foo'; end - def self.note; 'foo'; end - def self.fields; ['foo']; end - def self.icons; {}; end - def configured?; true; end - def errors; true; end - def create_issue; 'http'; end - def url; 'http'; end - end - - it 'is valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be true - end - it 'not say not implement close_issue method' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).not_to eql [[:instance_method_missing, :close_issue]] - end - end - - context "without url method" do - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.label; 'foo'; end - def self.note; 'foo'; end - def self.fields; ['foo']; end - def self.icons; {}; end - def configured?; true; end - def errors; true; end - def create_issue; 'http'; end - def close_issue; 'http'; end - end - - it 'not valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be false - end - - it 'say not implement url method' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).to eql [[:instance_method_missing, :url]] - end - end - - context "without note method" do - klass = Class.new(ErrbitPlugin::IssueTracker) do - def self.label; 'foo'; end - def self.fields; ['foo']; end - def self.icons; {}; end - def configured?; true; end - def errors; true; end - def create_issue; 'http'; end - def close_issue; 'http'; end - def url; 'foo'; end - end - - it 'not valid' do - expect(ErrbitPlugin::ValidateIssueTracker.new(klass).valid?).to be false - end - - it 'say not implement note method' do - is = ErrbitPlugin::ValidateIssueTracker.new(klass) - is.valid? - expect(is.errors).to eql [[:class_method_missing, :note]] - end - end - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 92338c7..040f26d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,26 +1,25 @@ -if ENV['COVERAGE'] - require 'simplecov' - if ENV['CI'] - require 'coveralls' - Coveralls.wear! - SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ - SimpleCov::Formatter::HTMLFormatter, - Coveralls::SimpleCov::Formatter - ] - end +# frozen_string_literal: true + +require "simplecov" + +SimpleCov.start do + enable_coverage :branch + + primary_coverage :branch - SimpleCov.start + add_filter "spec/" end -require 'errbit_plugin' +require "errbit_plugin" RSpec.configure do |config| - config.run_all_when_everything_filtered = true - config.filter_run :focus - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = 'random' + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" + + # Disable RSpec exposing methods globally on `Module` and `main` + config.disable_monkey_patching! + + config.expect_with :rspec do |c| + c.syntax = :expect + end end