Skip to content

Drop support for end-of-life Ruby and Active Record - #63

Merged
nertzy merged 3 commits into
masterfrom
drop-eol-versions
Jul 28, 2026
Merged

Drop support for end-of-life Ruby and Active Record#63
nertzy merged 3 commits into
masterfrom
drop-eol-versions

Conversation

@nertzy

@nertzy nertzy commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Drops Ruby and Active Record versions that are out of support, adds the ones that have shipped since the matrix was last touched, and adds a contributing guide.

What is out of support

released status
Ruby 3.2 2022-12-25 end of life 2026-03-31
Active Record 7.0 2021-12-15 end of life
Active Record 7.1 2023-10-05 end of life

So required_ruby_version becomes >= 3.3 and the Active Record dependency becomes >= 7.2.

What is new

Ruby 4.0 shipped on 2025-12-25 and Active Record 8.1 on 2025-10-22; neither was tested here. Both are now in the matrix, along with 8-1-stable and a ruby-head canary that cannot fail the build.

The grid goes from 17 jobs to 14 — 9 required plus 5 that are allowed to fail — while covering more current versions than before.

Two dead Gemfile conditionals go away with 7.0

The Gemfile chose between sqlite3 1.x and 2.x per matrix leg, because Active Record 7.0's adapter requires sqlite3 ~> 1.4. With 7.0 gone the Gemfile just asks for sqlite3.

A self-audit turned up a second one next to it, which had been dead for longer:

gem "arel", git: "https://github.com/rails/arel.git" if ar_branch == "master"

Three separate reasons it could never do anything: nothing sets ACTIVE_RECORD_BRANCH=master (the workflow tests main), Rails has not had a master branch in years, and rails/arel has been untouched since 2018 because Arel was merged into Active Record in 6.0 — activerecord 8.1.3 lists activesupport, activemodel, and timeout, with no arel among them. Removed, and the *-stable legs that exercise that code path are green.

The sqlite3 advisory

Dropping the pin also closes out the advisory reported against this repository: a use-after-free in sqlite3 <= 2.9.4, patched in 2.9.5. The pinned legs could never have taken that fix, since 1.x is not in its range. Now every leg resolves 2.9.5.

Verified locally

Both floors and both ceilings, on real interpreters rather than by inspection:

Active Record 7.2 Active Record 8.1
Ruby 3.3 130 examples, 10 runs 130 examples, 10 runs
Ruby 3.4 130 examples, 10 runs 130 examples, 10 runs
Ruby 4.0 130 examples, 10 runs 130 examples, 10 runs

All green, zero failures.

Workflow structure

The first commit restructures the workflow before any versions change, so the version diff is readable on its own. It follows pg_search, which had already solved the same problems:

  • Checks were named test (3.2, ACTIVE_RECORD_VERSION="~> 7.0.0", false) — hard to scan, and leaking the continue-on-error flag into the name. They are now Ruby 3.3 / AR 8.1.
  • The Active Record version is written to GITHUB_ENV in its own step rather than prefixed onto each command, so a matrix value is no longer interpolated into a shell script.
  • Pull requests cancel their own superseded runs, the job has a timeout, and the workflow requests only contents: read.

That commit changes how the jobs are named and set up, not which ones run: I confirmed the matrix expands to the same 17 (ruby, env, allow-failure) tuples before and after.

Contributing guide

CONTRIBUTING.md, adapted from pg_search's. The parts specific to this gem are the two suites — spec/ for behavior under RSpec, test/ for the minitest life cycle rather than a second copy of the specs — and the two environment variables for selecting an Active Record, which take a version requirement and a git branch respectively. It also asks contributors to leave version.rb alone and add to the Unreleased changelog section.

Linked from the README, which otherwise had nothing pointing at how to run the tests.

Worth knowing

Active Record 7.2 goes out of support on 2026-08-09, twelve days from now. This floor has days left rather than months, so a follow-up moving it to 8.0 is worth expecting shortly. I have kept 7.2 rather than pre-emptively dropping it, since it is supported today.

The README defers to the gemspec for supported versions instead of listing them, so it needed no version edit here — that indirection is why it has not drifted.

Each commit passes bin/rake on its own.

Ruby 4.0 needed bundle exec

The first push of this branch failed every Ruby 4.0 job with bin/rake: No such file or directory, while 3.3 and 3.4 passed. bin/ holds generated binstubs and is not checked in, so CI only ever had one because bundling wrote it — and whether bundling does that varies by Bundler version. Ruby 4.0 ships Bundler 4, which does not, so there was nothing to run.

Tests now run through bundle exec rake, as pg_search's do, and bundle update gains --all — required by Bundler 4, and already the meaning under Bundler 2.

Worth recording that my local "verified on Ruby 4.0" claim above was wrong when I made it: a stale binstub from a Ruby 3.x run was sitting in my working copy, so bin/rake resolved locally and hid the problem. The table's results are real, but they were produced with binstubs present. I re-ran all three Rubies with bin/ removed to confirm the fix, and CI now agrees.

The checks came out named `test (3.2, ACTIVE_RECORD_VERSION="~> 7.0.0", false)`,
which is hard to pick out of a list of seventeen and leaks the
continue-on-error flag into the name. Naming each job after the pair it
exercises gives `Ruby 3.2 / AR 7.0` instead.

Selecting the Active Record version now writes it to the environment rather
than prefixing each command, so the matrix value reaches the run without being
interpolated into a shell script. Pull requests also cancel their own
superseded runs, the job has a timeout, and the workflow asks for only the
read-only token it needs.

Tests run through `bundle exec rake` rather than `bin/rake`, as pg_search's do.
bin/ holds generated binstubs and is not checked in, so whether one exists to
run depends on the Bundler version that happened to install the gems. `bundle
update` also gains `--all`, which is what Bundler 4 asks for and what Bundler 2
already means.

The matrix still expands to the same seventeen jobs; this changes how they are
described and run, not which ones.
@nertzy
nertzy force-pushed the drop-eol-versions branch from 9eb0ee4 to da62e15 Compare July 28, 2026 22:21
nertzy added 2 commits July 28, 2026 17:35
Ruby 3.2 reached end of life on 2026-03-31, and Active Record 7.0 and 7.1 are
both out of support, so the floors move to Ruby 3.3 and Active Record 7.2. Ruby
4.0 and Active Record 8.1 have both shipped since this matrix was last touched
and are now covered, along with 8-1-stable and a ruby-head canary that cannot
fail the build.

Dropping Active Record 7.0 also retires the sqlite3 pin. Its adapter requires
sqlite3 1.x, which is why the Gemfile chose between 1.x and 2.x by matrix leg;
7.2 onward is happy with 2.x, so the Gemfile just asks for sqlite3. That also
clears the advisory against sqlite3 1.x, which no supported combination could
have taken the fix for.

The arel dependency goes with it. It was conditional on a branch named master,
which nothing sets - the workflow tests main - and Rails has not had a master
branch for years. rails/arel has been untouched since 2018 because Arel was
merged into Active Record in 6.0, so no supported version lists it as a
dependency at all.

Note that Active Record 7.2 goes out of support on 2026-08-09, so this floor
has days left on it rather than months.

The README points at the gemspec for supported versions instead of listing
them, so it needs no change here.
Adapted from pg_search's, which covers most of the same ground: report bugs with
a minimal example, discuss large features first, and expect review.

The parts specific to this gem are the two suites - spec/ for behavior under
RSpec, test/ for the minitest life cycle rather than a second copy of the specs -
and the two environment variables for choosing an Active Record, which take a
version requirement and a git branch respectively.

It also asks contributors to leave version.rb alone and add to the Unreleased
section of the changelog, since releases are cut separately and a bump in a pull
request only becomes a conflict.
@nertzy
nertzy force-pushed the drop-eol-versions branch from da62e15 to 1ef89a6 Compare July 28, 2026 22:35
@nertzy
nertzy merged commit 1ef89a6 into master Jul 28, 2026
14 checks passed
@nertzy
nertzy deleted the drop-eol-versions branch July 28, 2026 22:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant