Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

166 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

appraisal-rb Logo by GitHub

🍲 Kettle::Jem::Appraisals

Version Ruby Users Forum GitHub tag (latest SemVer) License: AGPL-3.0-only Total downloads CodeCov Test Coverage Coveralls Test Coverage CI Heads CI Runtime Dependencies @ HEAD CI Current CI JRuby Deps Locked Deps Unlocked CI Test Coverage CI Style

if ci_badges.map(&:color).detect { it != "green"} ☝️ let me know on Discord or RubyForum, as I may have missed the notification.


if ci_badges.map(&:color).all? { it == "green"} πŸ‘‡οΈ send money so I can do more of this. FLOSS maintenance is now my full-time job.

OpenCollective Backers OpenCollective Sponsors Sponsor Me on Github Liberapay Goal Progress Donate on PayPal Buy me a coffee Donate at ko-fi.com

πŸ‘£ How will this project approach the September 2025 hostile takeover of RubyGems? πŸš‘οΈ

I've summarized my thoughts in this blog post.

🌻 Synopsis Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0 ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5

kettle-jem-appraisals automates CI testing matrix generation for Ruby gems. It reads your gemspec, queries the RubyGems API to discover published versions of your runtime dependencies, detects Ruby-version seam points (where required_ruby_version changes), and produces:

  • Modular gemfiles under gemfiles/modular/{gem}/{ruby_series}/v{version}.gemfile
  • An Appraisals file for use with appraisal2
  • Workflow strategy matrix snippets for GitHub Actions CI

If you want a lighter-weight DSL for the original appraisal gem, consider appraisal-matrix instead. kettle-jem-appraisals targets appraisal2 (which supports eval_gemfile, and all ruby versions), while appraisal-matrix targets appraisal (which does not support eval_gemfile, and only supports modern ruby).

Key concepts

Concept Description
Tier 1 Primary runtime dependencies whose version matrix you test against (e.g. activerecord, mail)
Tier 2 Secondary runtime dependencies cross-producted with tier 1 (e.g. omniauth)
Ruby series Buckets like r2.4, r2.6, r2, r3.1, r3 derived from min-ruby seam analysis
Seam A version boundary where a gem's required_ruby_version floor increases
Mode Version selection strategy: major, minor, patch, minor-minmax, or semver
kja- prefix All generated appraisal names start with kja- for reliable cleanup on regeneration

πŸ’‘ Info you can shake a stick at

Tokens to Remember Gem name Gem namespace
Works with JRuby JRuby current Compat JRuby HEAD Compat
Works with MRI Ruby 4 Ruby current Compat Ruby HEAD Compat
Support & Community Join Me on Daily.dev's RubyFriends Get help from RubyForum Live Chat on Discord Get help from me on Upwork Get help from me on Codementor
Source Source on GitLab.com Source on CodeBerg.org Source on GitHub.com The best SHA: dQw4w9WgXcQ!
Documentation Current release on RubyDoc.info YARD on Galtzo.com Maintainer Blog GitLab Wiki GitHub Wiki
Compliance License: AGPL-3.0-only Apache license compatibility: Category X πŸ“„ilo-declaration-img Security Policy Contributor Covenant 2.1 SemVer 2.0.0
Style Enforced Code Style Linter Keep-A-Changelog 1.0.0 Gitmoji Commits Compatibility appraised by: appraisal2
Maintainer πŸŽ–οΈ Follow Me on LinkedIn Follow Me on Ruby.Social Follow Me on Bluesky Contact Maintainer My technical writing
... πŸ’– Find Me on WellFound: Find Me on CrunchBase My LinkTree More About Me 🧊 πŸ™ πŸ›– πŸ§ͺ

Compatibility

Compatible with MRI Ruby, and JRuby. CI workflows and Appraisals are generated for MRI Ruby 4.0.0+. This test floor is configured by ruby.test_minimum in .kettle-jem.yml and may be higher than the gem's runtime compatibility floor when legacy Rubies are not practical for the current toolchain.

kettle-dev Logo by Aboling0, CC BY-SA 4.0

The amazing test matrix is powered by the kettle-dev stack.

How kettle-dev manages complexity in tests
Gem Source Role Total downloads
appraisal2 GitHub multi-dependency Appraisal matrix generation Total downloads for appraisal2
appraisal2-rubocop GitHub RuboCop Appraisal generator integration Total downloads for appraisal2-rubocop
kettle-dev GitHub development, release, and CI workflow tooling Total downloads for kettle-dev
kettle-jem GitHub Appraisals & CI workflow templates Total downloads for kettle-jem
kettle-soup-cover GitHub SimpleCov coverage policy and reporting Total downloads for kettle-soup-cover
kettle-test GitHub standard test runner and coverage harness Total downloads for kettle-test
rubocop-lts GitHub Ruby-version-aware linting Total downloads for rubocop-lts
turbo_tests2 GitHub parallel test execution Total downloads for turbo_tests2

Federated DVCS

Find this repo on federated forges (Coming soon!)
Federated DVCS Repository Status Issues PRs Wiki CI
πŸ§ͺ appraisal-rb/kettle-jem-appraisals on GitLab The Truth πŸ’š πŸ’š πŸ’š 🐭 Tiny Matrix
🧊 appraisal-rb/kettle-jem-appraisals on CodeBerg An Ethical Mirror (Donate) πŸ’š πŸ’š βž– ⭕️ No Matrix
πŸ™ appraisal-rb/kettle-jem-appraisals on GitHub Another Mirror πŸ’š πŸ’š πŸ’š πŸ’― Full Matrix

Enterprise Support Tidelift

Available as part of the Tidelift Subscription.

Need enterprise-level guarantees?

The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.

Get help from me on Tidelift

  • πŸ’‘Subscribe for support guarantees covering all your FLOSS dependencies
  • πŸ’‘Tidelift is part of Sonar
  • πŸ’‘Tidelift pays maintainers to maintain the software you depend on!
    πŸ“Š@Pointy Haired Boss: An enterprise support subscription is "never gonna let you down", and supports open source maintainers

Alternatively:

  • Ruby Users Forum
  • Live Chat on Discord
  • Get help from me on Upwork
  • Get help from me on Codementor

✨ Installation

Install the gem and add to the application's Gemfile by executing:

bundle add kettle-jem-appraisals

If bundler is not being used to manage dependencies, install the gem by executing:

gem install kettle-jem-appraisals

βš™οΈ Configuration

Configuration lives in .kettle-jem.yml under the appraisal_matrix key. Running --scaffold creates a starter config from your gemspec.

Config schema

appraisal_matrix:
  # Global version selection mode (default: semver)
  # Per-gem overrides via the "mode" key on individual gem entries.
  mode: semver

  # Seconds before a resolved matrix is considered stale (default: 604800 = 7 days).
  # Use --force to bypass.
  freshness_ttl: 604800

  # Command to run in CI for each appraisal entry (default: "rake spec")
  exec_cmd: "rake spec"

  gems:
    # Tier 1: primary dependencies whose versions drive the matrix.
    # Each tier1 version is assigned to its optimal Ruby bucket.
    tier1:
      - name: activerecord
        # Optional requirements filter
        requirements:
          - ">= 6.1"
          - "< 8.0"
        # Optional exact-version allowlist, added on top of mode + requirements
        include_versions:
          - "8.0.1"
        # Optional exact-version denylist, removed from the final matrix
        exclude_versions:
          - "7.2"
      - name: mail
        mode: major  # per-gem mode override

    # Optional tier1_mode: default mode for all tier1 gems (overrides global mode)
    # tier1_mode: minor-minmax

    # Tier 2: secondary dependencies cross-producted with tier1.
    # Omit if your gem has only one primary dependency.
    tier2:
      - name: omniauth

    # Optional tier2_mode: default mode for all tier2 gems
    # tier2_mode: major

Version selection modes

Mode Selects Best for
major Latest minor of each major version Large gems with many majors (e.g. Rails)
minor Every minor version across all majors Small gems with few versions
patch Every matching patch version Tight compatibility windows or regression-focused matrices
minor-minmax First + last minor per older major; all minors of current major Balanced coverage
semver Latest minor per older major + Ruby-cutoff minors + all minors of current major unless that major is large, then latest + cutoffs Default β€” best signal-to-noise ratio

Per-gem requirements

Each gem entry may further restrict the resolved version set with requirements. Values can be a string or an array of RubyGems requirement strings.

appraisal_matrix:
  gems:
    tier1:
      - name: activerecord
        mode: patch
        requirements:
          - ">= 7.1"
          - "< 7.2"
      - name: sequel
        requirements:
          - ">= 5.0"
          - "< 6.0"

Those filters apply both to version selection and to Ruby seam detection, so the generated buckets stay aligned with the versions you actually intend to test.

Per-gem include_versions

Each gem entry may also specify include_versions, an explicit allowlist of additional versions to union into the matrix.

appraisal_matrix:
  gems:
    tier1:
      - name: activerecord
        mode: semver
        requirements:
          - ">= 7.1"
          - "< 7.2"
        include_versions:
          - "6.0.9"
          - "8.0.1"

include_versions is additive:

  • versions listed there are added even if they fall outside requirements
  • versions listed there are added even if the selected mode would not normally include them
  • the final generated matrix is the union of mode results, requirements filtering, and include_versions

Per-gem exclude_versions

Each gem entry may also specify exclude_versions, an explicit denylist of exact versions to remove from the resolved matrix.

appraisal_matrix:
  gems:
    tier1:
      - name: activerecord
        mode: semver
        requirements:
          - ">= 7.1"
          - "< 7.2"
        include_versions:
          - "6.0.9"
          - "8.0.1"
        exclude_versions:
          - "7.1.0"
          - "8.0.1"

exclude_versions is applied after mode selection, requirements, and include_versions, so the final set is:

  • start with the versions selected by mode
  • filter that set with requirements
  • union in include_versions
  • subtract exclude_versions

Semver pruning

When a single major version has more than 9 minor releases (e.g. aws-sdk-dynamodb with 166 minors in major 1), semver mode automatically prunes to:

  • The latest minor of that major
  • Any minor that is the last before a Ruby version is dropped (Ruby-cutoff versions)

This prevents matrix explosion while preserving meaningful coverage.

Appraisal naming

All generated names are prefixed with kja- (kettle-jem-appraisals) so that regeneration can reliably identify and remove stale entries.

Format: kja-{tier1}-{t1ver}-{tier2}-{t2ver}-{ruby}

Common gem abbreviations are applied automatically:

Gem Abbreviation
activerecord ar
activesupport as
omniauth oa
mongoid mo
sequel sq

Examples: kja-ar-7-1-oa-2-1-r3, kja-mail-2-8-r3 (tier1-only)

Optimal bucket assignment

Rather than cross-producting every gem version with every Ruby series, each tier1 version is assigned to its optimal bucket β€” the newest Ruby where that version is the best (latest) choice. Gaps are backfilled automatically.

Example with activerecord:

Version Optimal bucket Reason
AR 5.2 r2.4 Next seam (AR 6.0) needs Ruby β‰₯2.5; newest Ruby below is 2.4
AR 6.1 r2.6 Next seam (AR 7.0) needs Ruby β‰₯2.7; newest Ruby below is 2.6
AR 7.1 r2 Next seam (AR 7.2) needs Ruby β‰₯3.1; newest Ruby below is 2.7
AR 7.2 r3.1 Next seam (AR 8.0) needs Ruby β‰₯3.2; newest Ruby below is 3.1
AR 8.1 r3 Catch-all latest bucket

πŸ”§ Basic Usage

Two-step workflow

Step 1 β€” Scaffold reads your gemspec and populates .kettle-jem.yml:

kettle-jem-appraisals --scaffold

Review the generated config: move gems between tier1 and tier2, set per-gem mode overrides, and remove any gems you don't want in the matrix.

Step 2 β€” Resolve queries RubyGems, computes the matrix, and writes files:

kettle-jem-appraisals --resolve

This generates:

  • gemfiles/modular/{gem}/{ruby_series}/v{version}.gemfile β€” one per versionΓ—bucket
  • Appraisals β€” references the modular gemfiles
  • Runs bin/appraisal generate to create flat gemfiles (if binstub exists)

CLI flags

Flag Description
--scaffold Force scaffold mode (even if config exists)
--resolve Force resolve mode
--force Bypass freshness TTL and re-resolve

Without flags, the CLI auto-detects: scaffold if no versions are configured, resolve otherwise.

Re-resolving

The resolved matrix is timestamped. Subsequent runs within freshness_ttl seconds are skipped unless --force is passed. Stale kja-* flat gemfiles from previous runs are automatically cleaned up.

Example: sanitize_email (tier1-only)

appraisal_matrix:
  mode: semver
  gems:
    tier1:
      - name: mail

Produces ~5 entries like kja-mail-2-7-r2.4, kja-mail-2-8-r3.

Example: omniauth-identity (tier1 + tier2)

appraisal_matrix:
  mode: semver
  gems:
    tier1:
      - name: activerecord
      - name: sequel
        mode: major
    tier2:
      - name: omniauth

Produces entries like kja-ar-7-1-oa-2-1-r3, kja-sq-5-0-oa-2-1-r3.

Workflow strategy output

The resolve step also generates CI lifecycle groupings:

Lifecycle Description
supported Current Ruby series (actively maintained)
legacy Older Ruby series (maintenance mode)
unsupported Ruby versions past EOL
ancient Very old Ruby (best-effort)

These map to separate GitHub Actions workflow files for tiered CI execution.

πŸ” Security

See SECURITY.md.

🀝 Contributing

If you need some ideas of where to help, you could work on adding more code coverage, or if it is already πŸ’― (see below) check issues or PRs, or use the gem and think about how it could be better.

We Keep A Changelog so if you make changes, remember to update it.

See CONTRIBUTING.md for more detailed instructions.

πŸš€ Release Instructions

See CONTRIBUTING.md.

Code Coverage

Coverage service badges

Coverage Graph

Coveralls Test Coverage

πŸͺ‡ Code of Conduct

Everyone interacting with this project's codebases, issue trackers, chat rooms and mailing lists agrees to follow the Contributor Covenant 2.1.

🌈 Contributors

Contributors

Made with contributors-img.

Also see GitLab Contributors: https://gitlab.com/appraisal-rb/kettle-jem-appraisals/-/graphs/main

⭐️ Star History Star History Chart

πŸ“Œ Versioning

This library follows Semantic Versioning 2.0.0 for its public API where practical. For most applications, prefer the Pessimistic Version Constraint with two digits of precision.

For example:

spec.add_dependency("kettle-jem-appraisals", "~> 0.0")
πŸ“Œ Is "Platform Support" part of the public API? More details inside.

Dropping support for a platform can be a breaking change for affected users. If a release changes supported platforms, it should be called out clearly in the changelog and versioned with that impact in mind.

To get a better understanding of how SemVer is intended to work over a project's lifetime, read this article from the creator of SemVer:

See CHANGELOG.md for a list of releases.

πŸ“„ License

The gem is available under the following license: AGPL-3.0-only. See LICENSE.md for details.

If none of the available licenses suit your use case, please contact us to discuss a custom commercial license.

Β© Copyright

See LICENSE.md for the official copyright notice.

Copyright holders
  • Copyright (c) 2026 Peter H. Boling

πŸ€‘ A request for help

Maintainers have teeth and need to pay their dentists. After getting laid off in an RIF in March, and encountering difficulty finding a new one, I began spending most of my time building open source tools. I'm hoping to be able to pay for my kids' health insurance this month, so if you value the work I am doing, I need your support. Please consider sponsoring me or the project.

To join the community or get help, use the RubyForum or Discord.

Ruby Users Forum Live Chat on Discord

To say "thanks!" ☝️ Join the community or πŸ‘‡οΈ send money.

Sponsor kettle-dev/kettle-jem-appraisals on Open Source Collective πŸ’Œ Sponsor me on GitHub Sponsors πŸ’Œ Sponsor me on Liberapay πŸ’Œ Donate on PayPal

Please give the project a star ⭐ β™₯.

Many parts of this project are actively managed by a kettle-jem smart template utilizing StructuredMerge.org merge contracts.

Thanks for RTFM. ☺️

Field Value
Package kettle-jem-appraisals
Description 🍲 Kettle::Jem::Appraisals auto-generates CI test matrices from RubyGems API data. Scaffolds tier1/tier2 gem lists from gemspec, resolves version spreads per mode (major/minor/minor-minmax/semver), generates modular gemfiles and Appraisals files. Part of the kettle-dev ecosystem.
Homepage https://github.com/appraisal-rb/kettle-jem-appraisals
Source https://github.com/appraisal-rb/kettle-jem-appraisals
License AGPL-3.0-only
Funding https://github.com/sponsors/pboling, https://ko-fi.com/pboling, https://liberapay.com/pboling/donate, https://opencollective.com/kettle-dev, https://thanks.dev/u/gh/pboling, https://tidelift.com/funding/github/rubygems/kettle-jem-appraisals, https://www.buymeacoffee.com/pboling

About

🍲 Kettle::Jem::Appraisals auto-generates CI test matrices from RubyGems API data. Scaffolds tier1/tier2 gem lists from gemspec, resolves version spreads per mode (major/minor/minor-minmax/semver), generates modular gemfiles and Appraisals files. Part of the kettle-dev ecosystem.

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages