Skip to content

[Content Addressable Gems] Changes to gem build --ruby-abi 3.4 flag #9899

Description

@OughtPuts

The context for this issue is a discussion here between Harriet, Jenny and Kou about the suitability of the naming of the --ruby-abi build flag.

Update 22nd Sept.

We will offer two separate build flags:

  • --ruby-abi <version> explicitly sets the Ruby ABI for the build.
  • --content-addressable requests that RubyGems build a content-addressable gem.

The existing --ruby-abi option must also remain available to gem push and gem yank, where it selects a particular ABI-specific artifact.

Desired Outcome

Before:

gem build --ruby-abi 3.4

The --ruby-abi option both selects the Ruby ABI and enables content-addressable behaviour.

After:

gem build --content-addressable

This builds a content-addressable gem using the required_ruby_version and platform declared in the gemspec.

When the Ruby ABI needs to be supplied explicitly, the flags can be combined:

gem build --ruby-abi 3.4 --content-addressable

The --ruby-abi option sets required_ruby_version for the build, while --content-addressable enables and validates the content-addressable build.

Following on from this, in separate PRs, we will update the PackageTask work so that the final argument passed to Gem::Package.build is a boolean indicating whether to build a content-addressable gem, rather than a Ruby ABI value.

Breakdown of Changes

A skinny gem needs required_ruby_version, required_rubygems_version, and a platform. Currently, --ruby-abi sets or validates all of them even though its name refers only to the Ruby ABI. Separating the options makes the requested behaviour explicit.

1. Preserve --ruby-abi

Preserve --ruby-abi as an option that explicitly sets the Ruby ABI for the build.

Passing:

--ruby-abi 3.4

sets required_ruby_version to:

"~> 3.4.0"

RubyGems should not overwrite required_ruby_version when this option has not been passed.

Passing --ruby-abi alone should not enable content-addressable naming. Without --content-addressable, the build should continue to produce a traditionally named gem.

2. Add --content-addressable

Add a new boolean --content-addressable option to gem build.

When this flag is passed, the build flow should:

  • Validate required_ruby_version and platform using Gem::ContentAddress.eligible?.
  • Provide a useful error when the platform or Ruby requirement makes the specification ineligible.
  • Raise the minimum required_rubygems_version when necessary because older RubyGems versions cannot install content-addressable gems.
  • Raise an error if the existing required_rubygems_version excludes every compatible RubyGems version.
  • Derive the Ruby ABI from required_ruby_version.
  • Build the gem using its content-addressable filename.
  • Not change required_ruby_version or platform.
  • Remain incompatible with an explicitly supplied --output filename because the generated filename must contain the content address.

The gemspec remains the source of truth unless an explicit option, such as --ruby-abi, has been passed to override a value for that build.

3. Preserve existing required_rubygems_version behaviour

The handling of required_rubygems_version should remain the same as the current --ruby-abi content-addressable build behaviour.

For a content-addressable build:

  • Build from a duplicate of the supplied specification.
  • Raise the duplicate’s required_rubygems_version to the required minimum when necessary.
  • Preserve the existing warning when the requirement is raised.
  • Include the raised requirement in the built gem.
  • After a successful build, copy the resulting required_rubygems_version back onto the original in-memory spec.
  • If validation or the build fails, leave the original spec unchanged.
  • If the existing requirement conflicts with the minimum, raise an error and leave the original spec unchanged.

Traditional builds should continue to leave required_rubygems_version unchanged.

This changes only the in-memory Gem::Specification; it does not rewrite the .gemspec file on disk.

4. Preserve --ruby-abi for push and yank

Preserve the existing use of --ruby-abi in gem push and gem yank.

For these commands, the option selects a particular Ruby ABI variant; it does not enable content-addressable building.

5. Documentation update

Update command-reference.md to document both --ruby-abi and --content-addressable.

This could be added as an extra commit to this PR if it has not already been merged.

Suggested Implementation

build_command.rb

  • Add the new boolean --content-addressable option.
  • Keep the existing --ruby-abi option.
  • When --ruby-abi is passed, set the loaded spec’s required_ruby_version before calling Gem::Package.build.
  • Pass the content_addressable boolean to Gem::Package.build.
  • Update the command description and examples.

version_option.rb

  • Preserve add_ruby_abi_option because it is shared with gem push and gem yank.
  • Add a separate content-addressable option helper only if it is useful outside BuildCommand; otherwise, define the option directly in BuildCommand.

Gem::Package.build

  • Change the final argument from ruby_abi to a content_addressable boolean.
  • Default the argument to false.
  • Use the boolean to choose between the traditional and content-addressable build paths.
  • Preserve the current duplicate-spec behaviour for content-addressable builds.
  • After a successful content-addressable build, copy only the resulting required_rubygems_version back to the original spec. Copying back required_ruby_version is no longer necessary because this method should not change it.
  • Update the --output conflict error so that it refers to content-addressable building rather than a Ruby ABI.

Gem::Package#build_content_addressable_file

  • Remove the ruby_abi argument.
  • Remove validate_ruby_abi.
  • Validate the spec using Gem::ContentAddress.eligible?.
  • Do not overwrite required_ruby_version or platform.
  • Derive the ABI from required_ruby_version for console output.
  • Preserve the existing required_rubygems_version normalization, warning, conflict detection, and copy-back behaviour.

Other callsites

Update internal five-argument Gem::Package.build callsites because the final argument changes from an ABI string to a boolean. These include:

  • test/rubygems/helper.rb
  • spec/support/builders.rb
  • Content-addressable calls in test/rubygems/test_gem_package.rb

Ordinary callers using between one and four arguments should remain unchanged.

Gem::PackageTask will be updated to pass the boolean in its separate follow-up PR.

Testing

Update tests in test_gem_commands_build_command.rb, test_gem_package.rb, and the affected helper callsites.

Tests should cover:

  • --ruby-abi alone sets required_ruby_version but produces a traditionally named gem.
  • --content-addressable alone uses the gemspec’s existing Ruby ABI and platform.
  • Both flags can be used together.
  • Neither flag preserves traditional build behaviour.
  • content_addressable = false produces a traditional gem even when the specification is otherwise eligible.
  • Invalid platforms and Ruby requirements are rejected for content-addressable builds.
  • required_ruby_version and platform are preserved during a content-addressable build.
  • A default or weak required_rubygems_version is raised in the built gem and copied back to the original spec after success.
  • The original required_rubygems_version remains unchanged after a failed build.
  • Conflicting required_rubygems_version requirements are rejected.
  • --content-addressable and --output cannot be used together.
  • gem push and gem yank retain their existing --ruby-abi behaviour.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions