Galtzo.com Logo by Aboling0, CC BY-SA 4.0 appraisal-rb Logo by Aboling0, CC BY-SA 4.0 Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5

🔍️ Appraisal2

Find out what my gems are worth!

  • You, possibly

Version License: MIT Downloads Rank Open Source Helpers Depfu Coveralls Test Coverage QLTY Test Coverage QLTY Maintainability CI Heads CI Runtime Dependencies @ HEAD CI Current Deps Locked Deps Unlocked CI Test Coverage CI Style


Liberapay Goal Progress Sponsor Me on Github Buy me a coffee Donate on Polar Donate to my FLOSS or refugee efforts at ko-fi.com Donate to my FLOSS or refugee efforts using Patreon

🌻 Synopsis

Appraisal2 integrates with bundler and rake to test your library against
different versions of dependencies in repeatable scenarios called “appraisals.”
Appraisal2 is designed to make it easy to check for regressions in your library
without interfering with day-to-day development using Bundler.

Appraisal2 is a hard fork of the venerable appraisal gem,
which thoughtbot maintained for many years.
Many thanks to thoughtbot,
and Joe Ferris, the original author!

Appraisal2 adds:

  • support for eval_gemfile
  • support for Ruby 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 (all removed, or planned-to-be, in thoughtbot’s appraisal)
    • NOTE: The setup-ruby GH Action only ships support for Ruby 2.3+, so older Rubies are no longer tested in CI. Compatibility is assumed thanks to Enforced Code Style Linter enforcing the syntax for the oldest supported Ruby, which is Ruby v1.8. File a bug if you find something broken.
  • Support for JRuby 9.4+
  • updated and improved documentation
  • many other fixes and improvements. See CHANGELOG for details.

💡 Info you can shake a stick at

Tokens to Remember Gem name Gem namespace
Works with JRuby JRuby 9.4 Compat JRuby 10.0 Compat JRuby HEAD Compat
Works with Truffle Ruby Truffle Ruby 24.1 Compat
Works with MRI Ruby 3 Ruby 3.0 Compat Ruby 3.1 Compat Ruby 3.2 Compat Ruby 3.3 Compat Ruby 3.4 Compat Ruby HEAD Compat
Works with MRI Ruby 2 Ruby 2.3 Compat Ruby 2.4 Compat Ruby 2.5 Compat Ruby 2.6 Compat Ruby 2.7 Compat
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 BDFL Blog Wiki
Compliance License: MIT 📄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
Support Live Chat on Discord Get help from me on Upwork Get help from me on Codementor
Enterprise Support Get help from me on Tidelift
💡Subscribe for support guarantees covering all 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!
Comrade BDFL 🎖️ Follow Me on LinkedIn Follow Me on Ruby.Social Follow Me on Bluesky Contact BDFL My technical writing
... 💖 Find Me on WellFound: Find Me on CrunchBase My LinkTree More About Me 🧊 🐙 🛖 🧪

✨ Installation

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

$ bundle add appraisal2

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

$ gem install appraisal2

In a RubyGem library

In your package’s .gemspec:

spec.add_development_dependency "appraisal2"

Note that gems must be bundled in the global namespace. Bundling gems to a
local location or vendoring plugins is not fully supported. If you do not want to
pollute the global namespace, one alternative is
RVM’s Gemsets.

🔒 Secure Installation

appraisal2 is cryptographically signed, and has verifiable SHA-256 and SHA-512 checksums by
stone_checksums. Be sure the gem you install hasn’t been tampered with
by following the instructions below.

Add my public key (if you haven’t already, expires 2045-04-29) as a trusted certificate:

gem cert --add <(curl -Ls https://raw.github.com/appraisal-rb/appraisal2/main/certs/pboling.pem)

You only need to do that once. Then proceed to install with:

gem install appraisal2 -P MediumSecurity

The MediumSecurity trust profile will verify signed gems, but allow the installation of unsigned dependencies.

This is necessary because not all of appraisal2’s dependencies are signed, so we cannot use HighSecurity.

If you want to up your security game full-time:

bundle config set --global trust-policy MediumSecurity

NOTE: Be prepared to track down certs for signed gems and add them the same way you added mine.

🔧 Basic Setup

Setting up appraisal2 requires an Appraisals file (similar to a Gemfile) in
your project root, named “Appraisals” (note the case), and some slight changes
to your project’s Rakefile.

An Appraisals file consists of several appraisal definitions. An appraisal
definition is simply a list of gem dependencies. For example, to test with a
few versions of Rails:

appraise "rails-3" do
  gem "rails", "3.2.14"
end

appraise "rails-4" do
  gem "rails", "4.0.0"
end

The dependencies in your Appraisals file are combined with dependencies in
your Gemfile, so you don’t need to repeat anything that’s the same for each
appraisal. If something is specified in both the Gemfile and an appraisal, the
version from the appraisal takes precedence.

Examples of usage in the wild

Appraisal2 can be setup to achieve many different things, from testing against
different versions of services, like MySQL, Redis, or Memcached, and their drivers,
different versions of gems, different platforms, and running different types of validations
which each require a distinct set of gems.
It can also help developers to follow the official recommendation (since 2017) of the bundler team,
to commit the [main] Gemfile.lock for both apps and gems. It does this by giving you alternate gemfiles that won’t have their gemfiles/*.gemfile.lock committed, so you can simply commit the main one without breaking CI.

Having so many different use cases means it can be helpful to others to see how you have done your implementation. If you are willing to spend the time documenting, please send a PR to update this table with another Appraisal2-using project, linking to the specific workflows people can check to see how it is done!

# gem locked / unlocked deps analysis / services SemVer / HEAD deps Rubies os
1 omniauth-identity
Star
Rank
🔒️
un🔒️
Style
Coverage
Svcs
L-Svcs
S-Svcs
U-Svcs
A-Svcs
J-Svcs
AJ-Svcs
Current
Deps@HEAD
Supported
Unsupported
Legacy
Ancient
JRuby
JRuby Ancient
Head
2 rspec-stubbed_env
Star
Rank
🔒️
un🔒️
Style
Coverage
Current Supported
Unsupported
Legacy
Ancient
JRuby
Truffle
Head
3 silent_stream
Star
Rank
🔒️
un🔒️
Style
Coverage
Current Supported
Unsupported
Legacy
Ancient
JRuby
Truffle
Head

⚒️ Basic Usage

Once you’ve configured the appraisals you want to use, you need to install the
dependencies for each appraisal:

$ bundle exec appraisal install

This will resolve, install, and lock the dependencies for that appraisal using
bundler. Once you have your dependencies set up, you can run any command in a
single appraisal:

$ bundle exec appraisal rails-3 rake test

This will run rake test using the dependencies configured for Rails 3. You can
also run each appraisal in turn:

$ bundle exec appraisal rake test

If you want to use only the dependencies from your Gemfile, just run rake test as normal. This allows you to keep running with the latest versions of
your dependencies in quick test runs, but keep running the tests in older
versions to check for regressions.

In the case that you want to run all the appraisals by default when you run
rake, you can override your default Rake task by put this into your Rakefile:

if !ENV["APPRAISAL_INITIALIZED"] && ENV.fetch("CI", "false").casecmp("false") == 0
  task :default => :appraisal
end

(Appraisal2 sets APPRAISAL_INITIALIZED environment variable when it runs your
process. We put a check here to ensure that appraisal rake command should run
your real default task, which usually is your test task.)

Note that this may conflict with your CI setup if you decide to split the test
into multiple processes by Appraisal2 and you are using rake to run tests by
default.

Commands

appraisal clean                  # Remove all generated gemfiles and lockfiles from gemfiles folder
appraisal generate               # Generate a gemfile for each appraisal
appraisal help [COMMAND]         # Describe available commands or one specific command
appraisal install                # Resolve and install dependencies for each appraisal
appraisal list                   # List the names of the defined appraisals
appraisal update [LIST_OF_GEMS]  # Remove all generated gemfiles and lockfiles, resolve, and install dependencies again
appraisal version                # Display the version and exit

Under the hood

Running appraisal install generates a Gemfile for each appraisal by combining
your root Gemfile with the specific requirements for each appraisal. These are
stored in the gemfiles directory, and should be added to version control to
ensure that versions within constraints of the Gemfile are always used.

When you prefix a command with appraisal, the command is run with the
appropriate Gemfile for that appraisal, ensuring the correct dependencies
are used.

Sharing Modular Gemfiles between Appraisals

New in appraisal2 (not possible in thoughtbot’s appraisal)

It is common for Appraisals to duplicate sets of gems, and sometimes it
makes sense to DRY this up into a shared, modular, gemfile.
In a scenario where you do not load your main Gemfile in your Appraisals,
but you want to declare your various gem sets for e.g.
%w(coverage test documentation audit) once each, you can re-use the same
modular gemfiles for local development by referencing them from the main
Gemfile.

To do this, use the eval_gemfile declaration within the necessary
appraise block in your Appraisals file, which will behave the same as
eval_gemfile does in a normal Gemfile.

Example Usage

You could put your modular gemfiles in the gemfiles directory, or nest
them in gemfiles/modular/*, which will be used for this example.

Gemfile

eval_gemfile "gemfiles/modular/audit.gemfile"

gemfiles/modular/audit.gemfile

# Many gems are dropping support for Ruby < 3.1,
#   so we only want to run our security audit in CI on Ruby 3.1+
gem "bundler-audit", "~> 0.9.2"
# And other security audit gems...

Appraisals

appraise "ruby-2-7" do
  gem "dummy"
end

appraise "ruby-3-0" do
  gem "dummy"
end

appraise "ruby-3-1" do
  gem "dummy"
  eval_gemfile "modular/audit.gemfile"
end

appraise "ruby-3-2" do
  gem "dummy"
  eval_gemfile "modular/audit.gemfile"
end

appraise "ruby-3-3" do
  gem "dummy"
  eval_gemfile "modular/audit.gemfile"
end

appraise "ruby-3-4" do
  gem "dummy"
  eval_gemfile "modular/audit.gemfile"
end

Appraisal2.root.gemfile

source "https://rubygems.org"

# Appraisal2 Root Gemfile is for running appraisal to generate the Appraisal2 Gemfiles
# We do not load the standard Gemfile, as it is tailored for local development,
#   while appraisals are tailored for CI.

gemspec

gem "appraisal2"

Now when you need to update your appraisals:

BUNDLE_GEMFILE=Appraisal2.root.gemfile bundle exec appraisal update

Removing Gems using Appraisal2

It is common while managing multiple Gemfiles for dependencies to become deprecated and no
longer necessary, meaning they need to be removed from the Gemfile for a specific appraisal.
To do this, use the remove_gem declaration within the necessary appraise block in your
Appraisals file.

Example Usage

Gemfile

gem "rails", "~> 4.2"

group :test do
  gem "rspec", "~> 4.0"
  gem "test_after_commit"
end

Appraisals

appraise "rails-5" do
  gem "rails", "~> 5.2"

  group :test do
    remove_gem "test_after_commit"
  end
end

Using the Appraisals file defined above, this is what the resulting Gemfile will look like:

gem "rails", "~> 5.2"

group :test do
  gem "rspec", "~> 4.0"
end

Customization

It is possible to customize the generated Gemfiles by adding a customize_gemfiles block to
your Appraisals file. The block must contain a hash of key/value pairs. Currently supported
customizations include:

  • heading: a string that by default adds “# This file was generated by Appraisal2” to the top of each Gemfile, (the string will be commented for you)
  • single_quotes: a boolean that controls if strings are single quoted in each Gemfile, defaults to false

You can also provide variables for substitution in the heading, based on each appraisal. Currently supported variables:

  • %{appraisal}: Becomes the name of each appraisal, e.g. rails-3
  • %{gemfile}: Becomes the filename of each gemfile, e.g. rails-3.gemfile
  • %{gemfile_path}: Becomes the full path of each gemfile, e.g. /path/to/project/gemfiles/rails-3.gemfile
  • %{lockfile}: Becomes the filename of each lockfile, e.g. rails-3.gemfile.lock
  • %{lockfile_path}: Becomes the full path of each lockfile, e.g. /path/to/project/gemfiles/rails-3.gemfile.lock
  • %{relative_gemfile_path}: Becomes the relative path of each gemfile, e.g. gemfiles/rails-3.gemfile
  • %{relative_lockfile_path}: Becomes the relative path of each lockfile, e.g. gemfiles/rails-3.gemfile.lock

Example Usage

Appraisals

customize_gemfiles do
  {
    :single_quotes => true,
    :heading => <<-HEADING,
frozen_string_literal: true

`%{gemfile}` has been generated by Appraisal2, do NOT modify it or `%{lockfile}` directly!
Make the changes to the "%{appraisal}" block in `Appraisals` instead. See the conventions at https://example.com/
    HEADING
  }
end

appraise "rails-3" do
  gem "rails", "3.2.14"
end

Using the Appraisals file defined above, this is what the resulting Gemfile will look like:

# frozen_string_literal: true

# `rails-3.gemfile` has been generated by Appraisal2, do NOT modify it or `rails-3.gemfile.lock` directly!
# Make the changes to the "rails-3" block in `Appraisals` instead. See the conventions at https://example.com/

gem "rails", "3.2.14"

Version Control

When using Appraisal2, we recommend you check in the Gemfiles that Appraisal2
generates within the gemfiles directory, but exclude the lockfiles there
(*.gemfile.lock). The Gemfiles are useful when running your tests against a
continuous integration server.

Additionally, the Bundler team officially recommends
committing the main Gemfile.lock for both gems and libraries.

Circle CI Integration

In Circle CI you can override the default testing behavior.
You can configure Appraisal2 to execute your tests.

In order to this you can put the following configuration in your circle.yml file:

dependencies:
  post:
    - bundle exec appraisal install
test:
  pre:
    - bundle exec appraisal rake db:create
    - bundle exec appraisal rake db:migrate
  override:
    - bundle exec appraisal rspec

Notice that we are running an rspec suite. You can customize your testing
command in the override section and use your favourite one.

🔐 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

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.

⭐️ Star History

Star History Chart

</a>

📌 Versioning

This Library adheres to Semantic Versioning 2.0.0.
Violations of this scheme should be reported as bugs.
Specifically, if a minor or patch version is released that breaks backward compatibility,
a new version should be immediately released that restores compatibility.
Breaking changes to the public API will only be introduced with new major versions.

📌 Is “Platform Support” part of the public API?

Yes. But I’m obligated to include notes…

SemVer should, but doesn’t explicitly, say that dropping support for specific Platforms
is a breaking change to an API.
It is obvious to many, but not all, and since the spec is silent, the bike shedding is endless.

dropping support for a platform is both obviously and objectively a breaking change

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:

As a result of this policy, and the interpretive lens used by the maintainer,
you can (and should) specify a dependency on these libraries using
the Pessimistic Version Constraint with two digits of precision.

For example:

spec.add_dependency("appraisal2", "~> 3.0")

See CHANGELOG.md for a list of releases.

📄 License

The gem is available as open source under the terms of
the MIT License License: MIT.
See LICENSE.txt for the official Copyright Notice.

  • Copyright (c) 2024-2025 Peter H. Boling, of Galtzo.com Galtzo.com Logo by Aboling0, CC BY-SA 4.0 , and Appraisal2 contributors
  • Copyright (c) 2010-2013 Joe Ferris and thoughtbot, inc.

🤑 One more thing

Having arrived at the bottom of the page, please endure a final supplication.
The primary maintainer of this gem, Peter Boling, wants
Ruby to be a great place for people to solve problems, big and small.
Please consider supporting his efforts via the giant yellow link below,
or one of smaller ones, depending on button size preference.

Buy me a latte

Liberapay Goal Progress Sponsor Me on Github Donate on Polar Donate to my FLOSS or refugee efforts at ko-fi.com Donate to my FLOSS or refugee efforts using Patreon

P.S. If you need help️, or want to say thanks, 👇 Join the Discord.

Live Chat on Discord

Disabled Badges Badges for failing services. Bug reports filed. Once fixed, these should look much nicer. [![CodeCov Test Coverage][🔑codecovi♻️]][🔑codecov] [![Coverage Graph][🔑codecov-g♻️]][🔑codecov]