2010-02-01 02:27:32 +00:00
require 'open3'
module Rails
module Upgrading
class ApplicationChecker
def initialize
@issues = [ ]
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
raise NotInRailsAppError unless in_rails_app?
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
def in_rails_app?
File . exist? ( " config/environment.rb " )
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Run all the check methods
def run
2010-02-05 16:21:46 +00:00
# Ruby 1.8 returns method names as strings whereas 1.9 uses symbols
the_methods = ( self . public_methods - Object . methods ) - [ :run , :initialize , " run " , " initialize " ]
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
the_methods . each { | m | send m }
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Check for deprecated ActiveRecord calls
def check_ar_methods
files = [ ]
2010-02-04 15:27:37 +00:00
[ " find(:all " , " find(:first " , " find.*:conditions => " , " :joins => " ] . each do | v |
2010-02-01 02:27:32 +00:00
lines = grep_for ( v , " app/ " )
files += extract_filenames ( lines ) || [ ]
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
unless files . empty?
alert (
2010-06-04 21:25:51 +00:00
" Soon-to-be-deprecated ActiveRecord calls " ,
2010-02-01 02:27:32 +00:00
" Methods such as find(:all), find(:first), finds with conditions, and the :joins option will soon be deprecated. " ,
" http://m.onkey.org/2010/1/22/active-record-query-interface " ,
files
)
end
lines = grep_for ( " named_scope " , " app/models/ " )
files = extract_filenames ( lines )
2010-06-04 21:25:51 +00:00
2011-04-07 23:22:18 +00:00
unless files . empty?
2010-02-01 02:27:32 +00:00
alert (
2010-06-04 21:25:51 +00:00
" named_scope is now just scope " ,
2010-02-01 02:27:32 +00:00
" The named_scope method has been renamed to just scope. " ,
" http://github.com/rails/rails/commit/d60bb0a9e4be2ac0a9de9a69041a4ddc2e0cc914 " ,
files
)
end
end
2010-07-17 04:54:55 +00:00
2010-07-17 05:02:42 +00:00
def check_validation_on_methods
2010-07-17 04:54:55 +00:00
files = [ ]
[ " validate_on_create " , " validate_on_update " ] . each do | v |
lines = grep_for ( v , " app/models/ " )
files += extract_filenames ( lines ) || [ ]
end
2010-07-17 05:05:28 +00:00
unless files . empty?
2010-07-17 04:54:55 +00:00
alert (
2010-07-17 05:02:42 +00:00
" Updated syntax for validate_on_* methods " ,
" Validate-on-callback methods (validate_on_create/validate_on_destroy) have been changed to validate :x, :on => :create " ,
2010-07-17 04:54:55 +00:00
" https://rails.lighthouseapp.com/projects/8994/tickets/3880-validate_on_create-and-validate_on_update-no-longer-seem-to-exist " ,
files
)
end
end
2010-07-17 05:02:42 +00:00
def check_before_validation_on_methods
files = [ ]
%w( before_validation_on_create before_validation_on_update ) . each do | v |
lines = grep_for ( v , " app/models/ " )
files += extract_filenames ( lines ) || [ ]
end
2010-07-17 05:05:28 +00:00
unless files . empty?
2010-07-17 05:02:42 +00:00
alert (
" Updated syntax for before_validation_on_* methods " ,
" before_validation_on_* methods have been changed to before_validation(:on => :create/:update) { ... } " ,
" https://rails.lighthouseapp.com/projects/8994/tickets/4699-before_validation_on_create-and-before_validation_on_update-doesnt-exist " ,
files
)
end
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Check for deprecated router syntax
def check_routes
2010-02-03 03:13:32 +00:00
lines = [ " map \\ . " , " ActionController::Routing::Routes " , " \\ .resources " ] . map do | v |
2010-02-01 02:27:32 +00:00
grep_for ( v , " config/routes.rb " ) . empty? ? nil : true
end . compact
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
unless lines . empty?
alert (
2010-06-04 21:25:51 +00:00
" Old router API " ,
2010-02-01 02:27:32 +00:00
" The router API has totally changed. " ,
" http://yehudakatz.com/2009/12/26/the-rails-3-router-rack-it-up/ " ,
" config/routes.rb "
)
end
end
2010-06-04 21:25:51 +00:00
2010-02-03 16:58:52 +00:00
# Check for deprecated test_help require
def check_test_help
files = [ ]
# Hate to duplicate code, but we have to double quote this one...
lines = grep_for ( " \' test_help \' " , " test/ " , true )
files += extract_filenames ( lines ) || [ ]
lines = grep_for ( " \" test_help \" " , " test/ " )
files += extract_filenames ( lines ) || [ ]
2010-06-04 21:25:51 +00:00
2010-02-03 16:58:52 +00:00
files . uniq!
2010-06-04 21:25:51 +00:00
2010-02-03 16:58:52 +00:00
unless files . empty?
alert (
2010-06-04 21:25:51 +00:00
" Deprecated test_help path " ,
2010-02-03 16:58:52 +00:00
" You now must require 'rails/test_help' not just 'test_help'. " ,
" http://weblog.rubyonrails.org/2009/9/1/gem-packaging-best-practices " ,
files
)
end
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Check for old (pre-application.rb) environment.rb file
def check_environment
unless File . exist? ( " config/application.rb " )
alert (
2010-06-04 21:25:51 +00:00
" New file needed: config/application.rb " ,
2010-02-01 02:27:32 +00:00
" You need to add a config/application.rb. " ,
" http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade " ,
" config/application.rb "
)
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
lines = grep_for ( " config. " , " config/environment.rb " )
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
unless lines . empty?
alert (
2010-06-04 21:25:51 +00:00
" Old environment.rb " ,
2010-02-01 02:27:32 +00:00
" environment.rb doesn't do what it used to; you'll need to move some of that into application.rb. " ,
" http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade " ,
" config/environment.rb "
)
end
end
2010-06-04 21:25:51 +00:00
2010-02-06 04:10:12 +00:00
# Check for deprecated constants
def check_deprecated_constants
files = [ ]
[ " RAILS_ENV " , " RAILS_ROOT " , " RAILS_DEFAULT_LOGGER " ] . each do | v |
lines = grep_for ( v , " app/ " )
files += extract_filenames ( lines ) || [ ]
2010-06-04 21:25:51 +00:00
2010-02-06 04:10:12 +00:00
lines = grep_for ( v , " lib/ " )
files += extract_filenames ( lines ) || [ ]
end
2010-06-04 21:25:51 +00:00
2010-02-06 04:10:12 +00:00
unless files . empty?
alert (
2010-06-04 21:25:51 +00:00
" Deprecated constant(s) " ,
2010-02-06 04:10:12 +00:00
" Constants like RAILS_ENV, RAILS_ROOT, and RAILS_DEFAULT_LOGGER are now deprecated. " ,
" http://litanyagainstfear.com/blog/2010/02/03/the-rails-module/ " ,
files . uniq
)
end
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Check for old-style config.gem calls
def check_gems
lines = grep_for ( " config.gem " , " config/*.rb " )
2011-04-07 23:22:18 +00:00
lines += grep_for ( " config.gem " , " config/**/*.rb " )
2010-02-01 02:27:32 +00:00
files = extract_filenames ( lines )
2010-06-04 21:25:51 +00:00
2011-04-07 23:22:18 +00:00
unless files . empty?
2010-02-01 02:27:32 +00:00
alert (
2010-06-04 21:25:51 +00:00
" Old gem bundling (config.gems) " ,
2010-02-01 02:27:32 +00:00
" The old way of bundling is gone now. You need a Gemfile for bundler. " ,
" http://omgbloglol.com/post/353978923/the-path-to-rails-3-approaching-the-upgrade " ,
files
)
end
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Checks for old mailer syntax in both mailer classes and those
# classes utilizing the mailers
def check_mailers
lines = grep_for ( " deliver_ " , " app/models/ #{ base_path } app/controllers/ #{ base_path } app/observers/ " )
files = extract_filenames ( lines )
2010-06-04 21:25:51 +00:00
2011-04-07 23:22:18 +00:00
unless files . empty?
2010-02-01 02:27:32 +00:00
alert (
2010-06-04 21:25:51 +00:00
" Deprecated ActionMailer API " ,
2010-02-01 02:27:32 +00:00
" You're using the old ActionMailer API to send e-mails in a controller, model, or observer. " ,
" http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3 " ,
files
)
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
files = [ ]
2010-06-04 21:50:16 +00:00
[ " recipients " , " attachment(?!s) " , " (?<!:)subject " , " (?<!:)from " ] . each do | v |
lines = grep_for_with_perl_regex ( v , " app/models/ " )
2010-02-01 02:27:32 +00:00
files += extract_filenames ( lines ) || [ ]
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
unless files . empty?
alert (
2010-06-04 21:25:51 +00:00
" Old ActionMailer class API " ,
2010-02-01 02:27:32 +00:00
" You're using the old API in a mailer class. " ,
" http://lindsaar.net/2010/1/26/new-actionmailer-api-in-rails-3 " ,
files
)
end
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Checks for old-style generators
def check_generators
generators = Dir . glob ( base_path + " vendor/plugins/**/generators/**/ " )
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
unless generators . empty?
2010-08-05 19:31:23 +00:00
files = generators . reject do | g |
grep_for ( " def manifest " , g ) . empty?
2010-02-01 02:27:32 +00:00
end . compact
2010-06-04 21:25:51 +00:00
2011-04-07 23:22:18 +00:00
unless files . empty?
2010-02-01 02:27:32 +00:00
alert (
2010-06-04 21:25:51 +00:00
" Old Rails generator API " ,
2010-02-01 02:27:32 +00:00
" A plugin in the app is using the old generator API (a new one may be available at http://github.com/trydionel/rails3-generators). " ,
" http://blog.plataformatec.com.br/2010/01/discovering-rails-3-generators/ " ,
files
)
end
end
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Checks a list of known broken plugins and gems
def check_plugins
# This list is off the wiki; will need to be updated often, esp. since RSpec is working on it
bad_plugins = [ " rspec " , " rspec-rails " , " hoptoad " , " authlogic " , " nifty-generators " ,
" restful_authentication " , " searchlogic " , " cucumber " , " cucumber-rails " , " devise " ,
" inherited_resources " ]
2010-06-04 21:25:51 +00:00
bad_plugins = bad_plugins . map do | p |
2010-02-01 02:27:32 +00:00
p if File . exist? ( " #{ base_path } vendor/plugins/ #{ p } " ) || ! Dir . glob ( " #{ base_path } vendor/gems/ #{ p } -* " ) . empty?
end . compact
unless bad_plugins . empty?
alert (
2010-06-04 21:25:51 +00:00
" Known broken plugins " ,
2010-02-01 02:27:32 +00:00
" At least one plugin in your app is broken (according to the wiki). Most of project maintainers are rapidly working towards compatability, but do be aware you may encounter issues. " ,
" http://wiki.rubyonrails.org/rails/version3/plugins_and_gems " ,
bad_plugins
)
end
end
2010-06-04 21:25:51 +00:00
2010-03-31 20:26:51 +00:00
# Checks for old-style ERb helpers
def check_old_helpers
2010-08-19 22:35:10 +00:00
lines = grep_for ( " <% .*content_tag.* do.*%> " , " app/views/**/* " )
lines += grep_for ( " <% .*javascript_tag.* do.*%> " , " app/views/**/* " )
lines += grep_for ( " <% .*form_for.* do.*%> " , " app/views/**/* " )
lines += grep_for ( " <% .*form_tag.* do.*%> " , " app/views/**/* " )
lines += grep_for ( " <% .*fields_for.* do.*%> " , " app/views/**/* " )
lines += grep_for ( " <% .*field_set_tag.* do.*%> " , " app/views/**/* " )
2010-03-31 20:26:51 +00:00
files = extract_filenames ( lines )
2010-06-04 21:25:51 +00:00
2011-04-07 23:22:18 +00:00
if ! files . blank?
2010-03-31 20:26:51 +00:00
alert (
2010-06-04 21:25:51 +00:00
" Deprecated ERb helper calls " ,
2010-04-01 04:06:44 +00:00
" Block helpers that use concat (e.g., form_for) should use <%= instead of <%. The current form will continue to work for now, but you will get deprecation warnings since this form will go away in the future. " ,
2010-03-31 20:26:51 +00:00
" http://weblog.rubyonrails.org/ " ,
files
)
end
end
2010-06-04 21:25:51 +00:00
2010-04-19 21:28:24 +00:00
# Checks for old-style AJAX helpers
def check_old_ajax_helpers
files = [ ]
[ 'link_to_remote' , 'form_remote_tag' , 'remote_form_for' ] . each do | type |
lines = grep_for ( type , " app/views/**/* " )
inner_files = extract_filenames ( lines )
files += inner_files unless inner_files . nil?
end
2010-06-04 21:25:51 +00:00
unless files . empty?
2010-04-19 21:28:24 +00:00
alert (
2010-06-04 21:25:51 +00:00
" Deprecated AJAX helper calls " ,
2010-04-19 21:28:24 +00:00
" AJAX javascript helpers have been switched to be unobtrusive and use :remote => true instead of having a seperate function to handle remote requests. " ,
" http://www.themodestrubyist.com/2010/02/24/rails-3-ujs-and-csrf-meta-tags/ " ,
files
)
end
end
2010-06-04 21:25:51 +00:00
2010-03-31 20:26:51 +00:00
# Checks for old cookie secret settings
2010-04-05 22:56:13 +00:00
def check_old_cookie_secret
lines = grep_for ( " ActionController::Base.cookie_verifier_secret = " , " config/**/* " )
2010-03-31 20:26:51 +00:00
files = extract_filenames ( lines )
2010-04-05 22:56:13 +00:00
2011-04-07 23:22:18 +00:00
unless files . empty?
2010-03-31 20:26:51 +00:00
alert (
2010-06-04 21:25:51 +00:00
" Deprecated cookie secret setting " ,
2010-04-05 22:56:13 +00:00
" Previously, cookie secret was set directly on ActionController::Base; it's now config.secret_token. " ,
2010-04-08 03:35:22 +00:00
" http://lindsaar.net/2010/4/7/rails_3_session_secret_and_session_store " ,
2010-04-05 22:56:13 +00:00
files
)
end
end
def check_old_session_secret
lines = grep_for ( " ActionController::Base.session = { " , " config/**/* " )
files = extract_filenames ( lines )
2011-04-07 23:22:18 +00:00
unless files . empty?
2010-04-05 22:56:13 +00:00
alert (
2010-06-04 21:25:51 +00:00
" Deprecated session secret setting " ,
2010-04-05 22:56:13 +00:00
" Previously, session secret was set directly on ActionController::Base; it's now config.secret_token. " ,
2010-04-08 03:35:22 +00:00
" http://lindsaar.net/2010/4/7/rails_3_session_secret_and_session_store " ,
2010-03-31 20:26:51 +00:00
files
)
end
end
2010-06-04 21:25:51 +00:00
2010-03-31 20:26:51 +00:00
# Checks for old session settings
def check_old_session_setting
lines = grep_for ( " ActionController::Base.session_store " , " config/**/* " )
files = extract_filenames ( lines )
2010-06-04 21:25:51 +00:00
2011-04-07 23:22:18 +00:00
unless files . empty?
2010-03-31 20:26:51 +00:00
alert (
2010-06-04 21:25:51 +00:00
" Old session store setting " ,
2010-04-05 22:56:13 +00:00
" Previously, session store was set directly on ActionController::Base; it's now config.session_store :whatever. " ,
2010-04-08 03:35:22 +00:00
" http://lindsaar.net/2010/4/7/rails_3_session_secret_and_session_store " ,
2010-03-31 20:26:51 +00:00
files
)
end
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
private
2010-06-04 21:50:16 +00:00
def grep_for_with_perl_regex ( text , where = " ./ " , double_quote = false )
grep_for ( text , where , double_quote , true )
end
2010-02-01 02:27:32 +00:00
# Find a string in a set of files; calls +find_with_grep+ and +find_with_rak+
# depending on platform.
#
# TODO: Figure out if this works on Windows.
2010-06-04 21:50:16 +00:00
def grep_for ( text , where = " ./ " , double_quote = false , perl_regex = false )
2010-02-01 02:27:32 +00:00
# If they're on Windows, they probably don't have grep.
@probably_has_grep || = ( Config :: CONFIG [ 'host_os' ] . downcase =~ / mswin|windows|mingw / ) . nil?
2010-08-05 19:31:23 +00:00
# protect against double root paths in Rails 3
where . gsub! ( Regexp . new ( base_path ) , '' )
2010-02-01 02:27:32 +00:00
2010-02-05 03:21:58 +00:00
lines = if @probably_has_grep
2010-06-04 21:50:16 +00:00
find_with_grep ( text , base_path + where , double_quote , perl_regex )
2010-02-01 02:27:32 +00:00
else
2010-02-03 16:58:52 +00:00
find_with_rak ( text , base_path + where , double_quote )
2010-02-01 02:27:32 +00:00
end
2010-06-04 21:25:51 +00:00
2010-02-05 03:21:58 +00:00
# ignore comments
2010-08-05 19:31:23 +00:00
lines . gsub / ^( \/ [^:]+:)? \ s* # .+$ /m , " "
2010-02-01 02:27:32 +00:00
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Sets a base path for finding files; mostly for testing
def base_path
Dir . pwd + " / "
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Use the grep utility to find a string in a set of files
2010-06-04 21:50:16 +00:00
def find_with_grep ( text , where , double_quote , perl_regex = false )
2010-02-01 02:27:32 +00:00
value = " "
2010-02-03 16:58:52 +00:00
# Specifically double quote for finding 'test_help'
command = if double_quote
2011-04-07 23:19:30 +00:00
" grep -rH #{ " -P " if perl_regex } \" #{ text } \" #{ where } | grep -v \ .svn "
2010-02-03 16:58:52 +00:00
else
2011-04-07 23:19:30 +00:00
" grep -rH #{ " -P " if perl_regex } ' #{ text } ' #{ where } | grep -v \ .svn "
2010-02-03 16:58:52 +00:00
end
2011-04-07 23:19:30 +00:00
2010-02-03 16:58:52 +00:00
Open3 . popen3 ( command ) do | stdin , stdout , stderr |
2010-02-01 02:27:32 +00:00
value = stdout . read
end
value
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Use the rak gem to grep the files (not yet implemented)
2010-02-03 16:58:52 +00:00
def find_with_rak ( text , where , double_quote )
2010-02-01 02:27:32 +00:00
value = " "
Open3 . popen3 ( " rak --nogroup -l ' #{ Regexp . escape ( text ) } ' #{ where } " ) do | stdin , stdout , stderr |
value = stdout . read
end
value
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Extract the filenames from the grep output
def extract_filenames ( output )
if @probably_has_grep
2011-04-07 23:22:18 +00:00
filenames = extract_filenames_from_grep ( output )
2010-02-01 02:27:32 +00:00
else
2011-04-07 23:22:18 +00:00
filenames = extract_filenames_from_rak ( output )
end
filenames . compact . map do | f |
f . gsub ( base_path , " " )
2010-02-01 02:27:32 +00:00
end
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
def extract_filenames_from_grep ( output )
2011-04-07 23:22:18 +00:00
return [ ] if output . empty?
2010-06-04 21:25:51 +00:00
2010-08-05 19:31:23 +00:00
output . split ( " \n " ) . map do | fn |
2010-02-02 21:10:53 +00:00
if m = fn . match ( / ^(.+?): / )
m [ 1 ]
end
2010-08-05 19:31:23 +00:00
end . compact . uniq
2010-02-01 02:27:32 +00:00
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
def extract_filenames_from_rak ( output )
2011-04-07 23:22:18 +00:00
return [ ] if output . empty?
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
output . split ( " \n " ) . uniq
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Terminal colors, borrowed from Thor
CLEAR = " \e [0m "
BOLD = " \e [1m "
RED = " \e [31m "
YELLOW = " \e [33m "
CYAN = " \e [36m "
WHITE = " \e [37m "
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Show an upgrade alert to the user
def alert ( title , text , more_info_url , culprits )
if Config :: CONFIG [ 'host_os' ] . downcase =~ / mswin|windows|mingw /
basic_alert ( title , text , more_info_url , culprits )
else
color_alert ( title , text , more_info_url , culprits )
end
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Show an upgrade alert to the user. If we're on Windows, we can't
# use terminal colors, hence this method.
def basic_alert ( title , text , more_info_url , culprits )
puts " ** " + title
puts text
puts " More information: #{ more_info_url } "
puts
puts " The culprits: "
2010-02-05 16:21:46 +00:00
Array ( culprits ) . each do | c |
2010-02-01 02:27:32 +00:00
puts " \t - #{ c } "
end
puts
end
2010-06-04 21:25:51 +00:00
2010-02-01 02:27:32 +00:00
# Show a colorful alert to the user
def color_alert ( title , text , more_info_url , culprits )
puts " #{ RED } #{ BOLD } #{ title } #{ CLEAR } "
puts " #{ WHITE } #{ text } "
puts " #{ BOLD } More information: #{ CLEAR } #{ CYAN } #{ more_info_url } "
puts
puts " #{ WHITE } The culprits: "
2010-02-05 16:21:46 +00:00
Array ( culprits ) . each do | c |
2010-02-01 02:27:32 +00:00
puts " #{ YELLOW } \t - #{ c } "
end
ensure
puts " #{ CLEAR } "
end
end
end
2010-02-03 01:38:35 +00:00
end