dotnet toolはグローバルツールではなく、プロジェクトツールとして管理するとCIや開発メンバーの環境に依存せずツールを使うことができます。
今回は、プロジェクトのツールを復元するためdotnet tool restore
したときに出たエラー対処についてメモです。
エラーメッセージ
プロジェクトで適当なツールを保持しているとしましょう。
$ dotnet new tool-manifest $ dotnet tool install dotnet-test-rerun
これをCI環境で実行すると次のようなエラー起こりました。ローカルでは問題ないのにCIでだけおこる、何が何だかさっぱりわかりませんね。
$ dotnet tool restore Unhandled exception: Microsoft.DotNet.ToolPackage.ToolConfigurationException: Settings file 'DotnetToolSettings.xml' was not found in the package. at Microsoft.DotNet.ToolPackage.ToolPackageInstance.DeserializeToolConfiguration(LockFileTargetLibrary library) at Microsoft.DotNet.ToolPackage.ToolPackageInstance.GetToolConfiguration() at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy`1.CreateValue() at Microsoft.DotNet.ToolPackage.ToolPackageInstance.GetCommands() at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy`1.CreateValue() at Microsoft.DotNet.Tools.Tool.Restore.ToolRestoreCommand.InstallPackages(ToolManifestPackage package, Nullable`1 configFile) at System.Linq.Enumerable.SelectArrayIterator`2.Fill(ReadOnlySpan`1 source, Span`1 destination, Func`2 func) at System.Linq.Enumerable.SelectArrayIterator`2.ToArray() at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source) at Microsoft.DotNet.Tools.Tool.Restore.ToolRestoreCommand.Execute() at System.CommandLine.Invocation.InvocationPipeline.Invoke(ParseResult parseResult) at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, TimeSpan startupTime, ITelemetry telemetryClient)
GitHub Actionsのエラー例です。
原因
とりあえずエラーとなっているファイルがどこにあるか見てみましょう。DotnetToolSettings.xml
はツールの設定ファイルで次のパスにあります。このファイルの中身自体は問題じゃなく、ファイルパスがヒントになります。
$HOME/.nuget/packages/ツール名/ツールのバージョン/tools/ツールのターゲットフレームワーク/any/DotnetToolSettings.xml
例えばdotnet-test-rerun
ツールは2.1.0
と3.0.0
でそれぞれ次のようなパスになります。注目すべきはツールのターゲットフレームワークです。dotnet tool restore
が成功する条件は、実行環境にツールのターゲットフレームワークの.NET SDKが入っている必要があります。
# Windowsのパス (Linuxなら$HOMEに置き換える) %USERPROFILE%/.nuget/packages/dotnet-test-rerun/2.1.0/tools/net8.0/any/DotnetToolSettings.xml %USERPROFILE%/.nuget/packages/dotnet-test-rerun/3.0.0/tools/net9.0/any/DotnetToolSettings.xml
言い換えると、ツールが想定しているターゲットフレームワークに合致する.NET SDKのバージョンが入っていないと冒頭のエラーが発生します。
今回エラーが起こった私の環境は、「C#プロジェクトのターゲットフレームワークがnet8.0
」「ローカルマシンには.NET 9 SDKがインストールされていた」という状況でした。
- ローカル環境には、.NET 9 SDKがインストールされている。CI環境はプロジェクトにあわせて.NET 8 SDKがインストールされている
- ローカルでツールを構成時、
dotnet tool install dotnet-test-rerun
で最新版3.0.0がインストールされた - 同3.0.0は
net9.0
だけをターゲットフレームワークとしておりnet8.0
はターゲットフレームワークにない - CIで
dotnet tool restore
を実行するとnet8.0
のパスでDotnetToolSettings.xml
を探そうとする、が見つからず冒頭のエラーが出た
仮に、3.0.0がnet8.0
もターゲットフレームワークに入れていればエラーは起こらなかったし、プロジェクトのターゲットフレームワークがnet9.0
をターゲットにしていてもエラーは起こりませんでした。
ちなみにGitHub Discussionではファイルアクセス権限などを指摘しているものがありますが、今回のエラーはそういった問題ではないです。なんとググっても情報がない。
dotnet tool install gherkin fails #143952 | GitHub Community
対処
原因がわかれば対処も簡単です。対処は3つ考えられます。
- ツールをプロジェクト合致するターゲットフレームワークをサポートしているバージョンにする
- ツールのターゲットフレームワークに合致する.NET SDKをインストールする
- 自分のプロジェクトをツールのターゲットフレームワークにあわせてしまう
1は、ツールのバージョンによって機能差がないならいいでしょう。今回は、2.1.0と3.0.0の差分はターゲットフレームワークとパッケージ更新だけだったので、2.1.0にしました。
otnet tool install dotnet-test-rerun --version 2.1.0
2は、CI環境に追加で.NET 9 SDKをインストールするだけです。そこまで悪くないですが、プロジェクトが.NET 8 SDKなので、チームメンバーの環境でも動作保証するには対応が一貫性取れてないですね。
# プロジェクトとしては8.0.xだけでいいが、ツールのために9.0.xも追加する - uses: actions/setup-dotnet@v4 with: dotnet-version: | 8.0.x 9.0.x
3は、ツールを動機にプロジェクトのターゲットフレームワークもあげる動きになります。バージョンの一貫性はあるものの、ほかのツールやライブラリとの整合性担保も必要になるので、普段から最新バージョン追随している環境でないと難しいケースも考えられます。1
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net9.0</TargetFramework> </PropertyGroup> </Project>
まとめ
DotnetToolSettings.xmlが見つからないエラーから、ターゲットフレームワークがずれているを察するのはむりげーですね。厳しい。 WSL Ubuntuとか使っていると、Ubuntuで.NET 9 SDKを入れるのはめんどくさい2ので出会いやすいです。非Windows環境への.NET SDKのパッケージマネージャー経由の配布が微妙なんですよね。
このエラーについては、調べても情報にたどりつけないので次に出会った人が楽になることを願います。