Skip to content

Migrate CI to GitHub Actions and expand the Ruby/Rails test matrix - #219

Open
willnet wants to merge 12 commits into
Houdini:masterfrom
willnet:update-ci
Open

Migrate CI to GitHub Actions and expand the Ruby/Rails test matrix#219
willnet wants to merge 12 commits into
Houdini:masterfrom
willnet:update-ci

Conversation

@willnet

@willnet willnet commented Aug 10, 2026

Copy link
Copy Markdown

Fixes #216
Fixes #170
Fixes #169
Related to #218, #213, #211, #204, and #200

This PR migrates the CI setup from Travis CI to GitHub Actions and expands the test matrix to cover representative combinations from Ruby 2.2 through Ruby 4.0 and Rails 4.2 through Rails 8.1, as well as Rails main.

The versioned Rails jobs are required checks. The Rails main job is allowed to fail because it tracks unreleased upstream changes, while still making compatibility regressions visible.

This PR also includes the compatibility changes needed for the test suite to run across the expanded matrix. The suite continues to contain 79 examples; no tests have been removed or relaxed.

Please refer to the individual commits for the background and technical details of each compatibility fix.

CI results is here.

willnet added 12 commits August 10, 2026 14:59
Rails 7 removes Active Record's deprecated update_attributes method. Direct OTP issuance and cleanup would therefore fail before an authentication flow could complete.

Switch these calls to update and rename the non-persisted GuestUser test double's matching method so the test harness continues to mirror the production interface.
With the newer ROTP versions required by the Rails 8 matrix, verification returns a Unix timestamp while the persisted column expects a datetime. Convert it explicitly to UTC Time before assignment.

Rails 8 also validates the resource action list strictly: resend_code is declared as a separate collection route and must not be listed as a resource action. Keep that endpoint while limiting the resource actions to show and update.
Current concurrent-ruby releases no longer load Ruby's logger standard library as a side effect. Older Active Support versions still reference Logger constants during initialization, so the dummy application can fail before the test suite starts when those dependencies are resolved together.

Require logger explicitly before loading the Rails boot files. This keeps the historical framework targets bootable without constraining concurrent-ruby or changing application behavior.
The historical dummy application predates the manifest required by current sprockets-rails releases. When the expanded matrix boots a modern Rails stack with the asset railtie enabled, initialization stops because no application asset manifest is present.

Add the standard manifest and link the existing JavaScript and stylesheet directories. Older Rails targets retain their existing asset behavior while newer targets can complete application boot.
Zeitwerk infers SmsProvider from sms_provider.rb by default, while the dummy application intentionally defines SMSProvider. Register SMS as an acronym so the file name and constant agree when modern Rails validates or autoloads the test application.

Require the standalone provider explicitly from spec_helper as well. This makes it available before examples and support hooks run under both the classic and Zeitwerk autoloaders instead of relying on generation-specific load timing.
The generator spec wrote its output into a repository-relative tmp directory, tying test artifacts to the checkout layout. Use Ruby's system temporary directory so Rails' generator test helpers own an isolated destination consistently across local and hosted environments.

The existence assertion also relied on Ammeter's deprecated override of RSpec's exist matcher. That compatibility matcher warns through the legacy ActiveSupport::Deprecation class delegator, which newer Rails releases no longer expose. Check File.exist? directly through satisfy to preserve the assertion without depending on Ammeter or RSpec internals.
Newer ROTP releases percent-encode provisioning labels, so matching the raw URI rejects output that is semantically equivalent and valid. Parse the URI and verify its scheme, host, decoded path, and secret independently to preserve the authentication contract across ROTP generations.

Use URI.decode_www_form for query parameters in both examples and decode the issuer path before comparison. This removes the separate CGI parsing shape and keeps the assertions focused on the values an authenticator receives rather than their wire encoding.
The pessimistic Capybara 2.5 constraint keeps the test bundle on the 2.x line, which uses a Proc API removed by Ruby 4 and prevents the feature suite from booting on the newest matrix targets.

Retain 2.5 as the lower bound while allowing any release below Capybara 4. This lets Bundler select the maintained 3.x line for current Rubies without dropping the older Capybara versions needed by the historical Ruby and Rails combinations.
A single unconstrained dependency set no longer resolves to versions that can boot every supported runtime. Older Rubies need the last compatible Nokogiri releases, and Loofah must stay below the release that assumes the Nokogiri HTML4 namespace. Rails 4.2 and Rails 5.2 through 7.0 also require different SQLite adapter generations.

Add ostruct only for Ruby 4, where it is no longer bundled as a default library, and declare sprockets-rails for the dummy application instead of depending on historical Rails defaults.

Interpret a two-component RAILS_VERSION as an exact minor series by expanding it before applying the pessimistic constraint. This prevents a Rails 8.0 job from silently resolving Rails 8.1. Rename the edge selector from master to main and pin the Rails repository branch explicitly.
The Travis configuration only covered Ruby 2.2 through 2.5 against Rails 4.2, 5.2, and the former master branch. Move the project to GitHub Actions and exercise 22 explicit combinations spanning Ruby 2.2 through 4.0 and Rails 4.2 through 8.1 plus Rails main.

Every versioned Rails entry is required because the compatibility fixes now allow those releases to complete database setup and all 79 examples. Rails main follows unreleased framework changes, so allow only that job to fail while still reporting upstream compatibility regressions. Keep fail-fast disabled so one failure does not hide results from the rest of the matrix.

Run the entire matrix on ubuntu-latest from the job definition and keep each matrix record focused on its dependency combination. Derive the Rails main exception directly from matrix.rails instead of repeating operating-system and experimental flags in every record.

Use actions/checkout v7 without persisted credentials, ruby/setup-ruby with Bundler caching, read-only contents permission, and a per-job timeout. Remove Travis only after the replacement workflow and the expanded matrix have been prepared.
The first hosted GitHub Actions run showed that ruby/setup-ruby selected Bundler 2.3 for Ruby 2.3 through 2.5. Rails 4.2.11.3 declares bundler >= 1.3 and < 2.0, so dependency resolution stopped during the setup step before the database or specs could run.

Pin Bundler 1.17.3 on each Rails 4.2 matrix entry and retain the setup action default for every newer Rails target. Ruby 2.2 had already selected a compatible Bundler automatically, but an explicit pin keeps all Rails 4.2 jobs deterministic.
The hosted Ruby 2.7 / Rails 7.1 job resolved Psych 5.4 and sqlite3 1.7.3. Bundler installed their native extensions in parallel, allowing sqlite3 extconf to load Ruby 2.7's bundled Psych Ruby code with the Psych 5 extension. The incompatible parser APIs caused sqlite3 compilation to fail before tests started.

Constrain this one historical dependency set to Psych 4, whose extension remains compatible with Ruby 2.7's loader. Newer Ruby and Rails combinations continue using the latest available Psych. The CI-equivalent Bundler 2.4 parallel install now reaches database setup and passes all 79 examples.
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.

Rails 8 incompatability Rails 6.1 deprecation warning rotp breaking changes

1 participant