ゴマちゃんフロンティア

アザラシが大好きなエンジニアの開発日記です

【Unity】ビルド時にGitコミットハッシュをバージョン情報に含めた件

time 2018/08/05

というわけで、今回はタイトル通り「バージョン情報にGitのコミットハッシュを入れたい」というお話です。
SVNのリビジョン番号を入れるケースはよくヒットしますが、Gitについてはなかなか見つからず、ましてはUnityのプロジェクトでやっている例はなかったので考えてみました。

先に結論を言うと、
・ファイルバージョンには設定可能(警告あり)
・アセンブリバージョンは文字列が許可されないので、リポジトリ内のコミット回数を設定
という形で落ち着きました。

AssemblyInfoの準備

そもそも私のプロジェクトにAssemblyInfo.csがなかったので、まずはアセンブリ情報ファイルを追加しました。というかUnityから作成したプロジェクトでは大抵ないと思うので、明示的に追加する必要があります。
VisualStudioであれば「プロジェクトを右クリック→追加→新しい項目」から「アセンブリ情報ファイル」を選択するとテンプレで作成できます。

できたてだと以下のような感じです。

using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。
// アセンブリに関連付けられている情報を変更するには、
// これらの属性値を変更してください。
[assembly: AssemblyTitle("")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Copyright ©  2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// ComVisible を false に設定すると、その型はこのアセンブリ内で COM コンポーネントから
// 参照不可能になります。COM からこのアセンブリ内の型にアクセスする場合は、
// その型の ComVisible 属性を true に設定してください。
[assembly: ComVisible(false)]

// このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります
[assembly: Guid("5f5ca30f-c760-4ad5-8e4d-1deda811ed46")]

// アセンブリのバージョン情報は次の 4 つの値で構成されています:
//
//      メジャー バージョン
//      マイナー バージョン
//      ビルド番号
//      Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

内容は後述する置換処理で書き換えられるため、デフォルトのままで問題ありません。

AssemblyInfo書き換え用テンプレートの用意

AssemblyInfoを書き換えるベースとしてAssemblyInfoTemplate.txtを用意します。内容はAssemblyInfoをそのままコピペし、バージョン情報の部分のみ置換できるように細工しておきます。
以下はバージョン部分のサンプルです。

[assembly: AssemblyVersion("1.0.2.%rev%")]
[assembly: AssemblyFileVersion("1.0.2.%hash%")]

ビルド前に実行される関数の作成

VisualStudioのプロジェクト設定でビルド前イベントを設定することができますが、.csprojファイルがUnityから書き換えられる可能性があるため得策とは言えません。
エディタ拡張でビルド前に実行する関数を定義できるようなので、そちらを使います。以下のスクリプトを任意のEditorフォルダ内に作成します。

using System.Diagnostics;
using System.IO;
using System.Linq;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;

public class InsertGitVersionEvent : IPreprocessBuildWithReport
{
    public int callbackOrder
    {
        get {
            return 0;
        }
    }

    private string AssemblyInfoPath = "./Assets/AssemblyInfo.cs";
    private string AssemblyInfoTemplatePath = "./Assets/AssemblyInfoTemplate.txt";

    private string git_bin_path = @"C:\Program Files\Git\bin\";

    public void OnPreprocessBuild(BuildReport report)
    {
        string hash = GetCurrentCommitHash();
        int rev = GetTotalCommitCount();

        string assembly_text = File.ReadAllText(AssemblyInfoTemplatePath);
        assembly_text = assembly_text.Replace("%rev%", rev.ToString());
        assembly_text = assembly_text.Replace("%hash%", hash);

        File.WriteAllText(AssemblyInfoPath, assembly_text);
    }

    private string GetCurrentCommitHash()
    {
        Process process = CreateGitProcess();
        process.StartInfo.Arguments = @"rev-parse --short HEAD";

        process.Start();
        string result = process.StandardOutput.ReadLine();
        process.WaitForExit();
        process.Close();

        return result;
    }

    private int GetTotalCommitCount()
    {
        Process process = CreateGitProcess();
        process.StartInfo.Arguments = "log --oneline";

        process.Start();
        string commits = process.StandardOutput.ReadToEnd();
        int count = commits.Split('\n').Count() - 1;
        process.WaitForExit();
        process.Close();

        return count;
    }

    private Process CreateGitProcess()
    {
        Process process = new Process();
        process.StartInfo.FileName = git_bin_path + "git.exe";
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.RedirectStandardInput = false;
        process.StartInfo.RedirectStandardError = true;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.WorkingDirectory = @"C:\develop\Project\DefenceOfGoma";

        return process;
    }
}

一部サイトではIPreprocessBuildが紹介されていますが、現行のUnityでは既に廃止されているので使えません。今から実装する場合はIPreprocessBuildWithReportを使うようにしましょう。
Processクラスを使用しgitコマンドの実行結果を取得します。process.StartInfo.WorkingDirectoryでカレントディレクトリをプロジェクトフォルダ直下に指定するのがポイントです。
当然ですが各種パスは実行環境に合わせて書き換えましょう。

「AssemblyInfoの中身取得→バージョン情報を置換→AssemblyInfoに上書き」という流れでAssemblyInfo.csを書き換えます。
ファイルバージョンの方はHEADのコミットハッシュを取得し設定します。そのままでは長すぎるので--shortオプションを指定して短くしたものを使用しました。
アセンブリバージョンの方は文字列を指定するとコンパイルエラーとなってしまうのでコミットハッシュが使えません。仕方ないので「今までコミットされた回数」をリビジョン番号と見立てて設定しました。

バージョン情報の取得

AssemblyInfoに設定したバージョン情報は以下のようにして取得できます。

string assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
string fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion;

あとは必要な場面で使えばOKです。私の場合はタイトル画面のラベルに設定しました。

見た目は歪になりましたが、開発者からするとどの時点のソースか分かるので便利です。

down

コメントする