tasks/github-gem.rake in request-log-analyzer-1.2.3 vs tasks/github-gem.rake in request-log-analyzer-1.2.6

- old
+ new

@@ -1,249 +1,256 @@ require 'rubygems' -require 'rubyforge' require 'rake' require 'rake/tasklib' require 'date' +require 'git' -module Rake +module GithubGem - class GithubGem < TaskLib + def self.detect_gemspec_file + FileList['*.gemspec'].first + end + + def self.detect_main_include + if detect_gemspec_file =~ /^(\.*)\.gemspec$/ && File.exist?("lib/#{$1}.rb") + "lib/#{$1}.rb" + elsif FileList['lib/*.rb'].length == 1 + FileList['lib/*.rb'].first + else + raise "Could not detect main include file!" + end + end + + class RakeTasks - attr_accessor :name - attr_accessor :specification - - def self.define_tasks! - gem_task_builder = Rake::GithubGem.new - gem_task_builder.register_all_tasks! - end + attr_reader :gemspec, :modified_files, :git + attr_accessor :gemspec_file, :task_namespace, :main_include, :root_dir, :spec_pattern, :test_pattern, :remote, :remote_branch, :local_branch + + def initialize(task_namespace = :gem) + @gemspec_file = GithubGem.detect_gemspec_file + @task_namespace = task_namespace + @main_include = GithubGem.detect_main_include + @modified_files = [] + @root_dir = Dir.pwd + @test_pattern = 'test/**/*_test.rb' + @spec_pattern = 'spec/**/*_spec.rb' + @local_branch = 'master' + @remote = 'origin' + @remote_branch = 'master' + + + yield(self) if block_given? - def initialize - reload_gemspec! + @git = Git.open(@root_dir) + load_gemspec! + define_tasks! end + + protected + + def define_test_tasks! + require 'rake/testtask' - 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 + namespace(:test) do + Rake::TestTask.new(:basic) do |t| + t.pattern = test_pattern + t.verbose = true + t.libs << 'test' end end + + desc "Run all unit tests for #{gemspec.name}" + task(:test => ['test:basic']) + end - # Setup :spec task if RSpec files exist - if has_specs? - require 'spec/rake/spectask' + def define_rspec_tasks! + require 'spec/rake/spectask' - desc "Run all specs for #{@name}" - Spec::Rake::SpecTask.new(:spec) do |t| - t.spec_files = FileList['spec/**/*_spec.rb'] + namespace(:spec) do + desc "Verify all RSpec examples for #{gemspec.name}" + Spec::Rake::SpecTask.new(:basic) do |t| + t.spec_files = FileList[spec_pattern] end + + desc "Verify all RSpec examples for #{gemspec.name} and output specdoc" + Spec::Rake::SpecTask.new(:specdoc) do |t| + t.spec_files = FileList[spec_pattern] + t.spec_opts << '--format' << 'specdoc' << '--color' + end + + desc "Run RCov on specs for #{gemspec.name}" + Spec::Rake::SpecTask.new(:rcov) do |t| + t.spec_files = FileList[spec_pattern] + t.rcov = true + t.rcov_opts = ['--exclude', '"spec/*,gems/*"', '--rails'] + 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 + desc "Verify all RSpec examples for #{gemspec.name} and output specdoc" + task(:spec => ['spec:specdoc']) end - protected + # Defines the rake tasks + def define_tasks! + + define_test_tasks! if has_tests? + define_rspec_tasks! if has_specs? + + namespace(@task_namespace) do + desc "Updates the filelist in the gemspec file" + task(:manifest) { manifest_task } + + desc "Builds the .gem package" + task(:build => :manifest) { build_task } - def has_rdoc? - @specification.has_rdoc - end + desc "Sets the version of the gem in the gemspec" + task(:set_version => [:check_version, :check_current_branch]) { version_task } + task(:check_version => :fetch_origin) { check_version_task } + + task(:fetch_origin) { fetch_origin_task } + task(:check_current_branch) { check_current_branch_task } + task(:check_clean_status) { check_clean_status_task } + task(:check_not_diverged => :fetch_origin) { check_not_diverged_task } + + checks = [:check_current_branch, :check_clean_status, :check_not_diverged, :check_version] + checks.unshift('spec:basic') if has_specs? + checks.unshift('test:basic') if has_tests? + + desc "Perform all checks that would occur before a release" + task(:release_checks => checks) - def has_specs? - Dir['spec/**/*_spec.rb'].any? + desc "Release a new verison of the gem" + task(:release => [:release_checks, :set_version, :build, :push_changes]) { release_task } + + task(:push_changes => [:commit_modified_files, :tag_version]) { push_changes_task } + task(:tag_version) { tag_version_task } + task(:commit_modified_files) { commit_modified_files_task } + end end - def has_tests? - Dir['test/**/*_test.rb'].any? + def manifest_task + # Load all the gem's files using "git ls-files" + repository_files = git.ls_files.keys + test_files = Dir[test_pattern] + Dir[spec_pattern] + + update_gemspec(:files, repository_files) + update_gemspec(:test_files, repository_files & test_files) end - - def reload_gemspec! - raise "No gemspec file found!" if gemspec_file.nil? - spec = File.read(gemspec_file) - @specification = eval(spec) - @name = specification.name + + def build_task + sh "gem build -q #{gemspec_file}" + Dir.mkdir('pkg') unless File.exist?('pkg') + sh "mv #{gemspec.name}-#{gemspec.version}.gem pkg/#{gemspec.name}-#{gemspec.version}.gem" end - - def run_command(command) - lines = [] - IO.popen(command) { |f| lines = f.readlines } - return lines + + def version_task + update_gemspec(:version, ENV['VERSION']) if ENV['VERSION'] + update_gemspec(:date, Date.today) + + update_version_file(gemspec.version) + update_version_constant(gemspec.version) end - def git_modified?(file) - return !run_command('git status').detect { |line| Regexp.new(Regexp.quote(file)) =~ line }.nil? + def check_version_task + raise "#{ENV['VERSION']} is not a valid version number!" if ENV['VERSION'] && !Gem::Version.correct?(ENV['VERSION']) + proposed_version = Gem::Version.new(ENV['VERSION'] || gemspec.version) + # Loads the latest version number using the created tags + newest_version = git.tags.map { |tag| tag.name.split('-').last }.compact.map { |v| Gem::Version.new(v) }.max + raise "This version (#{proposed_version}) is not higher than the highest tagged version (#{newest_version})" if newest_version && newest_version >= proposed_version 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 + def check_not_diverged_task + raise "The current branch is diverged from the remote branch!" if git.log.between('HEAD', git.branches["#{remote}/#{remote_branch}"].gcommit).any? end - def git_create_tag(tag_name, message) - sh "git tag -a \"#{tag_name}\" -m \"#{message}\"" + def check_clean_status_task + raise "The current working copy contains modifications" if git.status.changed.any? 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}" + def check_current_branch_task + raise "Currently not on #{local_branch} branch!" unless git.branch.name == local_branch.to_s 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! + def fetch_origin_task + git.fetch('origin') 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! + def commit_modified_files_task + if modified_files.any? + modified_files.each { |file| git.add(file) } + git.commit("Released #{gemspec.name} gem version #{gemspec.version}") + end end - def gemspec_file - @gemspec_file ||= Dir['*.gemspec'].first + def tag_version_task + git.add_tag("#{gemspec.name}-#{gemspec.version}") 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 + def push_changes_task + git.push(remote, remote_branch, true) 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 + def release_task + puts + puts '------------------------------------------------------------' + puts "Released #{gemspec.name} version #{gemspec.version}" 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) + private + + def has_specs? + FileList[spec_pattern].any? end - def set_gem_version! - # update gemspec file - self.gemspec_version = ENV['VERSION'] if Gem::Version.correct?(ENV['VERSION']) - self.gemspec_date = Date.today + def has_tests? + FileList[test_pattern].any? 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" + + # Loads the gemspec file + def load_gemspec! + @gemspec = eval(File.read(@gemspec_file)) 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" + # Updates the VERSION file with the new version + def update_version_file(version) + if File.exists?('VERSION') + File.open('VERSION', 'w') { |f| f << version.to_s } + modified_files << 'VERSION' + end 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, "Updated #{gemspec_file} for release of version #{@specification.version}") if git_modified?(gemspec_file) - - # create tag and push changes - git_create_tag("#{@name}-#{@specification.version}", "Tagged version #{@specification.version}") - git_push('origin', 'master', [:tags]) + # Updates the VERSION constant in the main include file if it exists + def update_version_constant(version) + file_contents = File.read(main_include) + if file_contents.sub!(/^(\s+VERSION\s*=\s*)[^\s].*$/) { $1 + version.to_s.inspect } + File.open(main_include, 'w') { |f| f << file_contents } + modified_files << main_include + end end - def release_task - puts - puts '------------------------------------------------------------' - puts "Released #{@name} - version #{@specification.version}" + # Updates an attribute of the gemspec file. + # This function will open the file, and search/replace the attribute using a regular expression. + def update_gemspec(attribute, new_value, literal = false) + + unless literal + new_value = case new_value + when Array then "%w(#{new_value.join(' ')})" + when Hash, String then new_value.inspect + when Date then new_value.strftime('%Y-%m-%d').inspect + else raise "Cannot write value #{new_value.inspect} to gemspec file!" + end + end + + spec = File.read(gemspec_file) + regexp = Regexp.new('^(\s+\w+\.' + Regexp.quote(attribute.to_s) + '\s*=\s*)[^\s].*$') + if spec.sub!(regexp) { $1 + new_value } + File.open(gemspec_file, 'w') { |f| f << spec } + modified_files << gemspec_file + + # Reload the gemspec so the changes are incorporated + load_gemspec! + end end + end end - -Rake::GithubGem.define_tasks! \ No newline at end of file