require "open3" require "core/project" module Buildr desc "Build the project" Project.local_task("build") { |name| "Building #{name}" } desc "Clean files generated during a build" Project.local_task("clean") { |name| "Cleaning #{name}" } desc "Create packages" Project.local_task("package") { |name| "Packaging #{name}" } desc "Install packages created by the project" Project.local_task("install") { |name| "Installing packages from #{name}" } desc "Remove previously installed packages" Project.local_task("uninstall") { |name| "Uninstalling packages from #{name}" } desc "Deploy packages created by the project" Project.local_task("deploy") { |name| "Deploying packages from #{name}" } [ :build, :clean, :package, :install, :uninstall, :deploy ].each do |name| Project.on_define { |project| project.recursive_task name } end class Project # :call-seq: # build(*prereqs) => task # build { |task| .. } => task # # Returns the project's build task. With arguments or block, also enhances that task. def build(*prereqs, &block) task("build").enhance prereqs, &block end # :call-seq: # build(*prereqs) => task # build { |task| .. } => task # # Returns the project's clean task. With arguments or block, also enhances that task. def clean(*prereqs, &block) task("clean").enhance prereqs, &block end end desc "The default task it build" task "default"=>"build" class Release #:nodoc: VERSION_NUMBER_PATTERN = /VERSION_NUMBER\s*=\s*(["'])(.*)\1/ NEXT_VERSION_PATTERN = /NEXT_VERSION\s*=\s*(["'])(.*)\1/ class << self def svn_ignores() @ignores = (@ignores || []).map { |pat| pat.is_a?(Regexp) ? pat : Regexp.new("^.*\s+#{Regexp.escape pat}$") } end end def initialize(rakefile = nil) @rakefile = rakefile || Rake.application.rakefile end attr_reader :rakefile def invoke() # Make sure we don't have anything uncommitted in SVN. check_status # Update current version to next version before deploying. next_ver = update_version # Run the deployment externally using the new version number # (from the modified Rakefile). sh "rake deploy" # Update the next version as well to the next increment and commit. update_next_version next_ver # Tag the repository for this release. tag_repository next_ver # Update the next version to end with -SNAPSHOT. update_version_to_snapshot next_ver end def check_status() ignores = Release.svn_ignores status = svn("status", "--ignore-externals", :verbose=>false). reject { |line| line =~ /^X\s/ || ignores.any? { |pat| line =~ pat } } fail "Uncommitted SVN files violate the First Principle Of Release!\n#{status}" unless status.empty? end # Change the Rakefile and update the current version number to the # next version number (VERSION_NUMBER = NEXT_VERSION). We need this # before making a release with the next version. Return the next version. def update_version() rakefile = read_rakefile version = rakefile.scan(VERSION_NUMBER_PATTERN)[0][1] or fail "Looking for VERSION_NUMBER = \"...\" in your Rakefile, none found" next_ver = rakefile.scan(NEXT_VERSION_PATTERN)[0][1] or fail "Looking for NEXT_VERSION = \"...\" in your Rakefile, none found" if verbose puts "Current version: #{version}" puts "Next version: #{next_ver}" end # Switch version numbers. write_rakefile rakefile.gsub(VERSION_NUMBER_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{next_ver}"}) } next_ver end # Change the Rakefile and update the next version number to one after # (NEXT_VERSION = NEXT_VERSION + 1). We do this to automatically increment # future version number after each successful release. def update_next_version(version) # Update to new version number. nums = version.split(".") nums[-1] = nums[-1].to_i + 1 next_ver = nums.join(".") write_rakefile read_rakefile.gsub(NEXT_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{next_ver}"}) } # Commit new version number. svn "commit", "-m", "Changed version number to #{version}", rakefile end # Create a tag in the SVN repository. def tag_repository(version) # Copy to tag. cur_url = svn("info").scan(/URL: (.*)/)[0][0] new_url = cur_url.sub(/trunk$/, "tags/#{version}") svn "remove", new_url, "-m", "Removing old copy" rescue nil svn "copy", cur_url, new_url, "-m", "Release #{version}" end def update_version_to_snapshot(version) version += "-SNAPSHOT" write_rakefile read_rakefile.gsub(VERSION_NUMBER_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{version}"}) } # Commit new version number. svn "commit", "-m", "Changed version number to #{version}", rakefile end protected def read_rakefile() File.read(rakefile) end def write_rakefile(contents) File.open(rakefile, "w") { |file| file.write contents } end def svn(*args) if Hash === args.last options = args.pop else options = { :verbose=>verbose } end puts ["svn", *args].join(" ") if options[:verbose] Open3.popen3("svn", *args) do |stdin, stdout, stderr| stdin.close error = stderr.read fail error unless error.empty? stdout.read.tap { |output| puts output if Rake.application.options.trace } end end end desc "Make a release" task("release").tap do |task| class << task def release() @release ||= Release.new end end task.enhance { task.release.invoke } end end