Gem Versions Locking

Gem version locking is handled with bundler, Gemfile and Gemfile.lock. The concept is similar to package.json and package-lock.json or yarn.lock in the nodejs world and sort of like requirements.txt and pyenv in the python world.

The generated Terraspace project with terraspace new project provides a starter Gemfile. It looks something like this:

source "https://rubygems.org"
gem "terraspace", '~> 2.2.6'
gem "rspec-terraspace"
gem "terraspace_plugin_aws"

In this example, terraspace itself is pinned by using a version specifier ~>. This means that when bundle runs it will use at least version 2.2.6. Other patch versions above within the minor version are also ok.

You can add and specify additional gem version dependencies if you wish or need to lock down specific versions of gems further. For example, if you want to add tilt.

source "https://rubygems.org"
gem "terraspace", '~> 2.2.6'
gem "rspec-terraspace"
gem "terraspace_plugin_aws"
# added for more control over the dependencies
gem "tilt", "~> 2.1.0"

And run bundle again to regenerate the Gemfile.lock file.

bundle

Check that the gem is pinned to the desired version.

bundle info tilt

You should commit Gemifle.lock, so others or the pipeline use the exact same dependencies.

Thoughts

Considering adding additional version specifiers in the generated Gemfile, but there are some trade-offs.

An analogy:

Consider how Terraform itself handles version locking of providers and modules. You can always specify pinned versions of providers like aws, azurerm, or google in your provider.tf. Where you use the module keyword to source in a module, you can also specify specific versions to lock the module down. This practice has been repeated often enough that it often goes unquestioned without considering the trade-offs.

Locking versions can provide stability, especially since the speed at which terraform move is quick. At the same time, because terraform moves rapidly, locking versions means you won’t get the latest updates and fixes. In practice, this can also break things and cause the very thing you were trying to prevent: instability.

Because pinned versions are too old, they are not really being tested by the community. So you end up unlocking the versions and updating everything in one big go to fix things. It becomes a mouse-and-cat game of updating versions in hopes of fixing the breakage. To compound matters, this often happens at a non-ideal time. The updates would have of happened more incrementally had the versions been more “free”.

So is it better to leave versions free?

Of course not. As often the answer, it depends. It’s often pragmatic to consider each dependency closely on a case-by-case basis. Currently, the generated Gemfile contains a small list. Additional gem versions may be added as cases are considered.

Update

Terraspace 1.0.0 should resolve gem dependency graph issues. The improvements included:

Terrapace Shim Wrapper

On certain system setups, you may want or need to add a terraspace shim to ensure that bundle exec gets called early enough. It’s really system-dependent. Details are covered here: Shim Wrapper.

More tools: