require 'rubygems'
require 'rubyforge'
require 'rake'
require 'rake/tasklib'
require 'date'
module Rake
class GithubGem < TaskLib
attr_accessor :name
attr_accessor :specification
def self.define_tasks!
gem_task_builder = Rake::GithubGem.new
gem_task_builder.register_all_tasks!
end
def initialize
reload_gemspec!
end
def register_all_tasks!
namespace(:gem) do
desc "Updates the file lists for this gem"
task(:manifest) { manifest_task }
desc "Releases a new version of #{@name}"
task(:build => [:manifest]) { build_task }
release_dependencies = [:check_clean_master_branch, :version, :build, :create_tag]
release_dependencies.push 'doc:publish' if has_rdoc?
release_dependencies.unshift 'test' if has_tests?
release_dependencies.unshift 'spec' if has_specs?
desc "Releases a new version of #{@name}"
task(:release => release_dependencies) { release_task }
# helper task for releasing
task(:check_clean_master_branch) { verify_clean_status('master') }
task(:check_version) { verify_version(ENV['VERSION'] || @specification.version) }
task(:version => [:check_version]) { set_gem_version! }
task(:create_tag) { create_version_tag! }
end
# Register RDoc tasks
if has_rdoc?
require 'rake/rdoctask'
namespace(:doc) do
desc 'Generate documentation for request-log-analyzer'
Rake::RDocTask.new(:compile) do |rdoc|
rdoc.rdoc_dir = 'doc'
rdoc.title = @name
rdoc.options += @specification.rdoc_options
rdoc.rdoc_files.include(@specification.extra_rdoc_files)
rdoc.rdoc_files.include('lib/**/*.rb')
end
desc "Publish RDoc files for #{@name} to Github"
task(:publish => :compile) do
sh 'git checkout gh-pages'
sh 'git pull origin gh-pages'
sh 'cp -rf doc/* .'
sh "git commit -am \"Publishing newest RDoc documentation for #{@name}\""
sh "git push origin gh-pages"
sh "git checkout master"
end
end
end
# Setup :spec task if RSpec files exist
if has_specs?
require 'spec/rake/spectask'
desc "Run all specs for #{@name}"
Spec::Rake::SpecTask.new(:spec) do |t|
t.spec_files = FileList['spec/**/*_spec.rb']
end
end
# Setup :test task if unit test files exist
if has_tests?
require 'rake/testtask'
desc "Run all unit tests for #{@name}"
Rake::TestTask.new(:test) do |t|
t.pattern = 'test/**/*_test.rb'
t.verbose = true
t.libs << 'test'
end
end
end
protected
def has_rdoc?
@specification.has_rdoc
end
def has_specs?
Dir['spec/**/*_spec.rb'].any?
end
def has_tests?
Dir['test/**/*_test.rb'].any?
end
def reload_gemspec!
raise "No gemspec file found!" if gemspec_file.nil?
spec = File.read(gemspec_file)
@specification = eval(spec)
@name = specification.name
end
def run_command(command)
lines = []
IO.popen(command) { |f| lines = f.readlines }
return lines
end
def git_modified?(file)
return !run_command('git status').detect { |line| Regexp.new(Regexp.quote(file)) =~ line }.nil?
end
def git_commit_file(file, message, branch = nil)
verify_current_branch(branch) unless branch.nil?
if git_modified?(file)
sh "git add #{file}"
sh "git commit -m \"#{message}\""
else
raise "#{file} is not modified and cannot be committed!"
end
end
def git_create_tag(tag_name, message)
sh "git tag -a \"#{tag_name}\" -m \"#{message}\""
end
def git_push(remote = 'origin', branch = 'master', options = [])
verify_clean_status(branch)
options_str = options.map { |o| "--#{o}"}.join(' ')
sh "git push #{options_str} #{remote} #{branch}"
end
def gemspec_version=(new_version)
spec = File.read(gemspec_file)
spec.gsub!(/^(\s*s\.version\s*=\s*)('|")(.+)('|")(\s*)$/) { "#{$1}'#{new_version}'#{$5}" }
spec.gsub!(/^(\s*s\.date\s*=\s*)('|")(.+)('|")(\s*)$/) { "#{$1}'#{Date.today.strftime('%Y-%m-%d')}'#{$5}" }
File.open(gemspec_file, 'w') { |f| f << spec }
reload_gemspec!
end
def gemspec_date=(new_date)
spec = File.read(gemspec_file)
spec.gsub!(/^(\s*s\.date\s*=\s*)('|")(.+)('|")(\s*)$/) { "#{$1}'#{new_date.strftime('%Y-%m-%d')}'#{$5}" }
File.open(gemspec_file, 'w') { |f| f << spec }
reload_gemspec!
end
def gemspec_file
@gemspec_file ||= Dir['*.gemspec'].first
end
def verify_current_branch(branch)
run_command('git branch').detect { |line| /^\* (.+)/ =~ line }
raise "You are currently not working in the master branch!" unless branch == $1
end
def verify_clean_status(on_branch = nil)
sh "git fetch"
lines = run_command('git status')
raise "You don't have the most recent version available. Run git pull first." if /^\# Your branch is behind/ =~ lines[1]
raise "You are currently not working in the #{on_branch} branch!" unless on_branch.nil? || (/^\# On branch (.+)/ =~ lines.first && $1 == on_branch)
raise "Your master branch contains modifications!" unless /^nothing to commit \(working directory clean\)/ =~ lines.last
end
def verify_version(new_version)
newest_version = run_command('git tag').map { |tag| tag.split(name + '-').last }.compact.map { |v| Gem::Version.new(v) }.max
raise "This version number (#{new_version}) is not higher than the highest tagged version (#{newest_version})" if !newest_version.nil? && newest_version >= Gem::Version.new(new_version.to_s)
end
def set_gem_version!
# update gemspec file
self.gemspec_version = ENV['VERSION'] if Gem::Version.correct?(ENV['VERSION'])
self.gemspec_date = Date.today
end
def manifest_task
verify_current_branch('master')
list = Dir['**/*'].sort
list -= [gemspec_file]
if File.exist?('.gitignore')
File.read('.gitignore').each_line do |glob|
glob = glob.chomp.sub(/^\//, '')
list -= Dir[glob]
list -= Dir["#{glob}/**/*"] if File.directory?(glob) and !File.symlink?(glob)
end
end
# update the spec file
spec = File.read(gemspec_file)
spec.gsub! /^(\s* s.(test_)?files \s* = \s* )( \[ [^\]]* \] | %w\( [^)]* \) )/mx do
assignment = $1
bunch = $2 ? list.grep(/^(test.*_test\.rb|spec.*_spec.rb)$/) : list
'%s%%w(%s)' % [assignment, bunch.join(' ')]
end
File.open(gemspec_file, 'w') { |f| f << spec }
reload_gemspec!
end
def build_task
sh "gem build #{gemspec_file}"
Dir.mkdir('pkg') unless File.exist?('pkg')
sh "mv #{name}-#{specification.version}.gem pkg/#{name}-#{specification.version}.gem"
end
def install_task
raise "#{name} .gem file not found" unless File.exist?("pkg/#{name}-#{specification.version}.gem")
sh "gem install pkg/#{name}-#{specification.version}.gem"
end
def uninstall_task
raise "#{name} .gem file not found" unless File.exist?("pkg/#{name}-#{specification.version}.gem")
sh "gem uninstall #{name}"
end
def create_version_tag!
# commit the gemspec file
git_commit_file(gemspec_file, "Released #{@name} version #{@specification.version}") if git_modified?(gemspec_file)
# create tag and push changes
git_create_tag("#{@name}-#{@specification.version}", "Tagged #{@name} version #{@specification.version}")
git_push('origin', 'master', [:tags])
end
def release_task
puts
puts '------------------------------------------------------------'
puts "Released #{@name} - version #{@specification.version}"
end
end
end
Rake::GithubGem.define_tasks!