GitHub Actionsのsetup-dotnetアクションは、global.jsonを解釈して.NET SDKをインストールできます。ただ、global.jsonサポートは限定的でバージョン直指定かrollForwardlatestFeatureのみ対応しています。
気まぐれでC#でもサクッと同じものを用意したのでメモにおいておきます。特に意味はないけど、setup-dotnetと同じ解釈をしつつ何かツールに組み込むなら使えるか?1
setup-dotnetのglobal.json解釈
setup-dotnetのglobal.json解釈は、getVersionFromGlobalJson関数で行っています。(ソースコード)
function getVersionFromGlobalJson(globalJsonPath: string): string { let version = ''; const globalJson = JSON5.parse( // .trim() is necessary to strip BOM https://github.com/nodejs/node/issues/20649 fs.readFileSync(globalJsonPath, {encoding: 'utf8'}).trim(), // is necessary as JSON5 supports wider variety of options for numbers: https://www.npmjs.com/package/json5#numbers (key, value) => { if (key === 'version' || key === 'rollForward') return String(value); return value; } ); if (globalJson.sdk && globalJson.sdk.version) { version = globalJson.sdk.version; const rollForward = globalJson.sdk.rollForward; if (rollForward && rollForward === 'latestFeature') { const [major, minor] = version.split('.'); version = `${major}.${minor}`; } } return version; }
C#ポート
C#でTypeScriptと同様の処理を書きます。
// port of TypeScript https://github.com/actions/setup-dotnet/blob/83c0c1a6c843e2d7e6b14cc940a4a8c77243829b/src/setup-dotnet.ts#L99C1-L119C2 using System.Text.Json; using System.Text.Json.Serialization; // global.json spec https://docs.microsoft.com/en-us/dotnet/core/tools/global-json string GetVersionFromGlobalJson(string json) { JsonSerializerOptions options = new() { ReadCommentHandling = JsonCommentHandling.Skip, AllowTrailingCommas = true, }; options.Converters.Add(new JsonStringEnumConverter()); GlobalJson globalJson = JsonSerializer.Deserialize<GlobalJson>(json, options)!; var version = ""; if (globalJson.Sdk is { } sdk && sdk.Version is not null) { version = sdk.Version; var rollForawrd = sdk.RollForward; if (rollForawrd is not null && rollForawrd == GlobalJson.RollForwardType.latestFeature) { var split = sdk.Version.Split(".", StringSplitOptions.RemoveEmptyEntries); var (major, minor) = split.Length >= 2 ? (split[0], split[1]) : ("0", "0"); version = $"{major}.{minor}"; } } return version; } record GlobalJson() { [JsonPropertyName("sdk")] public required SdkInfo Sdk { get; init; } public record SdkInfo() { [JsonPropertyName("version")] public string? Version { get; init; } [JsonPropertyName("allowPrerelease")] public bool? AllowPrerelease { get; init; } [JsonPropertyName("rollForward")] public RollForwardType? RollForward { get; init; } } public enum RollForwardType { patch, feature, minor, major, latestPatch, latestFeature, latestMinor, latestMajor, disable, } }
呼び出してみましょう。
args = ["../../../../global.json"]; var filePath = Path.GetFullPath(args[0]); if (!File.Exists(filePath)) { Console.WriteLine($"global.jsonが見つかりません。 {filePath}"); return; } string json = File.ReadAllText(filePath); var version = GetVersionFromGlobalJson(json); Console.WriteLine(version);
以下のglobal.jsonなら、9.0.200が出力されます。
{ "sdk": { "version": "9.0.200" } }
以下のglobal.jsonなら、9.0が出力されます。
{ "sdk": { "version": "9.0.103", "rollForward": "latestFeature" } }
おまけ
latestFeature以外のバージョンをどう解決するかは、現在インストールされているdotnet sdk一覧やプロジェクトのTargetFrameworkも解釈が必要で面倒なんですね。なのでsetup-dotnetでもサポート薄い2のはなるほどという感じでした。やりやすくはなさそう。
おまけのおまけ
setup-dotnet的には、出力結果のバージョン文字列はinstall-dotnetのバージョン指定に使われています。(ソースコード)
dotnetInstaller = new DotnetCoreInstaller(version, quality);
渡し先のDotnetVersionResolver.createDotnetVersion()がdotnet-installへの引数解決場所で、なるほど地道だった。