Contents — 6 sections
Windows用のUnityスモーク試験runnerを作っていた。
やることは単純。
対象branchをworktreeへ展開し、Unityをbatch modeで起動し、smoke.txt と error CS を拾う。
Script自体のロジックは大したことがない。
でもWindows PowerShell 5.1で実行すると壊れた。
原因はC#でもUnityでもなかった。
日本語を含む .ps1 の文字コードだった。
BOMなしUTF-8をそのまま読んでくれなかった
対象は tools/windows/run-smoke.ps1。
Script内には、日本語を含むコメントや文字列があった。
開発側ではUTF-8として普通に見えている。
ところが当時のWindows PowerShell 5.1環境では、BOMなしUTF-8の日本語部分がUTF-8として認識されず、システム既定のANSIコードページ側として解釈された。
その結果、文字列境界などが崩れ、最終的には構文エラーになる。
見た目は、
「PowerShell Scriptの文法がおかしい」
なのに、実際に直す場所はロジックではなくencodingだった。
対応はBOM付きUTF-8へ固定
対応は .ps1 をUTF-8 with BOMで保存すること。
さらに人間のEditor設定任せにしないため、.editorconfig 側でもPowerShell fileのencodingを固定した。
狙いは、
「このPCではたまたま動く」
を避けること。
Windows側へhandoffするScriptなら、実行環境がWindows PowerShell 5.1である可能性も含めて、保存形式をRepositoryへ残す。
なぜ気づきにくかったか
この問題が面倒なのは、コードレビューではほぼ正常に見えること。
GitHub上でもEditor上でも日本語は読める。
差分も正しい。
構文も正しい。
でも「そのRuntimeがファイルをどうdecodeするか」だけが違う。
つまりSource Codeの見た目と、Runtimeが読むbyte列の解釈が一致していなかった。
Windowsのhandoffでは「Script本体」以外も仕様
今回のrunnerでは、
- branchをworktree展開
- Unity batchmode
- smoke result
error CS抽出
を自動化した。
こういうhandoff用Scriptでは、実行コマンドだけ書けば十分に見える。
でも実際には、
- PowerShell version
- encoding
- line ending
- execution policy
- path
- installed dependency
も再現性の一部。
今回壊れたのは、そのうちencodingだった。
「UTF-8ならOK」と一括りにしない
ここでの話は、
「PowerShellはUTF-8がダメ」
という意味ではない。
PowerShellの世代や既定encodingは違う。
今回問題になったのは、Windows PowerShell 5.1という実行環境と、BOMなしUTF-8の日本語入りScriptの組み合わせだった。
だから対策も、その環境を対象にBOM付きUTF-8へ固定した。
いまの結論
障害の見た目が「構文エラー」でも、原因が構文とは限らない。
特にWindowsの古いShellへScriptをhandoffするときは、
文字コードも依存関係として固定する。
UnityやVRChatのスモーク試験を自動化しているのに、試験runner自身がencodingで壊れるのはかなり間抜けだった。
でも、こういう一回踏めば二度と忘れない失敗は、短いKnowledgeとして残す価値がある。