-
1
require 'corundum/tasklib'
-
-
#require 'rubygems'
-
#require 'rubygems/installer'
-
-
1
module Corundum
-
1
extend Rake::DSL
-
-
1
class Toolkit < TaskLib
-
1
def default_configuration
-
settings(
-
:finished_dir => "corundum",
-
:finished_files => nested(
-
:build => nil,
-
:qa => nil,
-
:package => nil,
-
:release => nil,
-
:press => nil),
-
-
:browser => "chromium",
-
:gemspec => nil,
-
:gemspec_path => nil,
-
:email => nested(
-
:servers => [ nested({ :server => "ruby-lang.org", :helo => "gmail.com" }) ],
-
:announce_to_email => "ruby-talk@ruby-lang.org"
-
),
-
:package_dir => "pkg",
-
:files => nested(:code => nil, :test => nil, :docs => nil),
-
:file_lists => nested(:code => FileList['lib/**/*.rb'],
-
:test => FileList['test/**/*.rb','spec/**/*.rb','features/**/*.rb'],
-
:docs => FileList['doc/**/*.rb'],
-
:project => FileList['Rakefile'],
-
:all => nil),
-
:rubyforge => nested().nil_fields(:group_id, :package_id,
-
:release_name, :home_page, :project_page),
-
1
:doc_dir => "rubydoc"
-
)
-
end
-
-
1
def load_gemspec
-
1
@gemspec_path ||= guess_gemspec
-
1
@gemspec ||= Gem::Specification::load(gemspec_path)
-
1
return gemspec
-
end
-
-
1
def resolve_configuration
-
1
load_gemspec
-
-
1
@finished_files.build ||= File::join( package_dir, "#{gemspec.full_name}.gem")
-
-
1
@finished_files.qa ||= File::join( finished_dir, "qa_#{gemspec.version}")
-
1
@finished_files.release ||= File::join( finished_dir, "release_#{gemspec.version}")
-
1
@finished_files.press ||= File::join( finished_dir, "press_#{gemspec.version}")
-
-
1
@files.code ||= gemspec.files.grep(%r{^lib/})
-
1
@files.test ||= gemspec.files.grep(%r{^spec/})
-
1
@files.docs ||= gemspec.files.grep(%r{^doc/})
-
-
1
@file_lists.project << gemspec_path
-
1
@file_lists.all ||=
-
file_lists.code +
-
file_lists.test +
-
file_lists.docs
-
-
1
@rubyforge.group_id ||= gemspec.rubyforge_project
-
1
@rubyforge.package_id ||= gemspec.name.downcase
-
1
@rubyforge.release_name ||= gemspec.full_name
-
1
@rubyforge.home_page ||= gemspec.homepage
-
1
@rubyforge.project_page ||= "http://rubyforge.org/project/#{gemspec.rubyforge_project}/"
-
end
-
-
1
def guess_gemspec
-
1
speclist = Dir[File.expand_path("*.gemspec", Rake::original_dir)]
-
1
if speclist.length == 0
-
puts "Found no *.gemspec files"
-
exit 1
-
elsif speclist.length > 1
-
puts "Found too many *.gemspec files: #{speclist.inspect}"
-
exit 1
-
end
-
1
speclist[0]
-
end
-
-
1
def define
-
1
in_namespace do
-
1
directory finished_dir
-
-
1
desc "Run preflight checks"
-
1
task :preflight
-
-
1
desc "Run quality assurance tasks"
-
1
task :qa => [:preflight, finished_files.qa]
-
file finished_files.qa =>
-
1
[finished_dir] + file_lists.project + file_lists.code + file_lists.test do |task|
-
Rake::Task[:qa].invoke #because I don't want this to be needed if it's not
-
touch task.name
-
end
-
-
1
desc "Build the package"
-
1
task :build => [finished_files.qa, :preflight, finished_files.build]
-
file finished_files.build =>
-
1
[finished_dir] + file_lists.code + file_lists.project do |task|
-
Rake::Task[:build].invoke
-
touch task.name
-
end
-
-
1
desc "Push package out to the world"
-
1
task :release => [finished_files.build, :preflight, finished_files.release]
-
1
file finished_files.release => [finished_dir] do |task|
-
Rake::Task[:release].invoke
-
touch task.name
-
end
-
-
1
desc "Announce publication"
-
1
task :press => [finished_files.release, finished_files.press]
-
1
file finished_files.press => [finished_dir] do |task|
-
Rake::Task[:press].invoke
-
touch task.name
-
end
-
end
-
end
-
end
-
end
-
-
-
1
module Corundum
-
1
module Configurable
-
1
def local_attrs
-
@local_attrs ||=
-
begin
-
17
mod = Module.new
-
17
extend mod
-
17
mod
-
92
end
-
end
-
-
1
def local_attrs=(mod)
-
2
extend mod
-
2
@local_attrs = mod
-
end
-
-
1
def setting(name, default_value = nil)
-
92
local_attrs.instance_eval do
-
92
attr_accessor(name)
-
end
-
92
instance_variable_set("@#{name}", default_value)
-
end
-
-
1
def dup
-
2
result = super
-
2
result.extend Configurable
-
2
result.local_attrs = @local_attrs
-
2
result
-
end
-
-
1
def settings(hash)
-
10
hash.each_pair do |name, value|
-
42
setting(name, value)
-
end
-
10
return self
-
end
-
-
1
def nested(hash=nil)
-
9
obj = Object.new
-
9
obj.extend Configurable
-
9
obj.settings(hash || {})
-
9
return obj
-
end
-
-
1
def nil_fields(*names)
-
1
names.each do |name|
-
5
setting(name, nil)
-
end
-
1
return self
-
end
-
end
-
end
-
1
require 'corundum/tasklib'
-
-
1
module Corundum
-
1
class Email < TaskLib
-
1
def default_namespace
-
1
:email
-
end
-
-
1
def default_configuration(toolkit)
-
1
setting(:rubyforge, toolkit.rubyforge)
-
1
setting(:email_servers, [])
-
1
setting(:gemspec, toolkit.gemspec)
-
1
setting(:announce_to_email, nil)
-
1
setting(:urls, nested(:home_page => toolkit.gemspec.homepage,
-
:project_page => toolkit.rubyforge.project_page))
-
end
-
-
1
def announcement
-
changes = ""
-
begin
-
File::open("./Changelog", "r") do |changelog|
-
changes = "Changes:\n\n"
-
changes += changelog.read
-
end
-
rescue Exception
-
end
-
-
urls = "Project: #{urls.project_page}\n" +
-
"Homepage: #{urls.home_page}"
-
-
subject = "#{gemspec.name} #{gemspec.version} Released"
-
title = "#{gemspec.name} version #{gemspec.version} has been released!"
-
body = "#{gemspec.description}\n\n#{changes}\n\n#{urls}"
-
-
return subject, title, body
-
end
-
-
1
def define
-
1
desc 'Announce release on email'
-
1
task root_task => in_namespace("rubyforge", "email")
-
1
in_namespace do
-
1
file "email.txt" do |t|
-
require 'mailfactory'
-
-
subject, title, body= announcement
-
-
mail = MailFactory.new
-
mail.To = announce_to_email
-
mail.From = gemspec.email
-
mail.Subject = "[ANN] " + subject
-
mail.text = [title, body].join("\n\n")
-
-
File.open(t.name, "w") do |mailfile|
-
mailfile.write mail.to_s
-
end
-
end
-
-
1
task :email => "email.txt" do
-
require 'net/smtp'
-
-
email_servers.each do |server_config|
-
begin
-
File::open("email.txt", "r") do |email|
-
Net::SMTP.start(server_config[:server], 25, server_config[:helo], server_config[:username], server_config[:password]) do |smtp|
-
smtp.data do |mta|
-
mta.write(email.read)
-
end
-
end
-
end
-
break
-
rescue Object => ex
-
puts ex.message
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
1
require 'corundum/tasklib'
-
-
1
module Corundum
-
1
class GemBuilding < TaskLib
-
1
def default_configuration(toolkit)
-
1
setting(:gemspec, toolkit.gemspec)
-
1
setting(:qa_finished_file, toolkit.finished_files.qa)
-
1
setting(:package_dir, "pkg")
-
end
-
-
1
def define
-
1
require 'rubygems/package_task'
-
-
1
in_namespace do
-
1
package = Gem::PackageTask.new(gemspec) do |t|
-
1
t.need_tar_gz = true
-
1
t.need_tar_bz2 = true
-
1
t.package_dir = package_dir
-
end
-
-
1
task(:package).prerequisites.each do |package_type|
-
3
file package_type => qa_finished_file
-
end
-
end
-
-
1
task :build => in_namespace("gem")
-
end
-
end
-
end
-
1
require 'corundum/tasklib'
-
-
1
module Corundum
-
1
class GemCutter < TaskLib
-
1
def default_namespace
-
1
:gemcutter
-
end
-
-
1
def default_configuration(toolkit, build)
-
1
setting(:build, build)
-
1
setting(:gemspec, toolkit.gemspec)
-
1
setting(:build_finished_path, toolkit.finished_files.build)
-
1
setting(:gem_path, nil)
-
1
setting(:gem_name, toolkit.gemspec.full_name)
-
1
setting(:package_dir, build.package_dir)
-
end
-
-
1
def resolve_configuration
-
1
@gem_path ||= File::join(package_dir, gemspec.file_name)
-
end
-
-
1
module CommandTweaks
-
1
def setup_args(args = nil)
-
args ||= []
-
handle_options(args)
-
end
-
-
1
def gem_list=(list)
-
gems = list
-
end
-
-
1
def get_all_gem_names
-
return gems if defined?(gems)
-
super
-
end
-
-
1
def get_one_gem_name
-
return gems.first if defined?(gems)
-
super
-
end
-
end
-
-
1
def get_command(klass, args=nil)
-
cmd = klass.new
-
cmd.extend(CommandTweaks)
-
cmd.setup_args(args)
-
cmd
-
end
-
-
1
def define
-
1
in_namespace do
-
1
task :uninstall do |t|
-
when_writing("Uninstalling #{gem_name}") do
-
require "rubygems/commands/uninstall_command"
-
uninstall = get_command Gem::Commands::UninstallCommand
-
uninstall.options[:args] = [gem_path]
-
uninstall.execute
-
end
-
end
-
-
1
task :install => [gem_path] do |t|
-
when_writing("Installing #{gem_path}") do
-
require "rubygems/commands/install_command"
-
install = get_command Gem::Commands::InstallCommand
-
install.options[:args] = [gem_path]
-
install.execute
-
end
-
end
-
-
1
task :reinstall => [:uninstall, :install]
-
-
1
task :dependencies_available do
-
checker = Gem::SpecFetcher.new
-
gemspec.runtime_dependencies.each do |dep|
-
fulfilling = checker.find_matching(dep,false,false,false)
-
if fulfilling.empty?
-
fail "Dependency #{dep} is unfulfilled remotely"
-
else
-
puts "Remotely fulfilled: #{dep}" if verbose
-
end
-
end
-
end
-
-
1
task :is_unpushed do
-
checker = Gem::SpecFetcher.new
-
dep = Gem::Dependency.new(gemspec.name, "= #{gemspec.version}")
-
fulfilling = checker.find_matching(dep,false,false,false)
-
unless fulfilling.empty?
-
p fulfilling
-
fail "Gem #{gemspec.full_name} is already pushed"
-
end
-
end
-
-
1
desc 'Push a gem up to Gemcutter'
-
1
task :push => [:dependencies_available, :is_unpushed] do
-
require "rubygems/commands/push_command"
-
push = get_command(Gem::Commands::PushCommand)
-
push.options[:args] = [gem_path]
-
push.execute
-
end
-
1
task :push => build_finished_path
-
end
-
1
task :release => in_namespace(:push)
-
1
task :preflight => in_namespace(:dependencies_available, :is_unpushed)
-
end
-
end
-
end
-
1
require 'corundum/tasklib'
-
-
1
module Corundum
-
1
class GemspecSanity < TaskLib
-
1
def default_namespace
-
:gemspec_sanity
-
end
-
-
1
def default_configuration(toolkit)
-
setting(:gemspec, toolkit.gemspec)
-
end
-
-
1
def define
-
in_namespace do
-
task :files_exist do
-
missing = gemspec.files.find_all do |path|
-
not File::exists?(path)
-
end
-
-
fail "Files mentioned in gemspec are missing: #{missing.join(", ")}" unless missing.empty?
-
end
-
end
-
-
task :preflight => in_namespace(:files_exist)
-
end
-
end
-
end
-
1
require 'corundum/tasklib'
-
1
require 'rspec/core'
-
-
1
module Corundum
-
#TODO: this should take two command generators as arguments: the test runner,
-
#and the coverage tool - then the various tasks are the result of the
-
#collaboration of those two.
-
#
-
1
class RSpec < TaskLib
-
1
def default_namespace
-
1
:rspec
-
end
-
-
1
def default_configuration(toolkit)
-
1
setting(:task_options, nested(
-
:pattern => './spec{,/*/**}/*_spec.rb',
-
:ruby_opts => nil,
-
:rspec_configs => nil,
-
:rspec_opts => nil,
-
:warning => false,
-
:verbose => true,
-
:fail_on_error => true,
-
:ruby_opts => [],
-
:rspec_path => 'rspec',
-
:rspec_opts => %w{--format documentation --out last_run --color --format documentation},
-
:failure_message => "Spec examples failed.",
-
:files_to_run => "spec"
-
))
-
-
1
setting(:gemspec_path, toolkit.gemspec_path)
-
1
setting(:qa_finished_path, toolkit.finished_files.qa)
-
end
-
-
1
def resolve_configuration
-
#XXX Que?
-
1
@task_options.rspec_configs = task_options.rspec_opts
-
1
@task_options.rspec_opts = []
-
1
@task_options.rspec_path = %x"which #{task_options.rspec_path}".chomp
-
end
-
-
#XXX some point in the future, there needs to be a composible command
-
#object
-
1
def ruby_command(options)
-
cmd_parts = []
-
cmd_parts << RUBY
-
cmd_parts << options.ruby_opts
-
cmd_parts << "-w" if options.warning
-
if /^1\.8/ =~ RUBY_VERSION
-
cmd_parts << "-S"
-
end
-
return cmd_parts
-
end
-
-
1
def runner_command(options)
-
cmd_parts = []
-
cmd_parts << options.rspec_path
-
cmd_parts << options.rspec_opts
-
cmd_parts << options.files_to_run
-
return cmd_parts
-
end
-
-
1
def full_command(options)
-
cmd_parts = ruby_command(options) + runner_command(options)
-
return cmd_parts.flatten.compact.reject{|part| part.nil? or part.empty?}.join(" ")
-
end
-
-
1
def custom_options
-
2
options = task_options.dup
-
2
yield(options)
-
2
return options
-
end
-
-
1
def define_spec_task(name)
-
3
options = if block_given?
-
4
custom_options{|options| yield(options) if block_given?}
-
else
-
1
task_options
-
end
-
3
task name do
-
RakeFileUtils.send(:verbose, verbose) do
-
if options.files_to_run.empty?
-
puts "No examples matching #{options.pattern} could be found"
-
else
-
begin
-
cmd = full_command(options)
-
puts cmd if options.verbose
-
success = system(cmd)
-
rescue Object => ex
-
p ex
-
puts options.failure_message if options.failure_message
-
end
-
raise("ruby #{cmd} failed") if options.fail_on_error unless success
-
end
-
end
-
end
-
end
-
-
1
def define
-
1
in_namespace do
-
1
desc "Always run every spec"
-
1
define_spec_task(:all)
-
-
1
desc "Generate specifications documentation"
-
1
define_spec_task(:doc) do |t|
-
1
t.rspec_opts = %w{-o /dev/null -f d -o doc/Specifications}
-
1
t.failure_message = "Failed generating specification docs"
-
1
t.verbose = false
-
end
-
-
1
desc "Run only failing examples listed in last_run"
-
1
define_spec_task(:quick) do |t|
-
1
examples = []
-
1
begin
-
1
File.open("last_run", "r") do |fail_list|
-
1
fail_list.lines.grep(%r{^\s*\d+\)\s*(.*)}) do |line|
-
examples << $1.gsub(/'/){"[']"}
-
end
-
end
-
rescue
-
end
-
1
unless examples.empty?
-
t.rspec_opts << "--example"
-
t.rspec_opts << "\"#{examples.join("|")}\""
-
end
-
1
t.failure_message = "Spec examples failed."
-
end
-
end
-
-
1
desc "Run failing examples if any exist, otherwise, run the whole suite"
-
1
task root_task => in_namespace(:quick)
-
-
1
task :qa => in_namespace(:doc)
-
end
-
end
-
end
-
1
require 'corundum/tasklib'
-
-
-
#Big XXX: this totally isn't done. It's some notes against ever wanting to
-
#publish announcements to rubyforge ever again
-
-
1
module Corundum
-
1
class Publishing < TaskLib
-
1
def default_namespace
-
:rubyforge
-
end
-
-
1
def default_configuration(toolkit)
-
setting(:ns, ns)
-
setting(:rubyforge, nested(:package_id => nil, :group_id => nil, :release_name => nil))
-
setting(:package_dir, nil)
-
setting(:gemspec, nil)
-
end
-
-
1
def define
-
desc "Publish the gem and its documentation to Rubyforge and Gemcutter"
-
task root_task => in_namespace(:docs, :rubyforge)
-
-
in_namespace do
-
desc 'Publish RDoc to RubyForge'
-
task :docs do
-
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
-
host = "#{config["username"]}@rubyforge.org"
-
remote_dir = "/var/www/gforge-projects/#{@rubyforge[:group_id]}"
-
local_dir = 'rubydoc'
-
sh %{rsync -av --delete #{local_dir}/ #{host}:#{remote_dir}}
-
end
-
-
task :scrape_rubyforge do
-
require 'rubyforge'
-
forge = RubyForge.new
-
forge.configure
-
forge.scrape_project(@rubyforge[:package_id])
-
end
-
-
desc "Publishes to RubyForge"
-
task :rubyforge => [:docs, :scrape_rubyforge] do |t|
-
require 'rubyforge'
-
forge = RubyForge.new
-
forge.configure
-
files = [".gem", ".tar.gz", ".tar.bz2"].map do |extension|
-
File::join(@package_dir, @gemspec.full_name) + extension
-
end
-
release = forge.lookup("release", @rubyforge[:package_id])[@rubyforge[:release_name]] rescue nil
-
if release.nil?
-
forge.add_release(@rubyforge[:group_id], @rubyforge[:package_id], @rubyforge[:release_name], *files)
-
else
-
files.each do |file|
-
forge.add_file(@rubyforge[:group_id], @rubyforge[:package_id], @rubyforge[:release_name], file)
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
1
require 'corundum/tasklib'
-
-
1
module Corundum
-
1
class SimpleCov < TaskLib
-
1
def default_namespace
-
1
:coverage
-
end
-
-
1
def default_configuration(toolkit, testlib)
-
1
setting(:test_lib, testlib)
-
1
setting(:browser, toolkit.browser)
-
1
setting(:report_dir, "doc/coverage")
-
1
setting(:report_path, nil)
-
1
setting(:config_file, ".simplecov")
-
1
setting(:config_path, nil)
-
1
setting(:filters, ["./spec"])
-
-
1
setting(:coverage_filter, proc do |path|
-
/\.rb$/ =~ path
-
end)
-
-
1
setting(:threshold, 80)
-
1
setting(:groups, {})
-
1
setting(:code_files, toolkit.files.code)
-
1
setting(:all_files, toolkit.file_lists.project + toolkit.file_lists.code + toolkit.file_lists.test)
-
end
-
-
1
def resolve_configuration
-
1
@config_path ||= File::expand_path(config_file, Rake::original_dir)
-
1
@report_path ||= File::join(report_dir, "index.html")
-
end
-
-
1
def filter_lines
-
return filters.map do |pattern|
-
"add_filter \"#{pattern}\""
-
end
-
end
-
-
1
def group_lines
-
lines = []
-
groups.each_pair do |group, pattern|
-
lines << "add_group \"#{group}\", \"#{pattern}\""
-
end
-
lines
-
end
-
-
1
def config_file_contents
-
contents = ["SimpleCov.start do"]
-
contents << " coverage_dir \"#{report_dir}\""
-
contents += filter_lines.map{|line| " " + line}
-
contents += group_lines.map{|line| " " + line}
-
contents << "end"
-
return contents.join("\n")
-
end
-
-
1
def define
-
1
in_namespace do
-
1
file "Rakefile"
-
-
1
task :example_config do
-
$stderr.puts "Try this in #{config_path}"
-
$stderr.puts
-
puts config_file_contents
-
end
-
-
1
task :config_exists do
-
File::exists?(File::join(Rake::original_dir, ".simplecov")) or fail "No .simplecov"
-
end
-
-
1
directory File::dirname(report_path)
-
1
file report_path => all_files do
-
options = @test_lib.custom_options do |options|
-
options.rspec_opts += %w{-r simplecov}
-
end
-
sh @test_lib.full_command(options)
-
end
-
-
1
task :generate_report => [:preflight, report_path]
-
-
1
desc "View coverage in browser"
-
1
task :view => report_path do
-
sh "#{browser} #{report_path}"
-
end
-
-
1
task :verify_coverage => :generate_report do
-
require 'nokogiri'
-
-
doc = Nokogiri::parse(File::read(report_path))
-
-
coverage_total_xpath = "//span[@class='covered_percent']/span"
-
percentage = doc.xpath(coverage_total_xpath).first.content.to_f
-
-
raise "Coverage must be at least #{threshold} but was #{percentage}" if percentage < threshold
-
puts "Coverage is #{percentage}% (required: #{threshold}%)"
-
end
-
-
1
task :find_stragglers => :generate_report do
-
require 'nokogiri'
-
-
doc = Nokogiri::parse(File::read(report_path))
-
-
covered_files = doc.xpath(
-
"//table[@class='file_list']//td//a[@class='src_link']").map do |link|
-
link.content
-
end
-
need_coverage = @code_files.find_all(&coverage_filter)
-
-
not_listed = covered_files - need_coverage
-
not_covered = need_coverage - covered_files
-
unless not_listed.empty? and not_covered.empty?
-
raise ["Covered files and gemspec manifest don't match:",
-
"Not in gemspec: #{not_listed.inspect}",
-
"Not covered: #{not_covered.inspect}"].join("\n")
-
end
-
end
-
end
-
1
task :preflight => in_namespace(:config_exists)
-
-
1
task :qa => in_namespace(:verify_coverage, :find_stragglers)
-
end
-
end
-
end
-
1
require 'ostruct'
-
1
require 'rake/tasklib'
-
1
require 'corundum/configurable'
-
-
1
module Corundum
-
1
class TaskLib < Rake::TaskLib
-
1
include Configurable
-
-
1
def default_configuration(*tasklibs)
-
end
-
-
1
def resolve_configuration
-
end
-
-
1
def in_namespace(*tasknames)
-
23
if tasknames.empty?
-
10
if block_given?
-
10
if @namespace_name.nil?
-
3
yield
-
else
-
7
namespace @namespace_name do
-
7
yield
-
end
-
end
-
end
-
else
-
13
tasknames.map do |taskname|
-
18
[@namespace_name, taskname].compact.join(":")
-
end
-
end
-
end
-
-
1
def root_task
-
3
@namespace_name || :default
-
end
-
-
1
def default_namespace
-
nil
-
end
-
-
1
def [](taskname)
-
in_namespace(taskname).first
-
end
-
-
1
def initialize(*tasklibs)
-
8
setting(:namespace_name, default_namespace)
-
-
8
default_configuration(*tasklibs)
-
-
8
yield self if block_given?
-
-
8
resolve_configuration
-
-
8
define
-
end
-
end
-
end
-
1
require 'corundum/rspec'
-
1
require 'corundum/simplecov'
-
1
require 'corundum/gemspec_sanity'
-
1
require 'corundum/gem_building'
-
1
require 'corundum/gemcutter'
-
1
require 'corundum/email'
-
1
require 'corundum/version_control/monotone'
-
1
require 'corundum/version_control/git'
-
1
require 'corundum/yardoc'
-
1
require 'corundum/tasklib'
-
-
1
module Corundum
-
1
class VersionControl < TaskLib
-
1
def default_namespace
-
1
:version_control
-
end
-
-
1
def default_configuration(toolkit)
-
1
setting(:gemspec, toolkit.gemspec)
-
1
setting(:build_finished_file, toolkit.finished_files.build)
-
1
setting(:gemspec_files, toolkit.files.code + toolkit.files.test)
-
1
setting(:tag, toolkit.gemspec.version.to_s)
-
end
-
-
1
def define
-
1
in_namespace do
-
1
task :not_tagged
-
1
task :gemspec_files_added
-
1
task :workspace_committed
-
1
task :is_checked_in => %w{gemspec_files_added workspace_committed}
-
1
task :tag
-
1
task :check_in => :tag
-
end
-
-
1
task :preflight => in_namespace(:not_tagged)
-
1
task :build => in_namespace(:is_checked_in)
-
1
in_namespace(:tag, :check_in).each do |taskname|
-
2
task taskname => build_finished_file
-
end
-
1
task :release => in_namespace(:tag, :check_in)
-
end
-
end
-
end
-
1
require 'corundum/version_control'
-
-
1
module Corundum
-
1
class Git < VersionControl
-
1
def default_configuration(*args)
-
super
-
setting(:branch, nil)
-
end
-
-
1
def resolve_configuration
-
@branch ||= guess_branch
-
end
-
-
-
1
def git_command(*args)
-
result = ""
-
pid = nil
-
command = "git --no-pager #{args.join(" ")}"
-
puts command if verbose
-
pipe = IO.popen(command)
-
pid = pipe.pid
-
Process::wait(pid)
-
result = pipe.read
-
pipe.close
-
unless $?.exitstatus == 0
-
fail "Git exited with status #{$?.exitstatus}: \n#{result}"
-
end
-
return result.split("\n")
-
end
-
-
1
def guess_branch
-
puts "Guessing branch - configure Git > branch"
-
branch = git_command("branch").grep(/^\*/).first.sub(/\*\s*/,"").chomp
-
puts " Guessed: #{branch}"
-
return branch
-
end
-
-
1
def define
-
super
-
-
in_namespace do
-
task :on_branch do
-
current_branch = git_command("branch").grep(/^\*/).first.sub(/\*\s*/,"").chomp
-
unless current_branch == branch
-
fail "Current branch \"#{current_branch}\" is not #{branch}"
-
end
-
end
-
-
task :not_tagged => :on_branch do
-
tags = git_command("tag", "-l", tag)
-
unless tags.empty?
-
fail "Tag #{tag} already exists in branch #{branch}"
-
end
-
end
-
-
task :workspace_committed => :on_branch do
-
diffs = git_command("diff", "--stat", "HEAD")
-
unless diffs.empty?
-
fail "Workspace not committed:\n #{diffs.join(" \n")}"
-
end
-
end
-
-
task :gemspec_files_added => :on_branch do
-
list = git_command(%w{ls-tree -r HEAD})
-
list.map! do |line|
-
line.split(/\s+/)[3]
-
end
-
-
missing = gemspec_files - list
-
unless missing.empty?
-
fail "Gemspec files not in version control: #{missing.join(", ")}"
-
end
-
end
-
-
task :is_pulled do
-
fetch = git_command("fetch", "--dry-run")
-
unless fetch.empty?
-
fail "Remote branch has unpulled changes"
-
end
-
-
remote = git_command("config", "--get", "branch.#{branch}.remote").first
-
merge = git_command("config", "--get", "branch.#{branch}.merge").first.split("/").last
-
-
ancestor = git_command("merge-base", branch, "#{remote}/#{merge}").first
-
remote_rev = File::read(".git/refs/remotes/#{remote}/#{merge}").chomp
-
-
unless ancestor == remote_rev
-
fail "Unmerged changes with remote branch #{remote}/#{merge}"
-
end
-
end
-
task :is_checked_in => :is_pulled
-
-
task :tag => :on_branch do
-
git_command("tag", tag)
-
end
-
-
task :push => :on_branch do
-
git_command("push")
-
end
-
-
task :check_in => [:push]
-
end
-
end
-
end
-
end
-
1
require 'corundum/version_control'
-
1
require 'strscan'
-
-
1
module Corundum
-
1
class Monotone < VersionControl
-
1
def default_configuration(*args)
-
1
super
-
1
setting(:branch, nil)
-
end
-
-
1
def resolve_configuration
-
1
@branch ||= guess_branch
-
end
-
-
1
def mtn_automate(cmd, *args)
-
2
command = "mtn automate #{cmd} #{args.join(" ")}"
-
2
puts command if verbose
-
2
pipe = IO.popen(command)
-
2
pid = pipe.pid
-
2
Process.wait(pid)
-
2
result = pipe.read
-
2
pipe.close
-
2
unless $?.exitstatus == 0
-
fail "Monotone failed with exit status #{$?.exitstatus}: \n#{result}"
-
end
-
2
return result
-
end
-
-
1
def parse_basic_io(string)
-
1
items = []
-
1
scanner = StringScanner.new(string)
-
1
scanner.scan(/\s*/m)
-
1
until scanner.eos? do
-
-
20
symbol = scanner.scan(/[a-z_]*/)
-
20
scanner.scan(/\s*/)
-
20
value = ""
-
20
case scanner.scan(/["\[]/)
-
when '"'
-
16
while (value += scanner.scan(/[^"]*/)) =~ /\\$/
-
end
-
16
scanner.scan(/"/)
-
when '['
-
4
value = scanner.scan(/[^\]]*/)
-
4
scanner.scan(/]/)
-
else
-
raise "Improperly formatted basic_io: \
-
\n Got: #{items.inspect} + #{symbol}\
-
\n Rest:\
-
\n #{scanner.rest}"
-
end
-
20
items << [symbol, value]
-
20
scanner.scan(/\s*/m)
-
end
-
1
return items
-
end
-
-
1
def parse_certs(string)
-
1
items = parse_basic_io(string)
-
1
pair = []
-
1
hash = Hash.new do |h,k|
-
4
h[k] = []
-
end
-
1
items.each do |name, value|
-
20
case name
-
when "name"
-
4
pair[0] = value
-
when "value"
-
4
pair[1] = value
-
when "trust"
-
4
if value == "trusted"
-
4
hash[pair[0]] << pair[1]
-
end
-
4
pair = []
-
end
-
end
-
1
hash
-
end
-
-
1
def base_revision
-
1
mtn_automate("get_base_revision_id").chomp
-
end
-
-
1
def guess_branch
-
1
puts "Guessing branch - configure Monotone > branch"
-
1
certs = parse_certs(mtn_automate("certs", base_revision))
-
1
puts " Guessed: #{certs["branch"].first}"
-
1
certs["branch"].first
-
end
-
-
-
-
1
def stanzas(first_item, items)
-
stanzas = []
-
current_stanza = {}
-
items.each do |name, value|
-
if name == first_item
-
current_stanza = {}
-
stanzas << current_stanza
-
end
-
current_stanza[name] = value
-
end
-
return stanzas
-
end
-
-
1
def define
-
1
super
-
-
1
in_namespace do
-
1
task :on_branch do
-
branches = parse_certs(mtn_automate("certs", base_revision))["branch"] || []
-
unless branches.include?(branch)
-
fail "Not on branch #{branch}"
-
end
-
end
-
-
1
task :not_tagged do
-
items = parse_basic_io(mtn_automate("tags", branch))
-
tags = items.find{|pair| pair[0] == "tag" && pair[1] == tag}
-
unless tags.nil?
-
fail "Tag #{tag} already exists in branch #{branch}"
-
end
-
end
-
-
1
task :workspace_committed => :on_branch do
-
items = parse_basic_io(mtn_automate("inventory"))
-
changed = items.find{|pair| pair[0] == "changes"}
-
unless changed.nil?
-
fail "Uncommitted changes exist in workspace"
-
end
-
end
-
-
1
task :gemspec_files_added => :on_branch do
-
items = stanzas("path", parse_basic_io(mtn_automate("inventory")))
-
items.delete_if{|item| item["status"] == "unknown"}
-
known_paths = items.each_with_object({}) do |item, hash|
-
hash[item["path"]] = true
-
end
-
-
files = gemspec_files.dup
-
files.delete_if{|path| known_paths[path]}
-
unless files.empty?
-
fail "Gemspec files not in version control: #{files.join(" ")}"
-
end
-
end
-
-
1
task :tag => :on_branch do
-
mtn_automate("cert", base_revision, "tag", tag)
-
end
-
-
1
task :sync do
-
mtn_automate("sync")
-
end
-
-
1
task :check_in => [:sync]
-
end
-
end
-
end
-
end
-
1
require 'corundum/tasklib'
-
1
require 'yard/rake/yardoc_task'
-
-
1
module Corundum
-
1
class YARDoc < TaskLib
-
1
def default_namespace
-
1
:documentation
-
end
-
-
1
def default_configuration(toolkit)
-
1
setting(:gemspec, toolkit.gemspec)
-
1
setting(:doc_dir, "rubydoc")
-
1
setting(:files, nested(:code => [], :docs => []))
-
end
-
-
1
def define
-
1
directory doc_dir
-
-
1
in_namespace do
-
1
YARD::Rake::YardocTask.new(:docs) do |rd|
-
1
rd.options += gemspec.rdoc_options
-
1
rd.options += ["--output-dir", doc_dir]
-
1
rd.files += files.code
-
1
rd.files += files.docs
-
1
rd.files += gemspec.extra_rdoc_files
-
end
-
end
-
-
1
desc "Generate documentation based on code using YARD"
-
1
task root_task => in_namespace("docs")
-
end
-
end
-
end