From 5ba6dbe3b054062e5fc679010fbfbe196030d4d0 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 17:55:07 +0100 Subject: [PATCH 01/24] docs: update changelog for 0.3.0 --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba89a46..a146a66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ Keeps track of notable changes. Please remember to add new behaviours to the Unreleased section to make new releases easy. +## [0.3.0] +- [Breaking] Remove support for Ruby 2.5 +- [Added] Add support for Ruby 3.0 + ## [0.2.0] - [Added] `RecordLoader.export_attributes` for easy generation of yaml from From f1e805950d1cef7487522076074a8160dd2bf6cf Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 19:46:50 +0100 Subject: [PATCH 02/24] build: update gemspec file --- record_loader.gemspec | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/record_loader.gemspec b/record_loader.gemspec index 743cb26..03a9466 100644 --- a/record_loader.gemspec +++ b/record_loader.gemspec @@ -1,42 +1,38 @@ # frozen_string_literal: true -lib = File.expand_path('lib', __dir__) -$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require 'record_loader/version' +require_relative 'lib/record_loader/version' Gem::Specification.new do |spec| spec.name = 'record_loader' spec.version = RecordLoader::VERSION - spec.authors = ['James Glover'] - spec.email = ['james.glover@sanger.ac.uk'] + spec.authors = ['Sanger - Production Software Development'] + spec.email = ['psd@sanger.ac.uk'] spec.summary = 'Easily manage seeding and updating data from simple yml files' spec.description = 'Provides a simple interface for generating and maintaining database records across multiple environments in a simple and reproducible manner.' - spec.homepage = 'https://www.github.com/sanger/record_loader' + spec.homepage = 'https://github.com/sanger/record_loader' spec.license = 'MIT' spec.required_ruby_version = '>= 3.0.6' # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' # to allow pushing to a single host or delete this section to allow pushing to any host. - if spec.respond_to?(:metadata) - # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" - - spec.metadata['homepage_uri'] = spec.homepage - spec.metadata['source_code_uri'] = 'https://www.github.com/sanger/record_loader' - # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." - else - raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.' - end + # spec.metadata['allowed_push_host'] = "TODO: Set to your gem server 'https://example.com'" + + spec.metadata['homepage_uri'] = spec.homepage + spec.metadata['source_code_uri'] = 'https://github.com/sanger/record_loader' + spec.metadata['changelog_uri'] = 'https://github.com/sanger/record_loader/blob/master/CHANGELOG.md' # 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(__dir__)) do - `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } + spec.files = Dir.chdir(__dir__) do + `git ls-files -z`.split("\x0").reject do |f| + (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) + end end spec.bindir = 'exe' - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] # Development dependencies @@ -50,4 +46,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'simplecov', '~> 0.22' spec.add_development_dependency 'simplecov-lcov', '~> 0.9' spec.add_development_dependency 'yard', '~> 0.9' + + # For more information and examples about making a new gem, check out our + # guide at: https://bundler.io/guides/creating_gem.html end From d7acc979c958ff1202629416dc305cf2308d2a44 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 19:48:17 +0100 Subject: [PATCH 03/24] style: rubocop todo --- .rubocop_todo.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 601fba3..7ff2a52 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2026-04-29 17:06:59 UTC using RuboCop version 1.86.1. +# on 2026-04-29 18:48:04 UTC using RuboCop version 1.86.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -12,13 +12,6 @@ Gemspec/RequireMFA: Exclude: - 'record_loader.gemspec' -# Offense count: 1 -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: MinBodyLength, AllowConsecutiveConditionals. -Style/GuardClause: - Exclude: - - 'record_loader.gemspec' - # Offense count: 3 # This cop supports unsafe autocorrection (--autocorrect-all). Style/ReduceToHash: From cd102b5e3bddca3d57ba1bc6c7f9d6e9e9f795b1 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 20:07:57 +0100 Subject: [PATCH 04/24] docs: add table of contents to readme --- Gemfile.lock | 4 ++++ README.md | 34 ++++++++++++++++++++++++++++++++++ record_loader.gemspec | 1 + 3 files changed, 39 insertions(+) diff --git a/Gemfile.lock b/Gemfile.lock index 8f0350f..d34b3bf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,6 +13,8 @@ GEM docile (1.4.1) json (2.6.3) language_server-protocol (3.17.0.3) + mdtoc (0.3.1) + sorbet-runtime method_source (1.0.0) parallel (1.23.0) parser (3.2.2.3) @@ -69,6 +71,7 @@ GEM simplecov-html (0.13.2) simplecov-lcov (0.9.0) simplecov_json_formatter (0.1.4) + sorbet-runtime (0.6.13169) unicode-display_width (2.4.2) yard (0.9.34) @@ -77,6 +80,7 @@ PLATFORMS DEPENDENCIES bundler (~> 2.3) + mdtoc (~> 0.3.1) pry (~> 0.14) rake (~> 13.0) record_loader! diff --git a/README.md b/README.md index 93b1f75..571168b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,31 @@ your production and development environments. While written with ActiveRecord/Rails in mind, it is possible to use RecordLoader in different environments. + +* [RecordLoader](README.md#recordloader) + * [Key features](README.md#key-features) + * [Installation](README.md#installation) + * [How to run](README.md#how-to-run) + * [How to generate new records loaders for your project (Rails)](README.md#how-to-generate-new-records-loaders-for-your-project-rails) + * [An example loader](README.md#an-example-loader) + * [`lib/tasks/record_loader.rake`](README.md#libtasksrecord_loader.rake) + * [`lib/record_loader/application_record_loader.rb`](README.md#librecord_loaderapplication_record_loader.rb) + * [`config/record_loader/product_types/default_records.yml`](README.md#configrecord_loaderproduct_typesdefault_records.yml) + * [`lib/record_loader/product_type_loader.rb`](README.md#librecord_loaderproduct_type_loader.rb) + * [`lib/record_loader/tasks/record_loader/product_type.rake`](README.md#librecord_loadertasksrecord_loaderproduct_type.rake) + * [`spec/data/record_loader/product_types/product_types_basic.yml`](README.md#specdatarecord_loaderproduct_typesproduct_types_basic.yml) + * [`spec/lib/record_loader/product_type_loader_spec.rb`](README.md#speclibrecord_loaderproduct_type_loader_spec.rb) + * [Dev and Wip files](README.md#dev-and-wip-files) + * [RecordLoader Dependencies](README.md#recordloader-dependencies) + * [Triggering on deployment](README.md#triggering-on-deployment) + * [Within Sanger PSD](README.md#within-sanger-psd) + * [Non Rails Environments](README.md#non-rails-environments) + * [Development](README.md#development) + * [Contributing](README.md#contributing) + * [License](README.md#license) + * [Updating the table of contents](README.md#updating-the-table-of-contents) + + ## Key features - Produce testable, reproducible data migrations across multiple environments @@ -221,3 +246,12 @@ Bug reports and pull requests are welcome on GitHub at 2.3' + spec.add_development_dependency 'mdtoc', '~> 0.3.1' spec.add_development_dependency 'pry', '~> 0.14' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec', '~> 3.12' From 8ebcffbfd03e26259d3690e86b055771396d0646 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 20:15:32 +0100 Subject: [PATCH 05/24] docs: replace file headings with points --- README.md | 85 +++++++++++++++++++++++++------------------------------ 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 571168b..4c51ff4 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,6 @@ While written with ActiveRecord/Rails in mind, it is possible to use RecordLoade * [How to run](README.md#how-to-run) * [How to generate new records loaders for your project (Rails)](README.md#how-to-generate-new-records-loaders-for-your-project-rails) * [An example loader](README.md#an-example-loader) - * [`lib/tasks/record_loader.rake`](README.md#libtasksrecord_loader.rake) - * [`lib/record_loader/application_record_loader.rb`](README.md#librecord_loaderapplication_record_loader.rb) - * [`config/record_loader/product_types/default_records.yml`](README.md#configrecord_loaderproduct_typesdefault_records.yml) - * [`lib/record_loader/product_type_loader.rb`](README.md#librecord_loaderproduct_type_loader.rb) - * [`lib/record_loader/tasks/record_loader/product_type.rake`](README.md#librecord_loadertasksrecord_loaderproduct_type.rake) - * [`spec/data/record_loader/product_types/product_types_basic.yml`](README.md#specdatarecord_loaderproduct_typesproduct_types_basic.yml) - * [`spec/lib/record_loader/product_type_loader_spec.rb`](README.md#speclibrecord_loaderproduct_type_loader_spec.rb) * [Dev and Wip files](README.md#dev-and-wip-files) * [RecordLoader Dependencies](README.md#recordloader-dependencies) * [Triggering on deployment](README.md#triggering-on-deployment) @@ -107,62 +100,62 @@ Suppose you want to create a loader to maintain a selection of product types. Yo This will create several files: -#### `lib/tasks/record_loader.rake` +- `lib/tasks/record_loader.rake` -Adds the record_loader:all rake task which can be used to trigger all record loaders. + Adds the record_loader:all rake task which can be used to trigger all record loaders. -#### `lib/record_loader/application_record_loader.rb` +- `lib/record_loader/application_record_loader.rb` -Application specific base class for customization. + Application specific base class for customization. -#### `config/record_loader/product_types/default_records.yml` +- `config/record_loader/product_types/default_records.yml` -Example yaml file to begin populating with your record information. Record Loaders will load all yaml files from within -this directory, so it is possible to separate your records into multiple different files for better organization. -In addition yaml files ending in `.dev.yml` and `.wip.yml` exhibit special behaviour. -See [dev and wip files](#dev-and-wip). + Example yaml file to begin populating with your record information. Record Loaders will load all yaml files from within + this directory, so it is possible to separate your records into multiple different files for better organization. + In addition yaml files ending in `.dev.yml` and `.wip.yml` exhibit special behaviour. + See [dev and wip files](#dev-and-wip). -#### `lib/record_loader/product_type_loader.rb` +- `lib/record_loader/product_type_loader.rb` -The actual loader. It will look something like this: + The actual loader. It will look something like this: -```ruby -# frozen_string_literal: true -# This file was automatically generated via `rails g record_loader` - -# RecordLoader handles automatic population and updating of database records -# across different environments -# @see https://rubydoc.info/github/sanger/record_loader/ -module RecordLoader - # Creates the specified plate types if they are not present - class ProductTypeLoader < ApplicationRecordLoader - config_folder 'product_types' - - def create_or_update!(name, options) - ProductType.create_with(options).find_or_create_by!(name: name) + ```ruby + # frozen_string_literal: true + # This file was automatically generated via `rails g record_loader` + + # RecordLoader handles automatic population and updating of database records + # across different environments + # @see https://rubydoc.info/github/sanger/record_loader/ + module RecordLoader + # Creates the specified plate types if they are not present + class ProductTypeLoader < ApplicationRecordLoader + config_folder 'product_types' + + def create_or_update!(name, options) + ProductType.create_with(options).find_or_create_by!(name: name) + end end end -end -``` + ``` -The `config_folder` specifies which directory under `config/record_loader` will be used to source the yaml files. -The method `create_or_update!` will create the actual records, and should be idempotent (ie. calling it multiple times will -have the same effect as calling it once). `create_or_update!` will be called once for each entry in the yaml files, -with the first argument being the key, and the second argument being the value, usually a hash of options. + The `config_folder` specifies which directory under `config/record_loader` will be used to source the yaml files. + The method `create_or_update!` will create the actual records, and should be idempotent (ie. calling it multiple times will + have the same effect as calling it once). `create_or_update!` will be called once for each entry in the yaml files, + with the first argument being the key, and the second argument being the value, usually a hash of options. -#### `lib/record_loader/tasks/record_loader/product_type.rake` +- `lib/record_loader/tasks/record_loader/product_type.rake` -This contains the `record_loader:product_type` which will trigger the record loader, and also ensures that -`record_loader:product_type` will get invoked on calling `record_loader:all`. + This contains the `record_loader:product_type` which will trigger the record loader, and also ensures that + `record_loader:product_type` will get invoked on calling `record_loader:all`. -#### `spec/data/record_loader/product_types/product_types_basic.yml` +- `spec/data/record_loader/product_types/product_types_basic.yml` -A basic configuration for testing the loader. Tests use a separate directory to avoid coupling your specs to the data. + A basic configuration for testing the loader. Tests use a separate directory to avoid coupling your specs to the data. -#### `spec/lib/record_loader/product_type_loader_spec.rb` +- `spec/lib/record_loader/product_type_loader_spec.rb` -A basic rspec spec file for testing your loader. By default this just confirms that your loader creates the -expected number of records, and that it is idempotent. + A basic rspec spec file for testing your loader. By default this just confirms that your loader creates the + expected number of records, and that it is idempotent. ## Dev and Wip files From d805bdae32d167aa4c106db32254010d8c5062e1 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 21:02:35 +0100 Subject: [PATCH 06/24] docs: provide more explicit development instructions --- README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4c51ff4..4f98e01 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,9 @@ While written with ActiveRecord/Rails in mind, it is possible to use RecordLoade * [Within Sanger PSD](README.md#within-sanger-psd) * [Non Rails Environments](README.md#non-rails-environments) * [Development](README.md#development) + * [Setup](README.md#setup) + * [Testing](README.md#testing) + * [Releasing](README.md#releasing) * [Contributing](README.md#contributing) * [License](README.md#license) * [Updating the table of contents](README.md#updating-the-table-of-contents) @@ -224,11 +227,20 @@ See {RecordLoader::Adapter} for information about custom adapters. ## Development -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. +### Setup -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`, ensure the CHANGELOG.md is updated and that everything is committed. +After checking out the repo, run `bin/setup` to install dependencies. + +### Testing + +Then, run `bundle rspec` to run the unit tests. +You can also run `bin/console` for an interactive prompt that will allow you to experiment. +To install this gem onto your local machine, run `bundle exec rake install`. + +### Releasing + +To release a new version, update the version number in `version.rb`, ensure the CHANGELOG.md is updated +and that everything is committed. 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). From 51e6abc1a6b380fc07302c0c416d2e4160f3bafe Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 22:52:15 +0100 Subject: [PATCH 07/24] docs: update changelog for 3.0.0 --- CHANGELOG.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a146a66..2c231d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,18 +3,23 @@ Keeps track of notable changes. Please remember to add new behaviours to the Unreleased section to make new releases easy. +## [3.0.0] + +- [Changed] Version numbering to follow [Ruby Gem versioning guidelines](https://guides.rubygems.org/patterns/), loosely tracking Ruby versions. There are no functional changes in this release. + ## [0.3.0] + - [Breaking] Remove support for Ruby 2.5 - [Added] Add support for Ruby 3.0 ## [0.2.0] - [Added] `RecordLoader.export_attributes` for easy generation of yaml from - existing data + existing data - [Added] Improved feedback if exceptions raised during record creation - [Added] Improved templated yml files to use attributes from table - [Changed] Update name of yaml files generated as part of tests. - No changes are required to existing loaders. + No changes are required to existing loaders. - [Fixed] Default yaml files correctly templated ## [0.1.1] From ff2ab49c33c3c9d1572f70096c37f1ad5ed346f4 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 23:24:43 +0100 Subject: [PATCH 08/24] docs: add version comptibility table --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 4f98e01..19f376a 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ While written with ActiveRecord/Rails in mind, it is possible to use RecordLoade * [RecordLoader](README.md#recordloader) * [Key features](README.md#key-features) + * [Version compatibility](README.md#version-compatibility) * [Installation](README.md#installation) * [How to run](README.md#how-to-run) * [How to generate new records loaders for your project (Rails)](README.md#how-to-generate-new-records-loaders-for-your-project-rails) @@ -39,6 +40,14 @@ While written with ActiveRecord/Rails in mind, it is possible to use RecordLoade - Keep work-in-progress isolated with .wip.yml files - Rails generators to quickly create new record loaders +## Version compatibility + +| Ruby Version | RecordLoader Version | +| ------------- | -------------------- | +| 3.1 and above | 3.1.x | +| 3.0.6 - 3.0.7 | 0.3.0, 3.0.x | +| 2.5 - 2.7 | 0.2.0 | + ## Installation Add this line to your application's Gemfile: From 9883e40c4c0cdfdf339f9746ed83bb5f8f1f89d5 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 20:34:29 +0100 Subject: [PATCH 09/24] build: update to Ruby 3.1 --- .ruby-version | 2 +- record_loader.gemspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.ruby-version b/.ruby-version index 818bd47..23887f6 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.0.6 +3.1.7 diff --git a/record_loader.gemspec b/record_loader.gemspec index 688d72c..69c1496 100644 --- a/record_loader.gemspec +++ b/record_loader.gemspec @@ -14,7 +14,7 @@ Gem::Specification.new do |spec| spec.homepage = 'https://github.com/sanger/record_loader' spec.license = 'MIT' - spec.required_ruby_version = '>= 3.0.6' + spec.required_ruby_version = '>= 3.1.7' # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' # to allow pushing to a single host or delete this section to allow pushing to any host. From ddde8ae899696fcf2497726326aebd0845f8d06b Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 21:37:30 +0100 Subject: [PATCH 10/24] ci: matrix test again ruby 3.0-4.0-head --- .github/workflows/ruby_test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ruby_test.yml b/.github/workflows/ruby_test.yml index 6471a3f..56b33a9 100644 --- a/.github/workflows/ruby_test.yml +++ b/.github/workflows/ruby_test.yml @@ -12,6 +12,11 @@ jobs: name: Rspec runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0' + ruby: [ "3.0", "3.1", "3.2", "3.3", "3.4", "4.0", head ] steps: - name: Checkout Repository uses: sanger/.github/.github/actions/setup/checkout@master From a01494cc23aa7351a16dc1ab31da617a1166568a Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 21:39:58 +0100 Subject: [PATCH 11/24] build: update version and changelog --- CHANGELOG.md | 4 ++++ lib/record_loader/version.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c231d3..49740d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ Keeps track of notable changes. Please remember to add new behaviours to the Unreleased section to make new releases easy. +## [Unreleased] + +- [Added] Support for Ruby 3.1 + ## [3.0.0] - [Changed] Version numbering to follow [Ruby Gem versioning guidelines](https://guides.rubygems.org/patterns/), loosely tracking Ruby versions. There are no functional changes in this release. diff --git a/lib/record_loader/version.rb b/lib/record_loader/version.rb index cbdeefc..19d6905 100644 --- a/lib/record_loader/version.rb +++ b/lib/record_loader/version.rb @@ -2,5 +2,5 @@ module RecordLoader # @return [String] The current sem-ver version number - VERSION = '0.3.0' + VERSION = '3.1.0' end From 19456b394847888c44b618bcc5f7e782e2819a0f Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 21:49:39 +0100 Subject: [PATCH 12/24] ci: set ruby version in matric tests --- .github/workflows/ruby_test.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ruby_test.yml b/.github/workflows/ruby_test.yml index 56b33a9..2a66f3b 100644 --- a/.github/workflows/ruby_test.yml +++ b/.github/workflows/ruby_test.yml @@ -21,8 +21,11 @@ jobs: - name: Checkout Repository uses: sanger/.github/.github/actions/setup/checkout@master - - name: Setup Ruby - uses: sanger/.github/.github/actions/setup/ruby@master + - name: Setup Ruby ${{ matrix.ruby }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Run rspec run: bundle exec rspec From 7aedeb7292496124d0245f4fe0c6b327a9260b3e Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 21:54:32 +0100 Subject: [PATCH 13/24] build: downgrade to 3.1.6 for rspec support --- .ruby-version | 2 +- Gemfile.lock | 4 ++-- record_loader.gemspec | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.ruby-version b/.ruby-version index 23887f6..9cec716 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.1.7 +3.1.6 diff --git a/Gemfile.lock b/Gemfile.lock index 6a176bb..4c9951e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - record_loader (0.3.0) + record_loader (3.1.0) GEM remote: https://rubygems.org/ @@ -93,4 +93,4 @@ DEPENDENCIES yard (~> 0.9) BUNDLED WITH - 2.3.21 + 2.5.9 diff --git a/record_loader.gemspec b/record_loader.gemspec index 69c1496..9df10f4 100644 --- a/record_loader.gemspec +++ b/record_loader.gemspec @@ -14,7 +14,7 @@ Gem::Specification.new do |spec| spec.homepage = 'https://github.com/sanger/record_loader' spec.license = 'MIT' - spec.required_ruby_version = '>= 3.1.7' + spec.required_ruby_version = '>= 3.1.6' # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' # to allow pushing to a single host or delete this section to allow pushing to any host. From 54720c8b2e921b4978169a0693daffc2c80922a3 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 21:56:50 +0100 Subject: [PATCH 14/24] style: lint --- lib/record_loader/adapter/rails.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/record_loader/adapter/rails.rb b/lib/record_loader/adapter/rails.rb index 5880ac1..b352f06 100644 --- a/lib/record_loader/adapter/rails.rb +++ b/lib/record_loader/adapter/rails.rb @@ -16,8 +16,8 @@ def logger # Wraps the ActiveRecord::Base.transaction method. # @see https://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html # @return [Void] - def transaction(&block) - ActiveRecord::Base.transaction(&block) + def transaction(&) + ActiveRecord::Base.transaction(&) end # From bb0f4f922f1a114c4198e89caffdc8a8268b4d53 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 22:03:31 +0100 Subject: [PATCH 15/24] ci: add ruby version to coverage report name --- .github/workflows/ruby_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby_test.yml b/.github/workflows/ruby_test.yml index 2a66f3b..0755436 100644 --- a/.github/workflows/ruby_test.yml +++ b/.github/workflows/ruby_test.yml @@ -33,7 +33,7 @@ jobs: - name: Upload coverage reports to Codecov uses: sanger/.github/.github/actions/tests/codecov@master with: - name: ${{ github.run_id }}_${{ github.job }}_${{ github.event_name }} + name: ${{ github.run_id }}_${{ github.job }}_${{ github.event_name }}_${{ matrix.ruby }} token: ${{ secrets.CODECOV_TOKEN }} flags: ${{ github.event_name }} disable-search: true From bad72234b3aeee89f30c6518892aebd90f5f1c89 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 21:58:48 +0100 Subject: [PATCH 16/24] ci: remove Ruby 3.0 from test matrix --- .github/workflows/ruby_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby_test.yml b/.github/workflows/ruby_test.yml index 0755436..e6ad654 100644 --- a/.github/workflows/ruby_test.yml +++ b/.github/workflows/ruby_test.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0' - ruby: [ "3.0", "3.1", "3.2", "3.3", "3.4", "4.0", head ] + ruby: [ "3.1", "3.2", "3.3", "3.4", "4.0", head ] steps: - name: Checkout Repository uses: sanger/.github/.github/actions/setup/checkout@master From 2e5fb88f66332ed5a087e0642832d86d716b88ce Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 22:06:29 +0100 Subject: [PATCH 17/24] build: add dependencies for Ruby 4 --- Gemfile.lock | 6 +++++- record_loader.gemspec | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4c9951e..6da5d1b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -13,9 +13,11 @@ GEM json (2.19.4) language_server-protocol (3.17.0.5) lint_roller (1.1.0) + logger (1.7.0) mdtoc (0.3.1) sorbet-runtime method_source (1.0.0) + ostruct (0.6.3) parallel (1.28.0) parser (3.3.11.1) ast (~> 2.4.1) @@ -79,8 +81,10 @@ PLATFORMS ruby DEPENDENCIES - bundler (~> 2.3) + bundler (~> 2.5) + logger (~> 1.7) mdtoc (~> 0.3.1) + ostruct (~> 0.6.3) pry (~> 0.14) rake (~> 13.0) record_loader! diff --git a/record_loader.gemspec b/record_loader.gemspec index 9df10f4..479efc5 100644 --- a/record_loader.gemspec +++ b/record_loader.gemspec @@ -36,8 +36,10 @@ Gem::Specification.new do |spec| spec.require_paths = ['lib'] # Development dependencies - spec.add_development_dependency 'bundler', '~> 2.3' + spec.add_development_dependency 'bundler', '~> 2.5' + spec.add_development_dependency 'logger', '~> 1.7' spec.add_development_dependency 'mdtoc', '~> 0.3.1' + spec.add_development_dependency 'ostruct', '~> 0.6.3' spec.add_development_dependency 'pry', '~> 0.14' spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rspec', '~> 3.12' From da6e51984dc3f93e1bc84c83f8d3faa902d57f3c Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 22:35:04 +0100 Subject: [PATCH 18/24] ci: remove ruby-head tests --- .github/workflows/ruby_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ruby_test.yml b/.github/workflows/ruby_test.yml index e6ad654..036fa4f 100644 --- a/.github/workflows/ruby_test.yml +++ b/.github/workflows/ruby_test.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0' - ruby: [ "3.1", "3.2", "3.3", "3.4", "4.0", head ] + ruby: [ "3.1", "3.2", "3.3", "3.4", "4.0" ] steps: - name: Checkout Repository uses: sanger/.github/.github/actions/setup/checkout@master From 3c593a49184ad3b6a33836e9073f7fb3bd7c3fbe Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Wed, 29 Apr 2026 23:44:37 +0100 Subject: [PATCH 19/24] style: add rubocop TargetRubyVersion --- .rubocop.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index c29e870..513ea9a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,7 +1,5 @@ --- -inherit_from: ".rubocop_todo.yml" - # The behaviour of RuboCop can be controlled via the .rubocop.yml # configuration file. It makes it possible to enable/disable # certain cops (checks) and to alter their behaviour if they accept @@ -13,12 +11,15 @@ inherit_from: ".rubocop_todo.yml" # # See https://docs.rubocop.org/rubocop/latest/configuration.html +inherit_from: ".rubocop_todo.yml" + plugins: - rubocop-rake - rubocop-rspec AllCops: NewCops: enable + TargetRubyVersion: 3.1 Gemspec/DevelopmentDependencies: EnforcedStyle: gemspec From 38fdd00ca52dfb6ce990e046a11dfdd00a382384 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Thu, 30 Apr 2026 00:19:43 +0100 Subject: [PATCH 20/24] style: add Style/HashSyntax --- .rubocop.yml | 4 ++++ lib/record_loader/base.rb | 2 +- lib/record_loader/filter.rb | 2 +- spec/record_loader/filter/standard_spec.rb | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 513ea9a..d737d1b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -42,3 +42,7 @@ RSpec/NestedGroups: # The single-line syntax can be clearer than the multi-line version for multiple definitions Style/EmptyClassDefinition: Enabled: false + +# Only use shorthand hash syntax when all keys match the variables for better readability +Style/HashSyntax: + EnforcedShorthandSyntax: consistent diff --git a/lib/record_loader/base.rb b/lib/record_loader/base.rb index 6b81774..67fd505 100644 --- a/lib/record_loader/base.rb +++ b/lib/record_loader/base.rb @@ -66,7 +66,7 @@ def adapter(adapter = nil) def initialize(files: nil, directory: default_path, dev: adapter.development?) @path = directory.is_a?(Pathname) ? directory : Pathname.new(directory) - list = Filter.create(files: files, dev: dev, wip_list: wip_list) + list = Filter.create(files:, dev:, wip_list:) @files = @path.glob("*#{RecordFile::EXTENSION}") .select { |child| list.include?(RecordFile.new(child)) } load_config diff --git a/lib/record_loader/filter.rb b/lib/record_loader/filter.rb index 17ffade..df13078 100644 --- a/lib/record_loader/filter.rb +++ b/lib/record_loader/filter.rb @@ -39,7 +39,7 @@ module Filter # @return [RecordLoader::Filter::Standard, RecordLoader::Filter::FileList] An appropriate filter def self.create(files: nil, dev: false, wip_list: []) if files.nil? - RecordLoader::Filter::Standard.new(dev: dev, wip_list: wip_list) + RecordLoader::Filter::Standard.new(dev:, wip_list:) else RecordLoader::Filter::FileList.new(files) end diff --git a/spec/record_loader/filter/standard_spec.rb b/spec/record_loader/filter/standard_spec.rb index d772d8a..e122e5c 100644 --- a/spec/record_loader/filter/standard_spec.rb +++ b/spec/record_loader/filter/standard_spec.rb @@ -3,7 +3,7 @@ require 'record_loader/filter/standard' RSpec.describe RecordLoader::Filter::Standard, type: :model do - subject(:filter) { described_class.new(dev: dev, wip_list: wip_list) } + subject(:filter) { described_class.new(dev:, wip_list:) } def record_file(name) RecordLoader::RecordFile.new(Pathname.new(name)) From 90544c9da20ef6375b0964e70c8d1f5c138f0d71 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Thu, 30 Apr 2026 00:20:12 +0100 Subject: [PATCH 21/24] test: add initial spec --- spec/record_loader/base_spec.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spec/record_loader/base_spec.rb b/spec/record_loader/base_spec.rb index 5223bd0..13e2cc0 100644 --- a/spec/record_loader/base_spec.rb +++ b/spec/record_loader/base_spec.rb @@ -50,6 +50,23 @@ def create_or_update_called end end + describe '#initialize' do + let(:dev) { false } + + context 'when loading a string' do + let(:selected_files) { ['000_example'] } + + it 'loads the config from the specified file' do + expect(record_loader.instance_variable_get(:@config)) + .to eq({ + 'Example a' => { 'key_a' => 'value a' }, + 'Example b' => { 'key_a' => 'value b' } + }) + end + end + end + end + describe '#create' do before { record_loader.create! } From 0e1f088f15aa8e333202636c60c4530a81917ba3 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Thu, 30 Apr 2026 00:23:52 +0100 Subject: [PATCH 22/24] style: lint --- spec/record_loader/base_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/record_loader/base_spec.rb b/spec/record_loader/base_spec.rb index 13e2cc0..c452962 100644 --- a/spec/record_loader/base_spec.rb +++ b/spec/record_loader/base_spec.rb @@ -64,7 +64,6 @@ def create_or_update_called }) end end - end end describe '#create' do From 7cabeeae9a37e3d48b6b15c655f085cc44edc633 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Thu, 30 Apr 2026 00:40:49 +0100 Subject: [PATCH 23/24] docs: update versions table --- README.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 19f376a..dc9d743 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,21 @@ While written with ActiveRecord/Rails in mind, it is possible to use RecordLoade ## Version compatibility -| Ruby Version | RecordLoader Version | +If using with Rails: + +| Rails Version | RecordLoader Version | | ------------- | -------------------- | -| 3.1 and above | 3.1.x | -| 3.0.6 - 3.0.7 | 0.3.0, 3.0.x | -| 2.5 - 2.7 | 0.2.0 | +| 7.x and above | 1.x | +| 6.x and below | 0.3.0*, 1.0.x* | + +_\* Pin psych < 4_ + +If using with Ruby: + +| Ruby Version | RecordLoader Version | +| ------------ | -------------------- | +| 3.x | 0.3.0, 1.0.x | +| 2.5 - 2.7 | 0.2.0 | ## Installation From f89581378f5d46b4f93c0d35f4f2bd426ec542c1 Mon Sep 17 00:00:00 2001 From: Stephen Hulme Date: Thu, 30 Apr 2026 08:22:22 +0100 Subject: [PATCH 24/24] fix: use Psych v5 with unsafe load --- Gemfile.lock | 6 ++++++ lib/record_loader/base.rb | 2 +- record_loader.gemspec | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6da5d1b..9607bb8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,12 +2,14 @@ PATH remote: . specs: record_loader (3.1.0) + psych (~> 5.0) GEM remote: https://rubygems.org/ specs: ast (2.4.3) coderay (1.1.3) + date (3.5.1) diff-lcs (1.5.0) docile (1.4.1) json (2.19.4) @@ -26,6 +28,9 @@ GEM pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) + psych (5.3.1) + date + stringio racc (1.8.1) rainbow (3.1.1) rake (13.0.6) @@ -72,6 +77,7 @@ GEM simplecov-lcov (0.9.0) simplecov_json_formatter (0.1.4) sorbet-runtime (0.6.13169) + stringio (3.2.0) unicode-display_width (3.2.0) unicode-emoji (~> 4.1) unicode-emoji (4.2.0) diff --git a/lib/record_loader/base.rb b/lib/record_loader/base.rb index 67fd505..169aeb7 100644 --- a/lib/record_loader/base.rb +++ b/lib/record_loader/base.rb @@ -133,7 +133,7 @@ def default_path # def load_config @config = @files.each_with_object({}) do |file, store| - latest_file = YAML.load_file(file) + latest_file = Psych.unsafe_load_file(file) duplicate_keys = store.keys & latest_file.keys adapter.logger.warn "Duplicate keys in #{@path}: #{duplicate_keys}" unless duplicate_keys.empty? store.merge!(latest_file) diff --git a/record_loader.gemspec b/record_loader.gemspec index 479efc5..188cb02 100644 --- a/record_loader.gemspec +++ b/record_loader.gemspec @@ -35,6 +35,9 @@ Gem::Specification.new do |spec| spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } spec.require_paths = ['lib'] + # Runtime dependencies + spec.add_dependency 'psych', '~> 5.0' + # Development dependencies spec.add_development_dependency 'bundler', '~> 2.5' spec.add_development_dependency 'logger', '~> 1.7'