Skip to content

Instantly share code, notes, and snippets.

@joshcooper
Last active April 1, 2024 19:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joshcooper/4198b78460b82a0f3beefefbb5e0dea9 to your computer and use it in GitHub Desktop.
Save joshcooper/4198b78460b82a0f3beefefbb5e0dea9 to your computer and use it in GitHub Desktop.

Gemspec Simplification

TL;DR

We should remove the gem metadata contained in ext/project_data.yaml for the puppet and facter gems, and instead use the gemspec as the source of truth when building them.

Background

Puppet and Facter's gemspec files are only used when running under bundler, but not when building the gems!! Since there are multiple sources of truth, we have frequently updated one but not the other. Most recently, the puppet 8.0.0 gem listed the wrong minimum required ruby version, forcing us to release 8.0.1

One complexity is we publish platform-specific gems for puppet:

https://rubygems.org/downloads/puppet-8.5.1.gem
https://rubygems.org/downloads/puppet-8.5.1-x86-mingw32.gem
https://rubygems.org/downloads/puppet-8.5.1-x64-mingw32.gem
https://rubygems.org/downloads/puppet-8.5.1-universal-darwin.gem

The reason is because puppet depends on CFPropertyList on macOS and ffi on Windows. By publishing platform specific gems, we can add runtime dependencies that only affect that platform.

You might be asking why not just add CFPropertyList and ffi for all platforms? The reason is those gems contain native extensions, and so would require a compiler and ruby-dev packages to be installed in order to gem install puppet.

Technically, CFPropertyList itself doesn't contain native extensions, but it has at various times had a runtime dependency on nokogiri, which does.

Proposal

  1. Move and reconcile all of the common metadata from ext/project_data.yaml to the gemspec, such as author, description, required ruby version, etc.

  2. Move .gemspec back to puppet.gemspec, since it should be used to build the gem, see commit https://github.com/puppetlabs/puppet/commit/8f81b522a98472

  3. For the platform-specific gems, create corresponding puppet-<platform>.gemspec files. Each gemspec can append platform specific dependencies like:

    $ cat puppet-x64-mingw32.gemspec
    spec = Gem::Specification.load('puppet.gemspec')
    spec.platform = 'x64-mingw32'
    spec.add_runtime_dependency('ffi', '1.15.5')
    spec
  4. Modify our build process to build the generic gem:

    gem build <project>.gemspec
  5. Optionally, build platform specific gems in a data driven way. In other words, the build automation should not have a list of platforms to build. It should be based on the names of the gemspec files. For example, we could conceivably have different platform-specific gemspec in 7.x vs main branches.

    for file in <project>-*.gemspec
    do
        gem build $file
    done

Additional Context

https://github.com/puppetlabs/puppet/commit/1342839500624eb360fe30355adce1faa286cf50
https://github.com/puppetlabs/puppet/commit/2707fd88102c776d538e6496bb3f9db733d45c0d
https://puppet.atlassian.net/browse/PA-1077
https://puppet.atlassian.net/browse/PA-2058
https://puppet.atlassian.net/browse/PUP-8685

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment