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"
Pingback: Installing private ruby gem in rails project using heroku | Just wondering….
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
What about referencing a private github repository?
yeah, that’s essentially what Wolfram said too.
Pingback: Một số điều cần lưu ý khi viết ruby gem - AI Design - Thiết kế web theo yêu cầu tại Hồ Chí Minh