Working with private RubyGems in Rails 3, deploying to Heroku

Many development projects aren´t open source, they live with other closed-source projects/apps and they get huge. At some point, hopefully sooner than later, you’d like to extract that common and useful functionality you created and share it with other components/apps, just like any other gem.

Creating a gem is easy if you make it publicly available, jeweler is a dream come true for this, but creating a private gem is (was) a PITA, for me at least. I’m embarrassed to admit I’ve spent more than two days getting this up to speed, but luckily for you, I spent an additional hour sharing with the world, and you, how to distribute gems not to be shared with the world, nor you. Actually, the solution is pretty simple:

Create a private repo (github or private git server) for your gem. Make it a gem (gemspec file-examples below). In the description that follows, I setup a gemserver as well (behind a firewall in my case), which I recommend, but is not required. Read on:

1. Option: Setup gemserver

(You may skip this part)

Use rvm to have a clean server

~gemserver$ rvm 1.8.7@gemserver

(‘gemserver’ is gemset name. I suppose you now how to do this. Read more about rvm)

gem list should be clean, else gem uninstall gemname each of the present ones

Install gem

copy your gem to i.e. ~/gems at the server. Then do

~gemserver$ cd gems && gem install my_private_gem-VERSION.gem --ignore-dependencies

gem list should now contain only that gem.

Start gemserver

~gemserver$ gem server

Browse to your gem server ip, port 8808 is default, or http://localhost:8808 if you’re testing out the procedure locally. You should see your gem. Cool, your own gem server!

Add your gemserver to bundler

~$ gem sources -a http://mygemserver.mycompany.com:8808

should show up if you perform gem sources

Get the gem from the gemserver

~$ gem install my_private_gem

(optional; specify version -v ‘0.2.3’ )

2. Vendor private gem with rails app

This is common whether you have gemserver or not. You should have the gem locally at this point. Unpack gem to vendor/gems (feel free to choose other directory) and mark the dependence to it in Gemfile

Unpack

~$ gem unpack my_private_gem -v '0.2.3' --target vendor/gems/.

Gemfile

gem 'my_private_gem', :path => "#{File.expand_path(__FILE__)}/../vendor/gems/my_private_gem-0.2.3"

3. Thanks to

I stole the title from this article, which inspired my, but the private git repo didn’t work with hreoku for my. The main repo may be private, but you can’t have private dependencies as heroku won’t be authorized to access it. If you don’t use heroku, and control the infrastructure (may set ssh keys), this approach is better, IMO: Working with private RubyGems in Rails 3

Thanks to this railtie for beginners post Rails 3 Internals: Railtie & Creating Plugins and Ilya’s comment responses to me.

Thanks to the new bundler guide, it’s a great improvement!!

4. Examples

As promised, here are som source code. I’ll show the gemspec, a tiny ruby version file and a nice Rakefile

my_private_gem.gemspec



# -*- encoding: utf-8 -*-
lib = File.expand_path('../lib/', __FILE__)
$:.unshift lib unless $:.include?(lib)
require "version"
Gem::Specification.new do |s|
s.name = %q{mygemname}
s.version = MyGem::VERSION
s.required_rubygems_version = ">= 1.3.6"
s.authors = ["you"]
s.date = %q{2010-09-13}
s.description = %q{describe the gem}
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.markdown"]
s.summary = %q{a quick summary}
s.add_dependency("httparty", ["~>0.6.1"])
s.add_development_dependency("shoulda", ["~>2.11.3"])
s.files = Dir.glob("lib/**/*") + %w(CHANGELOG LICENSE README.markdown Rakefile Manifest my_private_gem.gemspec)
s.require_path = "lib"
end

lib/version.rb


module MyPrivateGem
VERSION = "0.0.3"
end

Rakefile

require "version"

task :build do
  system "gem build my_private_gem.gemspec"
end

##TODO create helper rake task

task :tag => :build do
  puts "Tagging #{MyPrivateGem::VERSION}..."
  system "git tag -a #{MyPrivateGem::VERSION} -m 'Tagging #{MyPrivateGem::VERSION}'"
  puts "Pushing to git..."
  system "git push --tags"
end

desc "release gem to gemserver"
task :release => [:tag, :deploy] do
  puts "congrats, the gem is now tagged, pushed, deployed and released! Rember to up the VERSION number"
end

task :deploy do
  puts "Deploying to gemserver@mygemserver.mycompany.com"
  system "scp my_private_gem-#{MyPrivateGem::VERSION}.gem gemserver@mygemserver.mycompany.com:gems/."
  puts "installing on gemserver"
  system "ssh gemserver@mygemserver.mycompany.com \"cd gems && gem install my_private_gem-#{MyPrivateGem::VERSION}.gem --ignore-dependencies\""
end

UPDATE 28th sep2010

I’ve created a ruby script to help me update the gem dependency. But you still have to edit the version number in Gemfile after running this:

gemupdate_private_gems.rb

# HELPER for automatic install of new gem. Remember to change to Gemfile accordingly.
puts "Adding myco gemserver to sources"
system('gem source --add http://mygemserver.myco.com:8808')
puts "Installing new gem, unpack and replace existing versions"
system("gem install myprivategem")
system('rm -rf vendor/gems/myprivategem*')
system('gem unpack myprivategem --target vendor/gems/')
puts "Removing myco gemserver from sources"
system('gem source --remove http://mygemserver.myco.com:8808')
puts "done. NEXT: Set the correct GEM VERSION in Gemfile"
About these ads

About Ole Morten Amundsen

Developer, programmer, entrepreneur. Java, .Net, ruby, rails, agile, lean. Opinionated enthusiast!
This entry was posted in rails, ruby and tagged , , , . Bookmark the permalink.

4 Responses to Working with private RubyGems in Rails 3, deploying to Heroku

  1. Pingback: Installing private ruby gem in rails project using heroku | Just wondering….

  2. Another option, as per Heroku tech support is to put the username and password into the github URL, like it’s done for Basic HTTP Auth. Details here: http://stackoverflow.com/a/8949955/459863

  3. Robert Reiz says:

    What about referencing a private github repository?

  4. Ole Morten Amundsen says:

    yeah, that’s essentially what Wolfram said too.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s