Newer
Older
require 'rake/clean'
require 'tempfile'
require 'net/http'
require 'launchy'
require 'colorize'
# Build Constants
REPO_ROOT = File.dirname(__FILE__)
BUILD_DIR = File.join(REPO_ROOT, "build")
REPORT_DIR = File.join(REPO_ROOT, "reports")
LMS_REPORT_DIR = File.join(REPORT_DIR, "lms")
# Packaging constants
DEPLOY_DIR = "/opt/wwc"
PACKAGE_NAME = "mitx"
Calen Pennington
committed
COMMIT = (ENV["GIT_COMMIT"] || `git rev-parse HEAD`).chomp()[0, 10]
BRANCH = (ENV["GIT_BRANCH"] || `git symbolic-ref -q HEAD`).chomp().gsub('refs/heads/', '').gsub('origin/', '')
BUILD_NUMBER = (ENV["BUILD_NUMBER"] || "dev").chomp()
if BRANCH == "master"
DEPLOY_NAME = "#{PACKAGE_NAME}-#{BUILD_NUMBER}-#{COMMIT}"
DEPLOY_NAME = "#{PACKAGE_NAME}-#{BRANCH}-#{BUILD_NUMBER}-#{COMMIT}"
end
PACKAGE_REPO = "packages@gp.mitx.mit.edu:/opt/pkgrepo.incoming"
NORMALIZED_DEPLOY_NAME = DEPLOY_NAME.downcase().gsub(/[_\/]/, '-')
INSTALL_DIR_PATH = File.join(DEPLOY_DIR, NORMALIZED_DEPLOY_NAME)
# Set up the clean and clobber tasks
Calen Pennington
committed
CLOBBER.include(BUILD_DIR, REPORT_DIR, 'cover*', '.coverage', 'test_root/*_repo', 'test_root/staticfiles')
CLEAN.include("#{BUILD_DIR}/*.deb", "#{BUILD_DIR}/util")
Calen Pennington
committed
def select_executable(*cmds)
cmds.find_all{ |cmd| system("which #{cmd} > /dev/null 2>&1") }[0] || fail("No executables found from #{cmds.join(', ')}")
end
Calen Pennington
committed
def django_admin(system, env, command, *args)
django_admin = ENV['DJANGO_ADMIN_PATH'] || select_executable('django-admin.py', 'django-admin')
return "#{django_admin} #{command} --settings=#{system}.envs.#{env} --pythonpath=. #{args.join(' ')}"
end
Calen Pennington
committed
def django_for_jasmine(system)
django_pid = fork do
exec(*django_admin(system, 'jasmine', 'runserver', '12345').split(' '))
end
puts django_pid
jasmine_url = 'http://localhost:12345/_jasmine/'
up = false
Calen Pennington
committed
start_time = Time.now
until up do
Calen Pennington
committed
if Time.now - start_time > 30
abort "Timed out waiting for server to start to run jasmine tests"
end
begin
response = Net::HTTP.get_response(URI(jasmine_url))
puts response.code
up = response.code == '200'
rescue => e
puts e.message
ensure
puts('Waiting server to start')
sleep(0.5)
end
end
begin
yield jasmine_url
ensure
Process.kill(:SIGKILL, -Process.getpgid(django_pid))
Process.wait(django_pid)
end
end
Calen Pennington
committed
task :default => [:test, :pep8, :pylint]
default_options = {
:lms => '8000',
:cms => '8001',
}
task :predjango do
sh("find . -type f -name *.pyc -delete")
sh('pip install -e common/lib/xmodule -e common/lib/capa')
Calen Pennington
committed
task :clean_test_files do
sh("git clean -fdx test_root")
end
[:lms, :cms, :common].each do |system|
report_dir = File.join(REPORT_DIR, system.to_s)
directory report_dir
desc "Run pep8 on all #{system} code"
task "pep8_#{system}" => report_dir do
sh("pep8 --ignore=E501 #{system}/djangoapps #{system}/lib | tee #{report_dir}/pep8.report")
end
task :pep8 => "pep8_#{system}"
desc "Run pylint on all #{system} code"
task "pylint_#{system}" => report_dir do
Dir["#{system}/djangoapps/*", "#{system}/lib/*"].each do |app|
if File.exists? "#{app}/setup.py"
pythonpath_prefix = "PYTHONPATH=#{app}"
else
pythonpath_prefix = "PYTHONPATH=#{File.dirname(app)}"
end
sh("#{pythonpath_prefix} pylint --rcfile=.pylintrc -f parseable #{app} | tee #{report_dir}/#{app}.pylint.report")
end
end
task :pylint => "pylint_#{system}"
desc "Open jasmine tests in your default browser"
task "browse_jasmine_#{system}" do
django_for_jasmine(system) do |jasmine_url|
Launchy.open(jasmine_url)
puts "Press ENTER to terminate".red
$stdin.gets
end
end
desc "Use phantomjs to run jasmine tests from the console"
task "phantomjs_jasmine_#{system}" do
phantomjs = ENV['PHANTOMJS_PATH'] || 'phantomjs'
django_for_jasmine(system) do |jasmine_url|
sh("#{phantomjs} common/test/phantom-jasmine/lib/run_jasmine_test.coffee #{jasmine_url}")
end
end
$failed_tests = 0
def run_tests(system, report_dir, stop_on_failure=true)
ENV['NOSE_XUNIT_FILE'] = File.join(report_dir, "nosetests.xml")
ENV['NOSE_COVER_HTML_DIR'] = File.join(report_dir, "cover")
dirs = Dir["common/djangoapps/*"] + Dir["#{system}/djangoapps/*"]
sh(django_admin(system, :test, 'test', *dirs.each)) do |ok, res|
if !ok and stop_on_failure
abort "Test failed!"
end
$failed_tests += 1 unless ok
end
TEST_TASKS = []
[:lms, :cms].each do |system|
report_dir = File.join(REPORT_DIR, system.to_s)
Calen Pennington
committed
directory report_dir
Calen Pennington
committed
desc "Run all django tests on our djangoapps for the #{system}"
task "test_#{system}", [:stop_on_failure] => ["clean_test_files", "#{system}:collectstatic:test", "fasttest_#{system}"]
# Have a way to run the tests without running collectstatic -- useful when debugging without
# messing with static files.
task "fasttest_#{system}", [:stop_on_failure] => [report_dir, :predjango] do |t, args|
args.with_defaults(:stop_on_failure => 'true')
run_tests(system, report_dir, args.stop_on_failure)
Calen Pennington
committed
end
TEST_TASKS << "test_#{system}"
desc <<-desc
Start the #{system} locally with the specified environment (defaults to dev).
Other useful environments are devplus (for dev testing with a real local database)
desc
task system, [:env, :options] => [:predjango] do |t, args|
args.with_defaults(:env => 'dev', :options => default_options[system])
sh(django_admin(system, args.env, 'runserver', args.options))
end
Calen Pennington
committed
Dir["#{system}/envs/**/*.py"].each do |env_file|
env = env_file.gsub("#{system}/envs/", '').gsub(/\.py/, '').gsub('/', '.')
desc "Attempt to import the settings file #{system}.envs.#{env} and report any errors"
task "#{system}:check_settings:#{env}" => :predjango do
sh("echo 'import #{system}.envs.#{env}' | #{django_admin(system, env, 'shell')}")
end
desc "Run collectstatic in the specified environment"
task "#{system}:collectstatic:#{env}" => :predjango do
sh("#{django_admin(system, env, 'collectstatic', '--noinput')}")
Calen Pennington
committed
end
Dir["common/lib/*"].each do |lib|
task_name = "test_#{lib}"
report_dir = File.join(REPORT_DIR, task_name.gsub('/', '_'))
Calen Pennington
committed
directory report_dir
desc "Run tests for common lib #{lib}"
Calen Pennington
committed
ENV['NOSE_XUNIT_FILE'] = File.join(report_dir, "nosetests.xml")
sh("nosetests #{lib} --cover-erase --with-xunit --with-xcoverage --cover-html --cover-inclusive --cover-package #{File.basename(lib)} --cover-html-dir #{File.join(report_dir, "cover")}")
Calen Pennington
committed
end
TEST_TASKS << task_name
desc "Run tests for common lib #{lib} (without coverage)"
task "fasttest_#{lib}" do
sh("nosetests #{lib}")
end
end
task :test do
TEST_TASKS.each do |task|
Rake::Task[task].invoke(false)
end
if $failed_tests > 0
abort "Tests failed!"
end
Calen Pennington
committed
desc "Run django-admin <action> against the specified system and environment"
Calen Pennington
committed
task "django-admin", [:action, :system, :env, :options] => [:predjango] do |t, args|
Calen Pennington
committed
args.with_defaults(:env => 'dev', :system => 'lms', :options => '')
sh(django_admin(args.system, args.env, args.action, args.options))
end
desc "Set the staff bit for a user"
task :set_staff, [:user, :system, :env] do |t, args|
args.with_defaults(:env => 'dev', :system => 'lms', :options => '')
sh(django_admin(args.system, args.env, 'set_staff', args.user))
end
afterremove = Tempfile.new('afterremove')
afterremove.write <<-AFTERREMOVE.gsub(/^\s*/, '')
# to be a little safer this rm is executed
sudo rm -rf "#{INSTALL_DIR_PATH}"
fi
AFTERREMOVE
afterremove.close()
FileUtils.chmod(0755, afterremove.path)
args = ["fakeroot", "fpm", "-s", "dir", "-t", "deb",
"--after-remove=#{afterremove.path}",
"--prefix=#{INSTALL_DIR_PATH}",
Calen Pennington
committed
"--exclude=**/build/**",
"--exclude=**/rakefile",
"--exclude=**/.git/**",
Calen Pennington
committed
"--exclude=**/reports/**",
"--exclude=**/test_root/**",
"--exclude=**/.coverage/**",
"-C", "#{REPO_ROOT}",
Calen Pennington
committed
"--provides=#{PACKAGE_NAME}",
"--name=#{NORMALIZED_DEPLOY_NAME}",
"--version=#{PKG_VERSION}",
system(*args) || raise("fpm failed to build the .deb")
end
end
task :publish => :package do
sh("scp #{BUILD_DIR}/#{NORMALIZED_DEPLOY_NAME}_#{PKG_VERSION}*.deb #{PACKAGE_REPO}")
namespace :cms do
desc "Import course data within the given DATA_DIR variable"
task :import do
if ENV['DATA_DIR']
sh(django_admin(:cms, :dev, :import, ENV['DATA_DIR']))
else
raise "Please specify a DATA_DIR variable that point to your data directory.\n" +
"Example: \`rake cms:import DATA_DIR=../data\`"
end
end
end
desc "Build a properties file used to trigger autodeploy builds"
task :autodeploy_properties do
File.open("autodeploy.properties", "w") do |file|
file.puts("UPSTREAM_NOOP=false")
file.puts("UPSTREAM_BRANCH=#{BRANCH}")
file.puts("UPSTREAM_JOB=#{PACKAGE_NAME}")
file.puts("UPSTREAM_REVISION=#{COMMIT}")
end
end