NAnt でアセンブリのバージョンアップデート

via CodeZine:NAntでアセンブリのバージョンアップデートを自動化する


複数アセンブリのバージョン番号管理を自動化する、いい方法はないかと考えている時に上記の記事を見つけた。
アイデア自体はいいんだけど、ビルド番号を決定するスクリプトがどうも気持ち悪い。


なんとかしようとタスクリファレンスを眺めていたら、アセンブリからバージョン番号を取得する関数があるじゃないですか。
現在のバージョン番号はアセンブリに埋め込まれているわけだから、そこから次のバージョン番号を決定すればいいのでは?と考えてやってみたらうまくいったのでメモしておく。


ついでにサンプル一式

想定するフォルダ構成

作業フォルダ以下にビルドスクリプト、アセンブリ出力先、ソースフォルダを格納する。

ビルドスクリプトを実行すると、アセンブリが bin フォルダに出力される。
ちなみに以下は2回目の実行で出力されたアセンブリのプロパティ。

ビルドスクリプト

ビルドスクリプトがやっているのはこんな感じ。

  1. CountUp タスク → バージョン番号のインクリメント。(既存のアセンブリがなければ 1.0.0.0)
  2. GenerateAsmInfo タスク → バージョン番号を埋め込んだ AssemblyInfo.cs を生成
  3. Build タスク → 出力先を指定して、プロジェクトをビルド

対象は .NET 1.1 だけど、solution タスクのところを MSBuild の呼び出しに変更すれば .NET 2.0 でもいけるはず。

<?xml version="1.0" encoding="utf-8" ?>
<project name="BuildAssembly" default="Build" basedir="." xmlns="http://nant.sf.net/release/0.85-rc4/nant.xsd">
  <property name="SolutionName" value="Solution"/>
  <property name="AssemblyName" value="ClassLibrary1"/>
  <property name="base.dir" value="${project::get-base-directory()}"/>
  <property name="source.dir" value="${base.dir}/source"/>
  <property name="output.dir" value="${base.dir}/bin"/>
  <property name="output.file" value="${output.dir}/${AssemblyName}.dll"/>
  <property name="info.file" value="${source.dir}/${SolutionName}/${AssemblyName}/AssemblyInfo.cs"/>
  <property name="proj.file" value="${source.dir}/${SolutionName}/${AssemblyName}/${AssemblyName}.csproj"/>

  <target name="CountUp" description="バージョン番号をカウントアップ">
    <!-- アセンブリがなければ 1.0.0.0 からスタート -->
    <if test="${not file::exists(output.file)}">
      <property name="version" value="1.0.0.0"/>
    </if>
    <!-- アセンブリがあればアセンブリバージョンを読み取って、ビルド番号をカウントアップ -->
    <if test="${file::exists(output.file)}">
      <property name="version" value="${assemblyname::get-version(assemblyname::get-assembly-name(output.file))}"/>
      <property name="major" value="${version::get-major(version::parse(version))}"/>
      <property name="minor" value="${version::get-minor(version::parse(version))}"/>
      <property name="build" value="${version::get-build(version::parse(version))}"/>
      <property name="revision" value="${version::get-revision(version::parse(version))}"/>
      <property name="build" value="${int::parse(build) + 1}"/>
      <property name="version" value="${major}.${minor}.${build}.${revision}"/>
    </if>
  </target>

  <target name="GenerateAsmInfo" depends="CountUp" description="AssemblyInfoを作成">
    <!-- 既存の AssemblyInfo.cs を削除 -->
    <delete file="${info.file}"/>
    <!-- AssemblyInfo.cs を生成 -->
    <attrib file="${info.file}" normal="true" />
    <asminfo output="${info.file}" language="CSharp">
      <imports>
        <import namespace="System.Reflection" />
        <import namespace="System.Runtime.InteropServices" />
        <import namespace="System.Runtime.CompilerServices" />
      </imports>
      <attributes>
        <attribute type="AssemblyTitleAttribute" value="${AssemblyName} for .NET 1.1" />
        <attribute type="AssemblyDescriptionAttribute" value="" />
        <attribute type="AssemblyConfigurationAttribute" value="" />
        <attribute type="AssemblyCompanyAttribute" value="Company" />
        <attribute type="AssemblyProductAttribute" value="${AssemblyName}" />
        <attribute type="AssemblyCopyrightAttribute" value="Copyright (C) 2006, HOGE CORP." />
        <attribute type="AssemblyTrademarkAttribute" value="${AssemblyName}" />
        <attribute type="AssemblyCultureAttribute" value="" />
        <attribute type="ComVisibleAttribute" value="false" />
        <attribute type="AssemblyVersionAttribute" value="${version}" />
      </attributes>
    </asminfo>
  </target>

  <target name="Build" depends="GenerateAsmInfo" description="ビルド">
    <solution configuration="release" outputdir="${output.dir}">
      <projects>
        <include name="${proj.file}"/>
      </projects>
    </solution>
  </target>
</project>