From 7817bc9707721fe218fa5e1933c6680dfcf8b7bf Mon Sep 17 00:00:00 2001 From: Jason Karns Date: Thu, 23 Jul 2026 10:22:38 -0400 Subject: [PATCH 1/5] GHA workflow only sets rails_versions, not expressions This will allow the gemfile to do things more intelligently in response to specific rails versions. (Attempting to avoid separate Gemfiles) --- .github/workflows/test.yml | 2 +- example/Gemfile | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 370eaae..c8c2f4f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -15,7 +15,7 @@ jobs: rails: [6.1, "7.0", 7.1, 7.2] env: - RAILS_VERSION: "~> ${{ matrix.rails }}.0" + RAILS_VERSION: ${{ matrix.rails }} steps: - uses: actions/checkout@v7 diff --git a/example/Gemfile b/example/Gemfile index 9ecb492..5883b0b 100644 --- a/example/Gemfile +++ b/example/Gemfile @@ -1,6 +1,8 @@ source "https://rubygems.org" -gem "rails", ENV.fetch("RAILS_VERSION", "~> 7.2") +rails_version = Gem::Version.new ENV.fetch("RAILS_VERSION", "7.2") + +gem "rails", rails_version.approximate_recommendation # ~> major.minor gem "good_migrations", path: ".." From bbe9d6722c9684653b416479e19a12a4f718f1db Mon Sep 17 00:00:00 2001 From: Jason Karns Date: Thu, 23 Jul 2026 10:29:04 -0400 Subject: [PATCH 2/5] only declare the stdlib/default gems for rails 6.1 --- example/Gemfile | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/example/Gemfile b/example/Gemfile index 5883b0b..a88e712 100644 --- a/example/Gemfile +++ b/example/Gemfile @@ -12,7 +12,9 @@ gem "zeitwerk", "~> 2.6" gem "bootsnap", require: false -# activesupport needs these but older rails got it from stdlib -gem "bigdecimal" # since ruby 3.4 -gem "mutex_m" # since ruby 3.4 -gem "benchmark" # since ruby 4.0 +# activesupport 6.1 needs these but older rails got it from stdlib +if Gem::Requirement.new("~> 6.1") === rails_version + gem "bigdecimal" # since ruby 3.4 + gem "mutex_m" # since ruby 3.4 + gem "benchmark" # since ruby 4.0 +end From 0193eb42a9782fd273ccf8b8451812ef16561986 Mon Sep 17 00:00:00 2001 From: Jason Karns Date: Thu, 23 Jul 2026 14:14:31 -0400 Subject: [PATCH 3/5] Generate binstubs in example app to help with running locally Update rails-generated binstubs to v6 --- example/.gitignore | 3 +++ example/bin/setup | 33 +++++++++++++++++++++++++++++++++ example/config/application.rb | 2 +- example/script/rails | 6 ------ 4 files changed, 37 insertions(+), 7 deletions(-) create mode 100755 example/bin/setup delete mode 100755 example/script/rails diff --git a/example/.gitignore b/example/.gitignore index ba66214..09edb9c 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -8,3 +8,6 @@ tmp/**/* # Not committing the schema as we shouldn't need it /db/schema.rb + +# allow using bundler binstubs but we don't want to version them +bin diff --git a/example/bin/setup b/example/bin/setup new file mode 100755 index 0000000..50fe751 --- /dev/null +++ b/example/bin/setup @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path("..", __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts "== Installing dependencies ==" + system! "gem install bundler --conservative" + system("bundle check") || system!("bundle install") + + # puts "\n== Copying sample files ==" + # unless File.exist?('config/database.yml') + # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' + # end + + puts "\n== Preparing database ==" + system! "bin/rails db:prepare" + + puts "\n== Removing old logs and tempfiles ==" + system! "bin/rails log:clear tmp:clear" + + puts "\n== Restarting application server ==" + system! "bin/rails restart" +end diff --git a/example/config/application.rb b/example/config/application.rb index 60ee48e..6f566db 100644 --- a/example/config/application.rb +++ b/example/config/application.rb @@ -42,6 +42,6 @@ class Application < Rails::Application # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] - config.autoloader = ENV["AUTOLOADER"] == "zeitwerk" ? :zeitwerk : :classic + config.autoloader = (ENV["AUTOLOADER"] == "zeitwerk") ? :zeitwerk : :classic end end diff --git a/example/script/rails b/example/script/rails deleted file mode 100755 index 9a5a81d..0000000 --- a/example/script/rails +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env ruby -# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. - -APP_PATH = File.expand_path("../../config/application", __FILE__) -require File.expand_path("../../config/boot", __FILE__) -require "rails/commands" From 2217e8ced1497b4f13c0bc18572e0a06f9c41409 Mon Sep 17 00:00:00 2001 From: Jason Karns Date: Thu, 23 Jul 2026 14:21:56 -0400 Subject: [PATCH 4/5] Use rake clean for nuking sqlite dbs and bundler files rake-clean wipes the sqlite dbs as part of per-test setup. This also enables devs to run `rake clean` themselves within the example app when testing. rake-clobber nukes bundler binstubs and bundler lockfiles. (So we can regenerate a fresh install after switching rails or ruby versions.) Also remove env vars for the rake commands. BUNDLE_GEMFILE and RAILS_ENV are not necessary for the test commands. We're currently operating with just a single gemfile, so we don't need to set explicit paths. Also, RAILS_ENV isn't changed anywhere so the default (unset) will run as development as Rails does. (Better to lean on the defaults which adheres to how rails apps are used in the wild.) --- example/Rakefile | 6 ++++-- test/good_migrations_test.rb | 12 +++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/example/Rakefile b/example/Rakefile index 725024f..0881737 100644 --- a/example/Rakefile +++ b/example/Rakefile @@ -2,6 +2,8 @@ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. require File.expand_path("../config/application", __FILE__) -require "rake" - Example::Application.load_tasks + +require "rake/clean" +CLEAN.include("db/*.sqlite3") # clear dbs between unit tests +CLOBBER.include(Bundler.default_lockfile) # clear lockfile before script/setup diff --git a/test/good_migrations_test.rb b/test/good_migrations_test.rb index 99d80b4..07bbcfd 100644 --- a/test/good_migrations_test.rb +++ b/test/good_migrations_test.rb @@ -1,6 +1,10 @@ require "test_helper" class GoodMigrationsTest < Minitest::Test + def setup + shell("bin/rake clean") + end + def test_that_it_has_a_version_number refute_nil ::GoodMigrations::VERSION end @@ -47,14 +51,8 @@ def test_that_it_has_a_version_number private def shell(command) - script = <<-SCRIPT - export BUNDLE_GEMFILE="Gemfile" - export RAILS_ENV="development" - rm -f db/*.sqlite3 - #{command} - SCRIPT Bundler.with_unbundled_env do - Open3.capture3(script, chdir: "example") + Open3.capture3(command, chdir: "example") end end end From 61189856679384d356cf879d5246845afb6b7b58 Mon Sep 17 00:00:00 2001 From: Jason Karns Date: Thu, 23 Jul 2026 14:09:32 -0400 Subject: [PATCH 5/5] Extract example app's setup script This way it can be run manually from a shell session (as well as in tests). Example app bootstrapping is handled by its own setup script --- example/Rakefile | 2 ++ example/bin/setup | 23 +++++++---------------- example/script/setup | 3 +++ script/test | 10 +--------- test/test_helper.rb | 8 +------- 5 files changed, 14 insertions(+), 32 deletions(-) create mode 100755 example/script/setup diff --git a/example/Rakefile b/example/Rakefile index 0881737..5b35858 100644 --- a/example/Rakefile +++ b/example/Rakefile @@ -7,3 +7,5 @@ Example::Application.load_tasks require "rake/clean" CLEAN.include("db/*.sqlite3") # clear dbs between unit tests CLOBBER.include(Bundler.default_lockfile) # clear lockfile before script/setup + +Rake::Task["clean"].enhance %w[log:clear tmp:clear] diff --git a/example/bin/setup b/example/bin/setup index 50fe751..ab85f58 100755 --- a/example/bin/setup +++ b/example/bin/setup @@ -1,7 +1,7 @@ #!/usr/bin/env ruby require "fileutils" +require "bundler" -# path to your application root. APP_ROOT = File.expand_path("..", __dir__) def system!(*args) @@ -9,25 +9,16 @@ def system!(*args) end FileUtils.chdir APP_ROOT do - # This script is a way to set up or update your development environment automatically. - # This script is idempotent, so that you can run it at any time and get an expectable outcome. - # Add necessary setup steps to this file. + # Rails scaffolded, but modified for abnormal example-app purposes. + + puts "\n== Removing bundler lockfile ==\n#{Bundler.default_lockfile}" + system! "rm -f #{Bundler.default_lockfile}" puts "== Installing dependencies ==" system! "gem install bundler --conservative" system("bundle check") || system!("bundle install") - - # puts "\n== Copying sample files ==" - # unless File.exist?('config/database.yml') - # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' - # end - - puts "\n== Preparing database ==" - system! "bin/rails db:prepare" + system! "bundle binstubs --all" puts "\n== Removing old logs and tempfiles ==" - system! "bin/rails log:clear tmp:clear" - - puts "\n== Restarting application server ==" - system! "bin/rails restart" + system! "bin/rake clean" end diff --git a/example/script/setup b/example/script/setup new file mode 100755 index 0000000..d4f0333 --- /dev/null +++ b/example/script/setup @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec "$(dirname "$0")/../bin/setup" diff --git a/script/test b/script/test index fd801fc..9c9d683 100755 --- a/script/test +++ b/script/test @@ -1,13 +1,5 @@ #!/usr/bin/env bash - set -euo pipefail -echo "---> Installing dependencies in example app" -cd example -bundle -cd .. - echo "---> Running tests" -bundle exec rake - -echo "---> Job's done!" +exec "$(dirname "$0")/../bin/rake" diff --git a/test/test_helper.rb b/test/test_helper.rb index b672139..e2ed97d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -8,12 +8,6 @@ require "open3" require "pry" -pre_test_setup_script = <<-SCRIPT - export BUNDLE_GEMFILE="Gemfile" - export RAILS_ENV="development" - rm -f Gemfile.lock - bundle install -SCRIPT Bundler.with_unbundled_env do - Open3.capture3(pre_test_setup_script, chdir: "example") + Open3.capture3("bin/setup", chdir: "example") end