diff --git a/.claude/skills/ruby-rails-ci-matrix/SKILL.md b/.claude/skills/ruby-rails-ci-matrix/SKILL.md new file mode 100644 index 0000000..a84a8d7 --- /dev/null +++ b/.claude/skills/ruby-rails-ci-matrix/SKILL.md @@ -0,0 +1,108 @@ +--- +description: Maintain the Ruby and Rails version matrix tested in CI for a Ruby gem. Use this when you need to remove EOL versions, add the latest supported versions, and update gemfiles and gemspec accordingly. Always use this for requests like 'remove unsupported Ruby/Rails versions', 'add the latest Rails', or 'update the CI matrix'. +license: MIT +metadata: + github-path: skills/ruby/ruby-rails-ci-matrix + github-ref: refs/heads/main + github-repo: https://github.com/aki77/skills + github-tree-sha: 59898557bcf3dd4e734ae3f25c8ab025a43341be +name: ruby-rails-ci-matrix +--- +# ruby-rails-ci-matrix + +Maintain the Ruby and Rails versions tested in CI for a Ruby gem that uses GitHub Actions matrix strategy with `gemfiles/railsXX.gemfile` and a gemspec. This skill keeps the test matrix aligned with the current support status. + +Remove EOL (End of Life) versions and add currently supported and latest stable versions. The gemfile, gemspec, and workflow YAML must be updated **in sync** — updating only one will break CI. + +## 1. Assess the Current State + +Before making any changes, read all three types of files involved. + +| File | What to check | +| --- | --- | +| `.github/workflows/*.yml` | `strategy.matrix.include` entries (`{ ruby:, gemfile: }`), `ruby/setup-ruby` version | +| `gemfiles/*.gemfile` | Per-Rails-version gemfiles — `source` URL and `gem 'rails', '~> X.Y.0'` | +| `*.gemspec` | `required_ruby_version` and the lower bound of `add_dependency "rails", ...` | + +Note that the `gemfile:` values in the matrix correspond 1:1 with `gemfiles/.gemfile`. + +## 2. Research EOL Status + +**Use today's date as the reference** and fetch the latest support information — do not rely on memory. + +- Ruby: +- Rails: + +If endoflife.date is unreachable, use WebSearch as a fallback. Confirm the following three things: + +1. EOL date for each version (including security support end date) — has it passed as of today? +2. Full list of currently supported versions +3. Latest stable releases (check whether a new major like Ruby 4.0 or Rails 8.1 has been released) + +> Ruby releases a new version every December with ~3 years 3 months of support. Rails 7.2+ receives 1 year of standard support and 2 years of security support. + +## 3. Decide What to Add and Remove + +- **Remove**: Ruby / Rails versions that are EOL (security support also ended) as of today. +- **Add**: Supported versions not yet in the matrix, plus the latest stable releases. +- **Keep**: Versions still under security support. For versions expiring within a few months, ask the user whether to keep them. +- Build the matrix as **each Rails version × the compatible Ruby versions**. Pay attention to compatibility — older Rails versions may not support the newest Ruby. + +## 4. Update Files + +Keep all three files consistent. **If you remove a gemfile, remove the matrix entry too** (and vice versa). + +### Workflow YAML Matrix + +Update the `include:` entries. Use short-form Ruby version strings (`"4.0"`) so `ruby/setup-ruby` automatically picks the latest patch. + +```yaml +strategy: + matrix: + include: + - { ruby: "3.3", gemfile: "rails72" } + - { ruby: "3.4", gemfile: "rails72" } + - { ruby: "4.0", gemfile: "rails72" } + - { ruby: "3.3", gemfile: "rails80" } + - { ruby: "3.4", gemfile: "rails80" } + - { ruby: "4.0", gemfile: "rails80" } + - { ruby: "3.3", gemfile: "rails81" } + - { ruby: "3.4", gemfile: "rails81" } + - { ruby: "4.0", gemfile: "rails81" } +``` + +### Create / Delete Gemfiles + +For a new Rails version, copy an existing gemfile and change only the `~> X.Y.0` constraint. + +```ruby +source "https://rubygems.org" + +gem 'rails', '~> 8.1.0' +gem 'sqlite3' + +gemspec path: '../' +``` + +Delete the gemfile for any Rails version being dropped. + +### Update gemspec Lower Bounds + +Update two lines to match the minimum supported versions. + +```ruby +spec.required_ruby_version = '>= 3.3.0' # minimum supported Ruby +spec.add_dependency "rails", ">= 7.2.0" # minimum supported Rails +``` + +## Notes + +- **Always use `https://rubygems.org`** as the `source` — fix any `http://` occurrences. +- **`ruby/setup-ruby@v1` and new majors**: For brand-new majors like Ruby 4.0, verify that setup-ruby already supports it (it usually does very quickly). +- **Raising `required_ruby_version` is a breaking change**. Users on the old Ruby version will no longer be able to install the gem, so a minor or major gem version bump is required at release time. Handle this in a separate PR / commit, not as part of this matrix update. + +## Pitfalls + +- **Forgetting to update the gemspec lower bounds** means the old Ruby/Rails version you removed from CI can still be `gem install`-ed, creating a mismatch between stated and actual support. +- **Updating only the gemfile or only the matrix** breaks CI — either a missing gemfile is referenced, or an unused gemfile is left behind. Always update both together. +- **Mixing unrelated changes** (e.g., fixing `http://` → `https://` sources) into the same commit as version removals obscures intent. Commit each logical unit separately. diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index ef5ad4c..a9f49ff 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -16,15 +16,8 @@ jobs: strategy: fail-fast: false matrix: - ruby: ["3.1", "3.2", "3.3", "3.4", "4.0"] - gemfile: ["rails71", "rails72", "rails80", "rails81"] - exclude: - # rails 8.0: support ruby 3.2+ - - ruby: "3.1" - gemfile: "rails80" - # rails 8.1: support ruby 3.2+ - - ruby: "3.1" - gemfile: "rails81" + ruby: ["3.3", "3.4", "4.0"] + gemfile: ["rails72", "rails80", "rails81"] steps: - uses: actions/checkout@v6 diff --git a/csb.gemspec b/csb.gemspec index aa482d7..6d98ed6 100644 --- a/csb.gemspec +++ b/csb.gemspec @@ -20,15 +20,15 @@ Gem::Specification.new do |spec| # 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. spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|\.claude)/}) } end spec.bindir = "exe" spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] - spec.required_ruby_version = '>= 3.1.0' + spec.required_ruby_version = '>= 3.3.0' - spec.add_dependency "rails", ">= 7.1.4" + spec.add_dependency "rails", ">= 7.2.0" spec.add_dependency "csv" spec.add_development_dependency "rake" diff --git a/gemfiles/rails71.gemfile b/gemfiles/rails71.gemfile deleted file mode 100644 index 65f1f08..0000000 --- a/gemfiles/rails71.gemfile +++ /dev/null @@ -1,5 +0,0 @@ -source "http://rubygems.org" - -gem 'rails', '~> 7.1.4' - -gemspec path: '../' diff --git a/gemfiles/rails72.gemfile b/gemfiles/rails72.gemfile index 721906b..edc36fa 100644 --- a/gemfiles/rails72.gemfile +++ b/gemfiles/rails72.gemfile @@ -1,4 +1,4 @@ -source "http://rubygems.org" +source "https://rubygems.org" gem 'rails', '~> 7.2.0' diff --git a/gemfiles/rails80.gemfile b/gemfiles/rails80.gemfile index 82532f7..2cc44c5 100644 --- a/gemfiles/rails80.gemfile +++ b/gemfiles/rails80.gemfile @@ -1,4 +1,4 @@ -source "http://rubygems.org" +source "https://rubygems.org" gem 'rails', '~> 8.0.0' diff --git a/gemfiles/rails81.gemfile b/gemfiles/rails81.gemfile index c7a213c..4d934d2 100644 --- a/gemfiles/rails81.gemfile +++ b/gemfiles/rails81.gemfile @@ -1,4 +1,4 @@ -source "http://rubygems.org" +source "https://rubygems.org" gem 'rails', '~> 8.1.0' diff --git a/lib/csb/version.rb b/lib/csb/version.rb index cfc0971..71520d5 100644 --- a/lib/csb/version.rb +++ b/lib/csb/version.rb @@ -1,3 +1,3 @@ module Csb - VERSION = '0.15.0' + VERSION = '0.16.0' end