lib/core/build.rb in buildr-0.19.0 vs lib/core/build.rb in buildr-0.20.0

- old
+ new

@@ -6,17 +6,17 @@ 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}" } + Project.local_task("package"=>"build") { |name| "Packaging #{name}" } desc "Install packages created by the project" - Project.local_task("install") { |name| "Installing packages from #{name}" } + Project.local_task("install"=>"package") { |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}" } + Project.local_task("deploy"=>"package") { |name| "Deploying packages from #{name}" } [ :build, :clean, :package, :install, :uninstall, :deploy ].each do |name| Project.on_define { |project| project.recursive_task name } end @@ -43,131 +43,137 @@ 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 Release + THIS_VERSION_PATTERN = /THIS_VERSION|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}$") } + + # :call-seq: + # make() + # + # Make a release. + def make() + check + version = with_next_version { |filename, version| sh "rake deploy --rakefile #{filename}" } + tag version + commit version + "-SNAPSHOT" end - end - def initialize(rakefile = nil) - @rakefile = rakefile || Rake.application.rakefile - end + protected - attr_reader :rakefile + # :call-seq: + # check() + # + # Check that we don't have any local changes in the working copy. Fails if it finds anything + # in the working copy that is not checked into source control. + def check() + # Status check reveals modified file, but also SVN externals which we can safely ignore. + status = svn("status", "--ignore-externals").reject { |line| line =~ /^X\s/ } + fail "Uncommitted SVN files violate the First Principle Of Release!\n#{status}" unless + status.empty? + end + + # :call-seq: + # with_next_version() { |filename| ... } => version + # + # Yields to block with upgraded version number, before committing to use it. Returns the *new* + # current version number. + # + # We need a Rakefile with upgraded version numbers to run the build, but we don't want the + # Rakefile modified unless the build succeeds. So this method updates the version numbers in + # a separate (Rakefile.next) file, yields to the block with that filename, and if successful + # copies the new file over the existing one. + # + # Version numbers are updated as follows. The next release version becomes the current one, + # and the next version is upgraded by one to become the new next version. So: + # THIS_VERSION = 1.1.0 + # NEXT_VERSION = 1.2.0 + # becomes: + # THIS_VERSION = 1.2.0 + # NEXT_VERSION = 1.2.1 + # and the method will return 1.2.0. + def with_next_version() + new_filename = Rake.application.rakefile + ".next" + modified = change_version do |this_version, next_version| + one_after = next_version.split(".") + one_after[-1] = one_after[-1].to_i + 1 + [ next_version, one_after.join(".") ] + end + File.open(new_filename, "w") { |file| file.write modified } + begin + yield new_filename + mv new_filename, Rake.application.rakefile + ensure + rm new_filename rescue nil + end + File.read(Rake.application.rakefile).scan(THIS_VERSION_PATTERN)[0][1] + end - 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 + # :call-seq: + # change_version() { |this, next| ... } => rakefile + # + # Change version numbers in the current Rakefile, but without writing a new file (yet). + # Returns the contents of the Rakefile with the modified version numbers. + # + # This method yields to the block with the current (this) and next version numbers and expects + # an array with the new this and next version numbers. + def change_version() + rakefile = File.read(Rake.application.rakefile) + this_version = rakefile.scan(THIS_VERSION_PATTERN)[0][1] or + fail "Looking for THIS_VERSION = \"...\" in your Rakefile, none found" + next_version = rakefile.scan(NEXT_VERSION_PATTERN)[0][1] or + fail "Looking for NEXT_VERSION = \"...\" in your Rakefile, none found" + this_version, next_version = yield(this_version, next_version) + if verbose + puts "Upgrading version numbers:" + puts " This: #{this_version}" + puts " Next: #{next_version}" + end + rakefile.gsub(THIS_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{this_version}"}) }. + gsub(NEXT_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{next_version}"}) } + 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 + # :call-seq: + # tag(version) + # + # Tags the current working copy with the release version number. + def tag(version) + url = svn("info").scan(/URL: (.*)/)[0][0].sub(/trunk$/, "tags/#{version}") + svn "remove", url, "-m", "Removing old copy" rescue nil + svn "copy", Dir.pwd, url, "-m", "Release #{version}" + 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}" + # :call-seq: + # commit(version) + # + # Last, we commit what we currently have in the working copy. + def commit(version) + rakefile = File.read(Rake.application.rakefile). + gsub(THIS_VERSION_PATTERN) { |ver| ver.sub(/(["']).*\1/, %Q{"#{version}"}) }. + File.open(Rake.application.rakefile, "w") { |file| file.write rakefile } + svn "commit", "-m", "Changed version number to #{version}", Rake.application.rakefile 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 } + # :call-seq: + # svn(*args) + # + # Executes SVN command and returns the output. + def svn(*args) + cmd = "svn " + args.map { |arg| arg[" "] ? %Q{"#{arg}"} : arg }.join(" ") + puts cmd if verbose + `#{cmd}`.tap { fail "SVN command failed" unless $?.exitstatus == 0 } 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 } + task "release" do |task| + Release.make end end