Chris@0: # This code lets us redefine existing Rake tasks, which is extremely Chris@0: # handy for modifying existing Rails rake tasks. Chris@0: # Credit for the original snippet of code goes to Jeremy Kemper Chris@0: # http://pastie.caboo.se/9620 Chris@0: unless Rake::TaskManager.methods.include?('redefine_task') Chris@0: module Rake Chris@0: module TaskManager Chris@0: def redefine_task(task_class, args, &block) Chris@0: task_name, arg_names, deps = resolve_args([args]) Chris@0: task_name = task_class.scope_name(@scope, task_name) Chris@0: deps = [deps] unless deps.respond_to?(:to_ary) Chris@0: deps = deps.collect {|d| d.to_s } Chris@0: task = @tasks[task_name.to_s] = task_class.new(task_name, self) Chris@0: task.application = self Chris@0: task.add_description(@last_description) Chris@0: @last_description = nil Chris@0: task.enhance(deps, &block) Chris@0: task Chris@0: end Chris@0: Chris@0: end Chris@0: class Task Chris@0: class << self Chris@0: def redefine_task(args, &block) Chris@0: Rake.application.redefine_task(self, [args], &block) Chris@0: end Chris@0: end Chris@0: end Chris@0: end Chris@0: end Chris@0: Chris@0: namespace :db do Chris@0: namespace :migrate do Chris@0: desc 'Migrate database and plugins to current status.' Chris@0: task :all => [ 'db:migrate', 'db:migrate:plugins' ] Chris@0: Chris@0: desc 'Migrate plugins to current status.' Chris@0: task :plugins => :environment do Chris@0: Engines.plugins.each do |plugin| Chris@0: next unless plugin.respond_to?(:migration_directory) Chris@0: next unless File.exists? plugin.migration_directory Chris@0: puts "Migrating plugin #{plugin.name} ..." Chris@0: plugin.migrate Chris@0: end Chris@0: end Chris@0: Chris@0: desc 'For engines coming from Rails version < 2.0 or for those previously updated to work with Sven Fuch\'s fork of engines, you need to upgrade the schema info table' Chris@0: task :upgrade_plugin_migrations => :environment do Chris@0: svens_fork_table_name = 'plugin_schema_migrations' Chris@0: Chris@0: # Check if app was previously using Sven's fork Chris@0: if ActiveRecord::Base.connection.table_exists?(svens_fork_table_name) Chris@0: old_sm_table = svens_fork_table_name Chris@0: else Chris@0: old_sm_table = ActiveRecord::Migrator.proper_table_name(Engines.schema_info_table) Chris@0: end Chris@0: Chris@0: unless ActiveRecord::Base.connection.table_exists?(old_sm_table) Chris@0: abort "Cannot find old migration table - assuming nothing needs to be done" Chris@0: end Chris@0: Chris@0: # There are two forms of the engines schema info - pre-fix_plugin_migrations and post Chris@0: # We need to figure this out before we continue. Chris@0: Chris@0: results = ActiveRecord::Base.connection.select_rows( Chris@0: "SELECT version, plugin_name FROM #{old_sm_table}" Chris@0: ).uniq Chris@0: Chris@0: def insert_new_version(plugin_name, version) Chris@0: version_string = "#{version}-#{plugin_name}" Chris@0: new_sm_table = ActiveRecord::Migrator.schema_migrations_table_name Chris@0: Chris@0: # Check if the row already exists for some reason - maybe run this task more than once. Chris@0: return if ActiveRecord::Base.connection.select_rows("SELECT * FROM #{new_sm_table} WHERE version = #{version_string.dump.gsub("\"", "'")}").size > 0 Chris@0: Chris@0: puts "Inserting new version #{version} for plugin #{plugin_name}.." Chris@0: ActiveRecord::Base.connection.insert("INSERT INTO #{new_sm_table} (version) VALUES (#{version_string.dump.gsub("\"", "'")})") Chris@0: end Chris@0: Chris@0: # We need to figure out if they already used "fix_plugin_migrations" Chris@0: versions = {} Chris@0: results.each do |r| Chris@0: versions[r[1]] ||= [] Chris@0: versions[r[1]] << r[0].to_i Chris@0: end Chris@0: Chris@0: if versions.values.find{ |v| v.size > 1 } == nil Chris@0: puts "Fixing migration info" Chris@0: # We only have one listed migration per plugin - this is pre-fix_plugin_migrations, Chris@0: # so we build all versions required. In this case, all migrations should Chris@0: versions.each do |plugin_name, version| Chris@0: version = version[0] # There is only one version Chris@0: Chris@0: # We have to make an assumption that numeric migrations won't get this long.. Chris@0: # I'm not sure if there is a better assumption, it should work in all Chris@0: # current cases.. (touch wood..) Chris@0: if version.to_s.size < "YYYYMMDDHHMMSS".size Chris@0: # Insert version records for each migration Chris@0: (1..version).each do |v| Chris@0: insert_new_version(plugin_name, v) Chris@0: end Chris@0: else Chris@0: # If the plugin is new-format "YYYYMMDDHHMMSS", we just copy it across... Chris@0: # The case in which this occurs is very rare.. Chris@0: insert_new_version(plugin_name, version) Chris@0: end Chris@0: end Chris@0: else Chris@0: puts "Moving migration info" Chris@0: # We have multiple migrations listed per plugin - thus we can assume they have Chris@0: # already applied fix_plugin_migrations - we just copy it across verbatim Chris@0: versions.each do |plugin_name, version| Chris@0: version.each { |v| insert_new_version(plugin_name, v) } Chris@0: end Chris@0: end Chris@0: Chris@0: puts "Migration info successfully migrated - removing old schema info table" Chris@0: ActiveRecord::Base.connection.drop_table(old_sm_table) Chris@0: end Chris@0: Chris@0: desc 'Migrate a specified plugin.' Chris@0: task(:plugin => :environment) do Chris@0: name = ENV['NAME'] Chris@0: if plugin = Engines.plugins[name] Chris@0: version = ENV['VERSION'] Chris@0: puts "Migrating #{plugin.name} to " + (version ? "version #{version}" : 'latest version') + " ..." Chris@0: plugin.migrate(version ? version.to_i : nil) Chris@0: else Chris@0: puts "Plugin #{name} does not exist." Chris@0: end Chris@0: end Chris@0: end Chris@0: end Chris@0: Chris@0: Chris@0: namespace :db do Chris@0: namespace :fixtures do Chris@0: namespace :plugins do Chris@0: Chris@0: desc "Load plugin fixtures into the current environment's database." Chris@0: task :load => :environment do Chris@0: require 'active_record/fixtures' Chris@0: ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym) Chris@0: Dir.glob(File.join(RAILS_ROOT, 'vendor', 'plugins', ENV['PLUGIN'] || '**', Chris@0: 'test', 'fixtures', '*.yml')).each do |fixture_file| Chris@0: Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*')) Chris@0: end Chris@0: end Chris@0: Chris@0: end Chris@0: end Chris@0: end Chris@0: Chris@0: # this is just a modification of the original task in railties/lib/tasks/documentation.rake, Chris@0: # because the default task doesn't support subdirectories like /app or Chris@0: # /component. These tasks now include every file under a plugin's load paths (see Chris@0: # Plugin#load_paths). Chris@0: namespace :doc do Chris@0: Chris@0: plugins = FileList['vendor/plugins/**'].collect { |plugin| File.basename(plugin) } Chris@0: Chris@0: namespace :plugins do Chris@0: Chris@0: # Define doc tasks for each plugin Chris@0: plugins.each do |plugin| Chris@0: desc "Create plugin documentation for '#{plugin}'" Chris@0: Rake::Task.redefine_task(plugin => :environment) do Chris@0: plugin_base = RAILS_ROOT + "/vendor/plugins/#{plugin}" Chris@0: options = [] Chris@0: files = Rake::FileList.new Chris@0: options << "-o doc/plugins/#{plugin}" Chris@0: options << "--title '#{plugin.titlecase} Plugin Documentation'" Chris@0: options << '--line-numbers' << '--inline-source' Chris@0: options << '-T html' Chris@0: Chris@0: # Include every file in the plugin's load_paths (see Plugin#load_paths) Chris@0: if Engines.plugins[plugin] Chris@0: files.include("#{plugin_base}/{#{Engines.plugins[plugin].load_paths.join(",")}}/**/*.rb") Chris@0: end Chris@0: if File.exists?("#{plugin_base}/README") Chris@0: files.include("#{plugin_base}/README") Chris@0: options << "--main '#{plugin_base}/README'" Chris@0: end Chris@0: files.include("#{plugin_base}/CHANGELOG") if File.exists?("#{plugin_base}/CHANGELOG") Chris@0: Chris@0: if files.empty? Chris@0: puts "No source files found in #{plugin_base}. No documentation will be generated." Chris@0: else Chris@0: options << files.to_s Chris@0: sh %(rdoc #{options * ' '}) Chris@0: end Chris@0: end Chris@0: end Chris@0: end Chris@0: end Chris@0: Chris@0: Chris@0: Chris@0: namespace :test do Chris@0: task :warn_about_multiple_plugin_testing_with_engines do Chris@0: puts %{-~============== A Moste Polite Warninge ===========================~- Chris@0: Chris@0: You may experience issues testing multiple plugins at once when using Chris@0: the code-mixing features that the engines plugin provides. If you do Chris@0: experience any problems, please test plugins individually, i.e. Chris@0: Chris@0: $ rake test:plugins PLUGIN=my_plugin Chris@0: Chris@0: or use the per-type plugin test tasks: Chris@0: Chris@0: $ rake test:plugins:units Chris@0: $ rake test:plugins:functionals Chris@0: $ rake test:plugins:integration Chris@0: $ rake test:plugins:all Chris@0: Chris@0: Report any issues on http://dev.rails-engines.org. Thanks! Chris@0: Chris@0: -~===============( ... as you were ... )============================~-} Chris@0: end Chris@0: Chris@0: namespace :engines do Chris@0: Chris@0: def engine_plugins Chris@0: Dir["vendor/plugins/*"].select { |f| File.directory?(File.join(f, "app")) }.map { |f| File.basename(f) }.join(",") Chris@0: end Chris@0: Chris@0: desc "Run tests from within engines plugins (plugins with an 'app' directory)" Chris@0: task :all => [:units, :functionals, :integration] Chris@0: Chris@0: desc "Run unit tests from within engines plugins (plugins with an 'app' directory)" Chris@0: Rake::TestTask.new(:units => "test:plugins:setup_plugin_fixtures") do |t| Chris@0: t.pattern = "vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/unit/**/*_test.rb" Chris@0: t.verbose = true Chris@0: end Chris@0: Chris@0: desc "Run functional tests from within engines plugins (plugins with an 'app' directory)" Chris@0: Rake::TestTask.new(:functionals => "test:plugins:setup_plugin_fixtures") do |t| Chris@0: t.pattern = "vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/functional/**/*_test.rb" Chris@0: t.verbose = true Chris@0: end Chris@0: Chris@0: desc "Run integration tests from within engines plugins (plugins with an 'app' directory)" Chris@0: Rake::TestTask.new(:integration => "test:plugins:setup_plugin_fixtures") do |t| Chris@0: t.pattern = "vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/integration/**/*_test.rb" Chris@0: t.verbose = true Chris@0: end Chris@0: end Chris@0: Chris@0: namespace :plugins do Chris@0: Chris@0: desc "Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name)" Chris@0: task :all => [:warn_about_multiple_plugin_testing_with_engines, Chris@0: :units, :functionals, :integration] Chris@0: Chris@0: desc "Run all plugin unit tests" Chris@0: Rake::TestTask.new(:units => :setup_plugin_fixtures) do |t| Chris@0: t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/unit/**/*_test.rb" Chris@0: t.verbose = true Chris@0: end Chris@0: Chris@0: desc "Run all plugin functional tests" Chris@0: Rake::TestTask.new(:functionals => :setup_plugin_fixtures) do |t| Chris@0: t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/functional/**/*_test.rb" Chris@0: t.verbose = true Chris@0: end Chris@0: Chris@0: desc "Integration test engines" Chris@0: Rake::TestTask.new(:integration => :setup_plugin_fixtures) do |t| Chris@0: t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/integration/**/*_test.rb" Chris@0: t.verbose = true Chris@0: end Chris@0: Chris@0: desc "Mirrors plugin fixtures into a single location to help plugin tests" Chris@0: task :setup_plugin_fixtures => :environment do Chris@0: Engines::Testing.setup_plugin_fixtures Chris@0: end Chris@0: Chris@0: # Patch the default plugin testing task to have setup_plugin_fixtures as a prerequisite Chris@0: Rake::Task["test:plugins"].prerequisites << "test:plugins:setup_plugin_fixtures" Chris@0: end Chris@0: end