diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 944da02..a34064b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,14 +14,25 @@ concurrency: jobs: specs: - name: Specs (Ruby ${{ matrix.ruby }}) + name: Specs (Ruby ${{ matrix.ruby }}, Rails ${{ matrix.rails }}) runs-on: ubuntu-latest timeout-minutes: 10 strategy: fail-fast: false matrix: - ruby: ['3.0', '3.1', '3.2', '3.3'] + ruby: ['3.0', '3.1', '3.2', '3.3', '3.4'] + rails: ['6.1', '7.0', '7.1', '7.2', '8.0', '8.1'] + exclude: + # Rails < 7.1 requires mutex_m, dropped from the default gems in 3.4. + - {ruby: '3.4', rails: '6.1'} + - {ruby: '3.4', rails: '7.0'} + # Each Rails version's own minimum Ruby. + - {ruby: '3.0', rails: '7.2'} + - {ruby: '3.0', rails: '8.0'} + - {ruby: '3.1', rails: '8.0'} + - {ruby: '3.0', rails: '8.1'} + - {ruby: '3.1', rails: '8.1'} services: postgres: @@ -38,6 +49,9 @@ jobs: --health-timeout 5s --health-retries 5 + env: + BUNDLE_GEMFILE: gemfiles/rails_${{ matrix.rails }}.gemfile + steps: - uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index c8a9280..71d070c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ /.bundle/ /.yardoc /Gemfile.lock +# A lockfile records one Ruby's resolution, and the CI matrix spans several. +/gemfiles/*.gemfile.lock /_yardoc/ /coverage/ /doc/ @@ -9,6 +11,7 @@ /tmp/ /spec/dummy/log/* +/spec/dummy/tmp/ # Ignore vim swap files *.swp diff --git a/Appraisals b/Appraisals new file mode 100644 index 0000000..d1dfbeb --- /dev/null +++ b/Appraisals @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# One appraisal per supported Rails version. `bundle exec appraisal install` +# regenerates gemfiles/ and their lockfiles. + +# concurrent-ruby >= 1.3.5 dropped the implicit `require 'logger'` that +# Rails < 7.1 relies on. +CONCURRENT_RUBY_PIN = '< 1.3.5' + +appraise 'rails-6.1' do + gem 'activerecord', '~> 6.1.0' + gem 'activesupport', '~> 6.1.0' + gem 'concurrent-ruby', CONCURRENT_RUBY_PIN +end + +appraise 'rails-7.0' do + gem 'activerecord', '~> 7.0.0' + gem 'activesupport', '~> 7.0.0' + gem 'concurrent-ruby', CONCURRENT_RUBY_PIN +end + +appraise 'rails-7.1' do + gem 'activerecord', '~> 7.1.0' + gem 'activesupport', '~> 7.1.0' +end + +appraise 'rails-7.2' do + gem 'activerecord', '~> 7.2.0' + gem 'activesupport', '~> 7.2.0' +end + +appraise 'rails-8.0' do + gem 'activerecord', '~> 8.0.0' + gem 'activesupport', '~> 8.0.0' +end + +appraise 'rails-8.1' do + gem 'activerecord', '~> 8.1.0' + gem 'activesupport', '~> 8.1.0' +end diff --git a/CHANGELOG.md b/CHANGELOG.md index ef4bb88..e2158b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Support for Rails 7.0, 7.1, 7.2, 8.0, and 8.1. Rails 6.1 remains supported. +- Support for Ruby 3.3 and 3.4. Ruby 3.0 remains the minimum. - Declared and tested the supported Ruby versions (#10). - The specs and RuboCop now run in GitHub Actions (#9). - Gem metadata: `source_code_uri`, `changelog_uri`, `bug_tracker_uri`, and @@ -16,10 +18,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- `activerecord` and `activesupport` requirements widen from `~> 6.1` to + `>= 6.1, < 9`, and the `< 3.4` Ruby ceiling is removed. Rails 6.1 and 7.0 + cannot run on Ruby 3.4; every other combination is exercised in CI. - The released gem now ships only `lib/`, the README, the LICENSE, and this changelog. Previous releases also carried repository scaffolding — CI configuration, `Rakefile`, `bin/`, and dotfiles — that a host app never loads. +### Removed + +- `pg` is no longer a runtime dependency. Revisions still require PostgreSQL + column types, but the adapter is the host application's to declare, so the + gem no longer forces `pg` into its bundle. + ### Fixed - Made the spec suite runnable and trustworthy again (#8). diff --git a/Gemfile b/Gemfile index 6a4ac30..cd29f96 100644 --- a/Gemfile +++ b/Gemfile @@ -5,10 +5,6 @@ source 'https://rubygems.org' # Specify your gem's dependencies in recorder.gemspec gemspec -# Development pins, removable with the Rails upgrade. - -# concurrent-ruby >= 1.3.5 has no implicit `require 'logger'`; Rails < 7.1 needs it. -gem 'concurrent-ruby', '< 1.3.5' - -# rubocop-factory_bot >= 2.24 needs a newer rubocop than standard 1.29 allows. +# rubocop-factory_bot >= 2.24 needs a newer rubocop than jetrockets-standard 1.29 +# allows, and its config fails to load against the older one. gem 'rubocop-factory_bot', '~> 2.23.0' diff --git a/README.md b/README.md index 1d1c04b..207efbb 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,20 @@ Recorder tracks changes of your Rails models ## Requirements -- Ruby >= 3.0, < 3.4 -- Rails 6.1 - PostgreSQL — revisions are stored in `jsonb` and `inet` columns +- Ruby and Rails per the table below + +| Rails | Supported Ruby | +|-------|----------------| +| 6.1 | 3.0 – 3.3 | +| 7.0 | 3.0 – 3.3 | +| 7.1 | 3.0 – 3.4 | +| 7.2 | 3.1 – 3.4 | +| 8.0 | 3.2 – 3.4 | +| 8.1 | 3.2 – 3.4 | + +Rails 6.1 and 7.0 cannot run on Ruby 3.4 — they require `mutex_m`, which left the +default gems in that release. Every combination in the table is exercised in CI. ## Installation @@ -84,6 +95,19 @@ The gem is under active maintenance and these defects are known as of 1.2.3: After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. +The specs need a PostgreSQL server. Connection settings are read from the +environment — `RECORDER_DB_HOST`, `RECORDER_DB_PORT`, `RECORDER_DB_USERNAME`, +`RECORDER_DB_PASSWORD`, `RECORDER_DB_NAME` — and default to `postgres:postgres` +on `localhost:5432` against a `recorder_test` database, which must already exist. + +`rake spec` runs against whichever Rails version the root `Gemfile` resolves to. +To run against a specific one, use the appraisal gemfiles: + +```bash +bundle exec appraisal install # once, to generate gemfiles/ +bundle exec appraisal rails-7.2 rake spec +``` + To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). ## Contributing diff --git a/gemfiles/rails_6.1.gemfile b/gemfiles/rails_6.1.gemfile new file mode 100644 index 0000000..1ce972d --- /dev/null +++ b/gemfiles/rails_6.1.gemfile @@ -0,0 +1,10 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "rubocop-factory_bot", "~> 2.23.0" +gem "activerecord", "~> 6.1.0" +gem "activesupport", "~> 6.1.0" +gem "concurrent-ruby", "< 1.3.5" + +gemspec path: "../" diff --git a/gemfiles/rails_7.0.gemfile b/gemfiles/rails_7.0.gemfile new file mode 100644 index 0000000..eba5190 --- /dev/null +++ b/gemfiles/rails_7.0.gemfile @@ -0,0 +1,10 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "rubocop-factory_bot", "~> 2.23.0" +gem "activerecord", "~> 7.0.0" +gem "activesupport", "~> 7.0.0" +gem "concurrent-ruby", "< 1.3.5" + +gemspec path: "../" diff --git a/gemfiles/rails_7.1.gemfile b/gemfiles/rails_7.1.gemfile new file mode 100644 index 0000000..a3d29be --- /dev/null +++ b/gemfiles/rails_7.1.gemfile @@ -0,0 +1,9 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "rubocop-factory_bot", "~> 2.23.0" +gem "activerecord", "~> 7.1.0" +gem "activesupport", "~> 7.1.0" + +gemspec path: "../" diff --git a/gemfiles/rails_7.2.gemfile b/gemfiles/rails_7.2.gemfile new file mode 100644 index 0000000..4028302 --- /dev/null +++ b/gemfiles/rails_7.2.gemfile @@ -0,0 +1,9 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "rubocop-factory_bot", "~> 2.23.0" +gem "activerecord", "~> 7.2.0" +gem "activesupport", "~> 7.2.0" + +gemspec path: "../" diff --git a/gemfiles/rails_8.0.gemfile b/gemfiles/rails_8.0.gemfile new file mode 100644 index 0000000..8cdabe7 --- /dev/null +++ b/gemfiles/rails_8.0.gemfile @@ -0,0 +1,9 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "rubocop-factory_bot", "~> 2.23.0" +gem "activerecord", "~> 8.0.0" +gem "activesupport", "~> 8.0.0" + +gemspec path: "../" diff --git a/gemfiles/rails_8.1.gemfile b/gemfiles/rails_8.1.gemfile new file mode 100644 index 0000000..3715196 --- /dev/null +++ b/gemfiles/rails_8.1.gemfile @@ -0,0 +1,9 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "rubocop-factory_bot", "~> 2.23.0" +gem "activerecord", "~> 8.1.0" +gem "activesupport", "~> 8.1.0" + +gemspec path: "../" diff --git a/recorder.gemspec b/recorder.gemspec index 5532486..7178a54 100644 --- a/recorder.gemspec +++ b/recorder.gemspec @@ -27,16 +27,19 @@ Gem::Specification.new do |spec| spec.files = Dir['lib/**/*', 'CHANGELOG.md', 'LICENSE.txt', 'README.md'].select { |f| File.file?(f) } spec.require_paths = ['lib'] - spec.required_ruby_version = ['>= 3.0', '< 3.4'] + spec.required_ruby_version = '>= 3.0' - spec.add_dependency 'activerecord', '~> 6.1' - spec.add_dependency 'activesupport', '~> 6.1' - spec.add_dependency 'pg' - spec.add_dependency 'request_store' + spec.add_dependency 'activerecord', '>= 6.1', '< 9' + spec.add_dependency 'activesupport', '>= 6.1', '< 9' + spec.add_dependency 'request_store', '>= 1.0' + spec.add_development_dependency 'appraisal', '~> 2.5' spec.add_development_dependency 'bundler', '>= 2.0' - spec.add_development_dependency 'generator_spec' + spec.add_development_dependency 'generator_spec', '~> 0.9' spec.add_development_dependency 'jetrockets-standard' + # Revisions are stored in `jsonb` and `inet` columns; the dummy app is PostgreSQL. + # Host apps supply their own adapter. + spec.add_development_dependency 'pg', '>= 1.0' spec.add_development_dependency 'rake', '~> 13.0' - spec.add_development_dependency 'rspec-rails' + spec.add_development_dependency 'rspec-rails', '>= 5.0' end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index be10794..6957fce 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -4,7 +4,15 @@ require File.expand_path('../spec/dummy/config/environment', __dir__) require 'rspec/rails' -ActiveRecord::MigrationContext.new(File.expand_path('dummy/db/migrate', __dir__), ActiveRecord::SchemaMigration).migrate +migrations_path = File.expand_path('dummy/db/migrate', __dir__) + +# Rails 6.1 requires the schema migration class here. It became optional in 7.0 +# and was removed in 7.2. +if ActiveRecord.version < Gem::Version.new('7.0') + ActiveRecord::MigrationContext.new(migrations_path, ActiveRecord::SchemaMigration).migrate +else + ActiveRecord::MigrationContext.new(migrations_path).migrate +end ActiveRecord::Migration.check_pending! if ActiveRecord::Migration.respond_to?(:check_pending!)