I have several gems that contain proprietary code that I do not want public to have access to. Rubygems.org is great for gem hosting, but they do not allow security restricted gems, since it defeats the purpose of having an open community for ruby gems. There are several options if you want to host your own gems and restrict access to them. Here are some of the options that I considered
1. Install gemcutter and use that for a gem server.
2. Install the geminabox sinatra app. This is a lightweight gem server with a web interface.
3. Use github. They no longer build gems, but you can still install from github using Bundler (or a plain rake task).
I started playing around with the first 2 options, but I ultimately decided to just use the github solution. Why waste resources setting up a private server when my code is already stored on github with security. I am assuming you know how to set up a project on github, password protect it and push your gem source to github.
Probably one of the coolest parts of working with gems is being able to install specific versions of a gem in your project.. which is much easier than using vendor plugins. In order to keep track of your versions you need to work with git tags. You could also do this with branches, but it would get a bit hairy if you created a new branch for every patch version. A good example of the proper way to set this up is the Ruby on Rails source on github – > http://github.com/rails/rails. Click the drop-down where it says “Switch Branches”. You can see they have a branch for every minor & major version 1.2, 2.0, 2.1, 2.2, 2.3, and 3.0 (master). But notice that you do not see branches for minor versions like 2.3.8. They use git tags to keep track of each version instead. Click “Switch Tags” on the rails source github page. Here you can see they created a separate tag for each version. You will want to do the same with your private gems that you host on github.
Jeweler to the rescue
Luckily, jeweler has already done most of the work for us. Install jeweler first:
gem install jeweler
Jeweler provides some nice shortcuts for creating, building and installing your gems. Take a look at the documentation for more info. I am only going to touch on the versioning that is included with this gem. After you create a project with Jeweler, you get a rakefile that gives you building and versioning tasks. Lets say you make a bunch of changes in your gem project, commit and push them to github and you are ready to bump this gem to a new version. You can use these Jeweler rake tasks to accomplish that:
rake version:bump:patch #you can also use version:bump:minor and version:bump:major.. 1.2.3 -> 1=major, 2=minor, 3=patch rake github:release rake git:release
Jeweler also has a rake task called “release”. This will accomplish the 3 tasks above, but it also tries to push the gem to gemcutter. I could not find a way to turn that off in the documentation (although it may be possible.. I have not looked at the source in depth). I opted to write some custom tasks that combine these 3 tasks into a single task. So I added this to my rakefile:
namespace :version do desc "create a new version, create tag and push to github" task :github_and_tag do Rake::Task['github:release'].invoke Rake::Task['git:release'].invoke end task :patch_release do Rake::Task['version:bump:patch'].invoke Rake::Task['version:github_and_tag'].invoke end task :minor_release do Rake::Task['version:bump:minor'].invoke Rake::Task['version:github_and_tag'].invoke end task :major_release do Rake::Task['version:bump:major'].invoke Rake::Task['version:github_and_tag'].invoke end end
The first tasks takes care of the git tag and github commit/push. The other 3 tasks use the first task and add the version bump for major, minor or patch. So now if I want to do a new patch version, I just have to execute one rake task.
That is half of the equation. The other half is installing the gem from github in your Rails 3 project with Bundler.
Bundler takes care of the rest
Bundler ships with Rails 3 and its purpose is gem dependency management. I really like this tool so far, and the development seems to be moving along very fast. I learned a little trick when I was trying to see if something was fixed in Rails Edge. You can specify github as the source of the gem and it will pull the source code from github, build it and install it for you. You can even specify the tag which makes life even easier. So all I have to do is add one line to the Gemfile in my Rails 3 project and install the bundle. Check this out:
Now that is easy!