require 'rake/clean' require 'rexml/document' require 'net/smtp' require 'net/http' require 'uri' require 'find' #Project general settings PROJECT_NAME = "Aardvark" VERSION_MAJOR_MINOR_BUILD = "0.1.0" COPYRIGHT = "Copyright 2009 1minus1 Ltd. All rights reserved." #Project technical settings SVN_URL = "http://aardvark-cms.googlecode.com/svn/trunk/" COVERAGE_ASSEMBLIES = "OneMinusOne.Aardvark.Web;OneMinusOne.Aardvark.Framework;OneMinusOne.Aardvark.Entities;OneMinusOne.Aardvark.Core" DEPLOYMENT_PATH = "D:\\Websites\\DevSite\\Aardvark" DEPLOYMENT_URL = "http://aardvark.1minus1testing.com" DEPLOYMENT_CONNECTION_STRING = "server=SERVER40118\\SQL1MINUS102;database=Aardvark;uid=aardvark_dbo;pwd=we-are-cool-265;" INSTALL_URL = "#{DEPLOYMENT_URL}/Install" SMTP_SERVER = "localhost" NOTIFY_TO_EMAIL = "andy@1minus1.com" NOTIFY_FROM_EMAIL = "noreply@1minus1.com" NOTIFY_FROM_NAME = "Aardvark CMS Build Server" WEB_PROJECT_PATH = "../src/OneMinusOne.Aardvark.Web" #Common settings DOT_NET_PATH = "#{ENV["SystemRoot"]}\\Microsoft.NET\\Framework\\v3.5" TEAMCITY_NUNIT_RUNNER = ENV["teamcity.dotnet.nunitlauncher"] NUNIT_EXE = "../tools/NUnit/nunit-console.exe" NCOVER_EXE = "../tools/NCover/NCover.Console.exe" NCOVER_EXPLORER_EXE = "../tools/NCoverExplorer/NCoverExplorer.Console.exe" ZIP_EXE = "../tools/7Zip/7za.exe" SOURCE_PATH = "../src" OUTPUT_PATH = "output" ARTIFACTS_PATH = "#{OUTPUT_PATH}/artifacts" SVN_LOG_PATH = "#{OUTPUT_PATH}/svn_log.xml" CONFIG = "Release" #Cleanup the output folder CLEAN.include(OUTPUT_PATH) task :default => ["clean", "build:all"] task :local => ["clean", "build:local"] namespace :build do task :all => [:init, :writeAssemblyInfo, :compile, :test, :coverage, :artifacts, :configure, :package, :deploy, :install, :notify] task :local => [:init, :writeAssemblyInfo, :compile, :test, :coverage, :artifacts, :configure, :package] desc "Perform the required initial tasks." task :init do puts "Performing Initialization..." puts "Creating folders..." Dir.mkdir(OUTPUT_PATH) Dir.mkdir(ARTIFACTS_PATH) puts "Deleting any existing bin folders..." FileUtils.rm_r FileList["#{SOURCE_PATH}/**/bin"], :force => true puts "Getting SVN revision number and saving to #{SVN_LOG_PATH}..." sh "svn log --xml --revision HEAD #{SVN_URL} > \"#{SVN_LOG_PATH}\"" svnLogFile = File.new(SVN_LOG_PATH) log = REXML::Document.new svnLogFile logEntry = log.root.elements["logentry"] $svn_revision = logEntry.attributes["revision"] $svn_message = logEntry.elements["msg"].text VERSION = "#{VERSION_MAJOR_MINOR_BUILD}.#{$svn_revision}" svnLogFile.close puts "Revision #{$svn_revision} found with message: #{$svn_message}" end desc "Write AssemblyInfo.cs with current svn revision." task :writeAssemblyInfo => [:init] do puts "Writing AssemblyInfo Files..." assemblyInfoFiles = FileList["#{SOURCE_PATH}/**/AssemblyInfo.cs"] assemblyInfoFiles.each do |filePath| puts "AssemblyInfo file found at: #{filePath}" file = File.new(filePath, "w") file.puts "//This file was generated by the rakefile.rb build script" file.puts "using System.Reflection;" file.puts "using System.Runtime.InteropServices;\r\n" file.puts "[assembly: AssemblyTitle(\"#{PROJECT_NAME} for .NET 3.5\")]" file.puts "[assembly: AssemblyDescription(\"\")]" file.puts "[assembly: AssemblyConfiguration(\"\")]" file.puts "[assembly: AssemblyCompany(\"\")]" file.puts "[assembly: AssemblyProduct(\"#{PROJECT_NAME}\")]" file.puts "[assembly: AssemblyCopyright(\"#{COPYRIGHT}\")]" file.puts "[assembly: AssemblyTrademark(\"\")]" file.puts "[assembly: AssemblyCulture(\"\")]" file.puts "[assembly: ComVisible(false)]" file.puts "[assembly: AssemblyVersion(\"#{VERSION}\")]" file.puts "[assembly: AssemblyFileVersion(\"#{VERSION}\")]" file.close end end desc "Build solution using MSBuild." task :compile => [:writeAssemblyInfo] do puts "Compiling Solution..." solutions = FileList["#{SOURCE_PATH}/**/*.sln"] solutions.each do |solution| sh "#{DOT_NET_PATH}/msbuild.exe /p:Configuration=#{CONFIG} #{solution} /t:Rebuild" end end desc "Runs tests with NUnit only (without coverage)." task :test => [:compile] do puts "Running Tests..." tests = FileList["#{SOURCE_PATH}/**/#{CONFIG}/*.Tests.dll"].exclude(/obj\//) #Select the correct test runner if(TEAMCITY_NUNIT_RUNNER == nil) sh "#{NUNIT_EXE} #{tests} /nologo /exclude:Acceptance /xml=#{OUTPUT_PATH}/TestResults.xml" else sh "#{TEAMCITY_NUNIT_RUNNER} v2.0 x86 NUnit-2.4.6 /category-exclude:Acceptance #{tests}" end end desc "Run tests with NUnit and NCover for coverage. NCoverExplorer is used to format the coverage results into html." task :coverage => [:compile] do puts "Running Tests with Coverage..." tests = FileList["#{SOURCE_PATH}/**/#{CONFIG}/*.Tests.dll"].exclude(/obj\//) sh "#{NCOVER_EXE} #{NUNIT_EXE} #{tests} /nologo /exclude:Acceptance /xml=#{OUTPUT_PATH}/TestResults.xml //reg //x #{OUTPUT_PATH}/Coverage.xml //l #{OUTPUT_PATH}/Coverage.log //ea System.CodeDom.Compiler.GeneratedCodeAttribute //a #{COVERAGE_ASSEMBLIES}" sh "#{NCOVER_EXPLORER_EXE} #{OUTPUT_PATH}/Coverage.xml /r:ModuleClassFunctionSummary /p:#{PROJECT_NAME} /q /h /so:2 /m:80 /h:#{OUTPUT_PATH}/CoverageReport.html" end desc "Arrange the required artifacts." task :artifacts => [:compile] do puts "Gathering artifacts files..." Dir.mkdir "#{ARTIFACTS_PATH}/bin" FileUtils.cp_r FileList["#{WEB_PROJECT_PATH}/bin/*.dll"], "#{ARTIFACTS_PATH}/bin" FileUtils.cp_r "#{WEB_PROJECT_PATH}/Content", "#{ARTIFACTS_PATH}" FileUtils.cp_r "#{WEB_PROJECT_PATH}/Views", "#{ARTIFACTS_PATH}" FileUtils.cp_r FileList["#{WEB_PROJECT_PATH}/*.aspx"], "#{ARTIFACTS_PATH}" FileUtils.cp_r FileList["#{WEB_PROJECT_PATH}/*.asax"], "#{ARTIFACTS_PATH}" FileUtils.cp_r FileList["#{WEB_PROJECT_PATH}/*.config"], "#{ARTIFACTS_PATH}" delete_svn_folders(ARTIFACTS_PATH) end desc "Update the artifact config files ready for deployment." task :configure => [:artifacts] do puts "Configuring ActiveRecord..." #Update the ActiveRecord.config before deploying arConfigFilePath = "#{ARTIFACTS_PATH}/ActiveRecord.config" arConfigFile = File.new(arConfigFilePath) arConfig = REXML::Document.new arConfigFile connectionString = arConfig.root.elements["facilities/facility[@id='arfacility']/config/add[@key='connection.connection_string']"] connectionString.attributes["value"] = DEPLOYMENT_CONNECTION_STRING arConfigFile.close #Save the updated ActiveRecord.config file arConfigFile = File.open(arConfigFilePath, "w") formatter = REXML::Formatters::Default.new(5) formatter.write(arConfig, arConfigFile) arConfigFile.close end desc "Package the required artifacts." task :package => [:configure] do puts "Creating zip package" zipFolder(ARTIFACTS_PATH, "#{OUTPUT_PATH}/#{PROJECT_NAME}-v#{VERSION}.zip"); end desc "Copy artifacts to the specified deployment location" task :deploy => [:package] do puts "Deploying..." #Copy files to the deployment folder FileUtils.mkdir DEPLOYMENT_PATH, :noop => true FileUtils.cp_r "#{ARTIFACTS_PATH}/.", DEPLOYMENT_PATH end desc "Install database and other requirements" task :install => [:compile] do puts "Installing..." httpGet(INSTALL_URL) end desc "Run acceptance tests that were ignored by normal test runner" task :acceptance => [:install] do puts "Running Acceptance Tests..." #TODO: Only select Web.Tests assembly #TODO: Update the app.config with correct settings (url etc) #TODO: Add this target to build:all and test on teamcity tests = FileList["#{SOURCE_PATH}/**/#{CONFIG}/*.Tests.dll"].exclude(/obj\//) #Select the correct test runner if(TEAMCITY_NUNIT_RUNNER == nil) sh "#{NUNIT_EXE} #{tests} /nologo /include:Acceptance /xml=#{OUTPUT_PATH}/AcceptanceTestResults.xml" else sh "#{TEAMCITY_NUNIT_RUNNER} v2.0 x86 NUnit-2.4.6 /category-include:Acceptance #{tests}" end end desc "Email the selected addresses that a new build is complete" task :notify do puts "Sending email notifications..." send_email NOTIFY_FROM_EMAIL , NOTIFY_FROM_NAME, NOTIFY_TO_EMAIL, "A new version of #{PROJECT_NAME} is available: #{VERSION}", "Version #{VERSION} of #{PROJECT_NAME} includes the following changes:\r\n\r\n#{$svn_message}" end def zipFolder(folderPath, zipPath) sh "#{ZIP_EXE} a #{zipPath} .\\#{folderPath}\\*" end def send_email(from, from_alias, to, subject, message) msg = < To: #{to} Subject: #{subject} #{message} You can see this version of #{PROJECT_NAME} running here: #{DEPLOYMENT_URL} ========================================================================= This is an automated email sent by the #{PROJECT_NAME} build server END_OF_MESSAGE #http://www.ruby-doc.org/stdlib/libdoc/net/smtp/rdoc/classes/Net/SMTP.html Net::SMTP.start(SMTP_SERVER) do |smtp| smtp.send_message msg, from, to end end def httpGet(url) #http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/classes/Net/HTTP.html Net::HTTP.get_print URI.parse(url) end def delete_svn_folders(folder) Find.find(folder) do |path| if(path =~ /\.svn$/ || path =~ /\_svn$/) puts "Deleting: #{path}" FileUtils.rm_r path, :force => true end end end end