A lot of Rails plugins are starting to be released as RubyGems. I’ve found using RubyGems to manage plugins has been easy and have several advantages over a standard Rails plugin:
- built in versioning
- easy installation – no more installing plugins to the wrong directory
- pick a specific version to use
- not having to add a bunch of code to the application tree
Since I’ve created several dozen plugins for Redmine, I decided to start releasing them as RubyGems. I hoping this will make it easier for the user to install and upgrade them. After spending a night converting four plugins, I found I was running the same commands again and again. That meant, I could script it for the remaining 29 plugins.
The process
After a few tweaks, I ended up with a simple procedural script that would:
- Checkout the master branch
- Update the master branch from origin
- Create a new branch called ‘gem’ to work in
- Add a configuration for jeweler to the Rakefile
- Add a VERSION file based on the version used in
init.rb
- Move the existing
init.rb
torails/init.rb
so Rails will load it from the gem - Generate a valid gemspec for the plugin
- Install the new gem
Finally, I would review the ‘gem’ branch and test out the newly minted gem in Redmine. If something went wrong, the entire ‘gem’ branch could be destroyed with git branch -D gem
. This let me finish converting the rest of the plugins in just a couple of hours.
The script
This script is still Redmine specific (how it parses the version and description) but it could easily be adapted to work with any Rails plugin. I’ve also shared this as a Gist, so feel free to fork and modify it there. Let me know if you used it and how it worked for you.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
#!/usr/bin/env ruby # Usage: # ruby plugin_to_gem.rb my_plugin_directory require 'fileutils' @plugin_dir = ARGV[0] @plugin_name = ARGV[0] def rakefile_content description = 'TODO' redmine_init_content = File.read('init.rb') if redmine_init_content.match(/description (.*$)/) description = $1.gsub("'",'').gsub('"','') end content =< true) do |dir| system('rake clean') system('git status') system('git checkout master') system('git merge origin/master') system('git checkout -b gem') # Rakefile File.open('Rakefile','a') do |file| file.puts(rakefile_content) end system('git commit -am "Updated rakefile for jeweler"') # VERSION File.open('VERSION','w') do |version_file| redmine_init_content = File.read('init.rb') if redmine_init_content.match(/version (.*$)/) version = $1.gsub("'",'').gsub('"','') version_file.puts version end end system('git add VERSION') system('git commit -am "Added Version file"') # Rails GemPlugin init.rb FileUtils.mkdir_p('rails') system('git mv init.rb rails/init.rb') File.open('init.rb','w') do |init_file| init_file.puts('require File.dirname(__FILE__) + "/rails/init"') end system('git add init.rb') system('git commit -am "Added init file for Rails GemPlugin"') # Gemspec system('rake gemspec') system("git add #{@plugin_name}.gemspec") system('git commit -am "Added generated gemspec"') # Install to test system('rake install') # Back to master to allow merging system('git checkout master') end |
Eric Davis