.NET プロジェクトのリリース作業を Rake で自動化

.NET で開発しているプロジェクトのソースコードをチェックアウトして、ビルドして、出来あがったアセンブリを公開用リポジトリにコミット、という作業を MSBuild で自動化してました。

でもいい加減、条件分岐とかループとか MSBuild でやるの面倒になったので、ビルドスクリプトを Ruby + Rake で書き変えることにしました。やっぱ Rake いいわぁ。言語内 DSL 最高。

作成した Rakefile をメモしておきます。

# coding: utf-8
require "yaml"

SVN = 'svn'
MSBUILD = 'C:/windows/Microsoft.NET/Framework/v4.0.30319/MSBuild.exe'

File.open("./projects.yml") do |io|
  YAML.load_documents(io) do |obj|
    obj.keys.each do |key|
      namespace key do

# YAML からビルドに必要な情報を取得
src_repo_url = obj[key]["src_repo"]
bin_repo_url = obj[key]["bin_repo"]
src_work_dir = obj[key]["src_work"]
bin_work_dir = obj[key]["bin_work"]
sln_path = obj[key]["sln_path"]

# クリーンアップ
# CLOBBER を使うと動的に生成した他のタスクの成果物まで削除してしまうので
# クリーンアップ用タスクを用意
desc "Cleanup"
task :cleanup do
  FileUtils.rm_rf(bin_work_dir)
  FileUtils.rm_rf(src_work_dir)
end

# ソースコードをチェックアウト
desc "Checkout source code files from subversion repository."
task :checkout_src do
  sh "#{SVN} checkout #{src_repo_url} #{src_work_dir}"
end

# アセンブリをチェックアウト
desc "Checkout binary files from subversion repository."
task :checkout_bin do
  sh "#{SVN} checkout #{bin_repo_url} #{bin_work_dir}"
end

# 古いアセンブリを削除
desc "Delete all old binary files."
task :delete_old_bin do
  Dir.glob("#{bin_work_dir}/**/*").each do |path|
    if File.file?(path)
      puts "Delete #{path}"
      File.delete(path)
    end
  end
end

# ソリューションをビルド
desc "Build Visual Studio solution."
task :build do
  sh "#{MSBUILD} #{sln_path} /p:Configuration=Release /p:Platform=\"Any CPU\" /t:Rebuild"
end

# 空のディレクトリをリポジトリから削除
desc "Delete all empty directories."
task :delete_empty_dirs do
  Dir.glob("#{bin_work_dir}/**/*").each do |path|
    if File.directory?(path) and Dir.glob("#{path}/*").count == 0
      sh "#{SVN} delete #{path}"
    end
  end
end

# 新しいアセンブリをリポジトリに追加
desc "Regist new files to subversion repository."
task :add_new_files do
  pattern = File.join(bin_work_dir, "*")
  sh "#{SVN} add #{pattern}"
end

# アセンブリのリポジトリをコミット
desc "Commit binary repository."
task :commit_bin do
  message = '"update binary files"'
  sh "#{SVN} commit #{bin_work_dir} -m #{message} --username foo --password bar"
end

# すべてのタスクを実行
desc "Execute all build task."
task :all => [:cleanup,
              :checkout_src,
              :checkout_bin,
              :delete_old_bin,
              :build,
              :delete_empty_dirs,
              :add_new_files,
              :commit_bin]

      end
    end
  end
end

あとは、Rakefile と同じディレクトリに projects.yml ファイルを作成して、次のような設定を記述。

foo_main:
    src_repo: "http://reposerver/svn/Foo/trunk"
    bin_repo: "http://reposerver/svn/FooBin/trunk"
    src_work: "C:/Work/Foo"
    bin_work: "C:/Work/Foo/BIN"
    sln_path: "C:/Work/Foo/Foo.sln"

foo_ver1:
    src_repo: "http://reposerver/svn/Foo/branches/1.0"
    bin_repo: "http://reposerver/svn/FooBin/branches/1.0"
    src_work: "C:/Work/Foo1.0"
    bin_work: "C:/Work/Foo1.0/BIN"
    sln_path: "C:/Work/Foo1.0/Foo.sln"

これで rake を実行すれば、YAML ファイルから設定を読み込んで、動的にタスクを生成できます。ビルドするプロジェクトが増えたら、そのプロジェクトのリポジトリや作業ディレクトリを YAML に追加するだけ。