Rubygems Package Manager MVC
Most Ruby software uses Rubygems (and often Bundler) for dependency management. Open-source libraries are almost always distributed as .gem files uploaded to
rubygems.org. They are transformed into deployment artifacts in a number of different ways; perhaps Debian's gem2deb, or just calling
bundle install inside a Docker image to be distributed (or even on the production host itself).
Challenge - Privacy
It would be unwise to upload proprietary gems to rubygems.org, so many organisations who use Ruby and GitLab EE are unable to rely on the above workflow for their Ruby dependency management needs. They have two realistic options:
- Introduce a second dependency management scheme
- Run a private Rubygems server
Having two dependency management schemes is a lot of work, so I expect most organisations choose the second option (can we get numbers on this?). Of organisations who choose the first option, the costs may be avoided by abandoning rubygems for all dependencies - perhaps by vendoring everything, or converting .gem files into a preferred format (Debian packages is one example I've seen for real).
If an organisation does choose the second option, there is a significant amount of infrastructure setup, integration and maintenance work to provide the service and ensure .gem files built with gitlab-ci end up in the repository. However, once set up, it is the lowest-friction option for developers.
GitLab EE could provide a built-in Rubygems server (some options), analogous to the existing Docker Container Registry functionality. This relieves significant burden from Ruby-using EE customers, and could be a powerful selling point for this segment of the market.
In terms of operation, .gitlab-ci.yml file would acquire a special task (a bit like the
pages: task), which would take any .gem artifacts and upload them to the new, integrated Rubygems server (or copy the .gem files to the appropriate place and regenerates the metadata files, if it's desirable for serving them to be static):
rubygems: script: - gem build secretsauce.gemspec artifacts: paths: - secretsauce*.gem
Projects can use this task to upload their .gem files once tests pass, and other projects can simply reference them in the gemfile like:
source "https://gitlab.example.com/somegroup/someproject/rubygems" do gem "secretsauce" end source "https://rubygems.org" do # third-party dependencies here end
Presumably, the default case would be for each project to have its own rubygems namespace, but it's possible we might want to provide a group- or site-wide rubygems server as well? For a project with a number of home-grown dependencies, this would reduce the number of source blocks required in the Gemfile, but it complicates access control.
Challenge - Availability
Rubygems present a second challenge, which is to do with availability. Most Ruby code, even proprietary Ruby code, will rely on gems present on rubygems.org. If your deployment pipeline depends on downloading them each time it runs, an outage or left-pad scenario can break it.
Organisations may be unaware of this (significant) risk to their continued operation (again, can we get numbers?); those that are aware can mitigate it by setting up a private mirror. This downloads copies of the .gem files used by their projects (or just every single gem). Again, there are setup and maintenance costs (and integration costs too, for private mirrors).
GitLab EE could gain an administrator setting -
Mirror rubygems.org. If checked, this would construct a full mirror which could then be used as the source for third-party dependencies in project Gemfiles.
A more complicated option would be to generate a partial mirror of dependencies per project, but it's not clear how one would manage the "source" parameter in the project Gemfile in this case - it needs to be "https://rubygems.org" for GitLab EE to construct the mirror, but then it needs to be "gitlab.example.com/gems" (or so) any time the project is checked out as part of a deployment pipeline.
- This API is handled by https://github.com/rubygems/rubygems.org (check the routes file)