< Summary - ZhEaIsNsAaBn.Libraries coverage (affected: 23 packages)

Information
Class: ZhEaIsNsAaBn.DbSeeder.Tool.ProjectMetadata
Assembly: ZhEaIsNsAaBn.DbSeeder.Tool
File(s): /home/runner/work/ZhEaIsNsAaBn.Libraries.V1/ZhEaIsNsAaBn.Libraries.V1/src/DataBasePackages/ZhEaIsNsAaBn.DbSeeder.Tool/ProjectMetadata.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 35
Coverable lines: 35
Total lines: 86
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 22
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
ResolveProjectFile(...)0%110100%
TargetFrameworkAsync()0%7280%
ReadAsync()100%210%
PropertiesAsync()0%2040%

File(s)

/home/runner/work/ZhEaIsNsAaBn.Libraries.V1/ZhEaIsNsAaBn.Libraries.V1/src/DataBasePackages/ZhEaIsNsAaBn.DbSeeder.Tool/ProjectMetadata.cs

#LineLine coverage
 1using System.Text.Json;
 2
 3namespace ZhEaIsNsAaBn.DbSeeder.Tool;
 4
 5/// <summary>A project's build facts, from <c>dotnet msbuild -getProperty</c> (evaluation only, no injected targets).</s
 06internal sealed record ProjectMetadata( string ProjectFile, string Name, string ProjectDirectory, string TargetFramework
 07                                        string RuntimeConfigFile, IReadOnlyList<string> PackageFolders )
 8{
 9    /// <summary>The project file for <paramref name="path"/>: a .csproj, or the folder holding exactly one.</summary>
 10    /// <exception cref="ToolException">No project or several.</exception>
 11    public static string ResolveProjectFile( string? path, string currentDirectory )
 12    {
 013        var full = Path.GetFullPath( path ?? ".", currentDirectory );
 14
 015        if ( File.Exists( full ) ) { return full; }
 16
 017        if ( !Directory.Exists( full ) ) { throw new ToolException( $"{full} doesn't exist." ); }
 18
 019        var projects = Directory.GetFiles( full, "*.csproj" );
 20
 021        return projects.Length switch
 022        {
 023            1 => projects[ 0 ],
 024            0 => throw new ToolException( $"No project in {full}. Use --project (and --startup-project)." ),
 025            _ => throw new ToolException( $"More than one project in {full}: {string.Join( ", ", projects.Select( Path.G
 026        };
 27    }
 28
 29    /// <summary>The target framework to use: <paramref name="framework"/>, else the project's only one.</summary>
 30    /// <exception cref="ToolException">The project has several and none was picked.</exception>
 31    public static async Task<string> TargetFrameworkAsync( string projectFile, string? framework, string configuration, 
 32    {
 033        if ( framework is not null ) { return framework; }
 34
 035        var properties = await PropertiesAsync( projectFile, null, configuration, process, "TargetFramework", "TargetFra
 36
 037        if ( properties[ "TargetFramework" ] is { Length: > 0 } single ) { return single; }
 38
 039        var frameworks = properties[ "TargetFrameworks" ].Split( ';', StringSplitOptions.RemoveEmptyEntries | StringSpli
 40
 041        return frameworks.Length == 1
 042                   ? frameworks[ 0 ]
 043                   : throw new ToolException( $"{Path.GetFileNameWithoutExtension( projectFile )} targets {string.Join( 
 044    }
 45
 46    /// <summary>The metadata after a build (NuGetPackageFolders comes from the restore).</summary>
 47    public static async Task<ProjectMetadata> ReadAsync( string projectFile, string framework, string configuration, Too
 48    {
 049        var properties = await PropertiesAsync( projectFile, framework, configuration, process, "MSBuildProjectName", "P
 050                                                "ProjectRuntimeConfigFilePath", "NuGetPackageFolders" ).ConfigureAwait( 
 51
 052        return new ProjectMetadata( projectFile, properties[ "MSBuildProjectName" ], properties[ "ProjectDir" ], framewo
 053                                    properties[ "ProjectDepsFilePath" ], properties[ "ProjectRuntimeConfigFilePath" ],
 054                                    properties[ "NuGetPackageFolders" ].Split( ';', StringSplitOptions.RemoveEmptyEntrie
 055    }
 56
 57
 58    private static async Task<Dictionary<string, string>> PropertiesAsync( string projectFile, string? framework, string
 59                                                                            params string[] names )
 60    {
 061        List<string> args = [ "msbuild", projectFile, "-nologo", $"-p:Configuration={configuration}", .. names.Select( n
 62
 063        if ( framework is not null ) { args.Add( $"-p:TargetFramework={framework}" ); }
 64
 065        var (code, output) = await process.CaptureAsync( args ).ConfigureAwait( false );
 66
 067        if ( code != 0 ) { throw new ToolException( $"Reading {Path.GetFileName( projectFile )} failed:\n{output}" ); }
 68
 69        try
 70        {
 071            using var document = JsonDocument.Parse( output );
 72
 073            return names.ToDictionary( n => n, n => document.RootElement.GetProperty( "Properties" ).GetProperty( n ).Ge
 74        }
 075        catch ( JsonException )
 76        {
 077            throw new ToolException( $"Unexpected output from dotnet msbuild -getProperty (SDK 8 or later needed):\n{out
 78        }
 079    }
 80}
 81
 82/// <summary>A tool error: printed as <c>error: …</c>, exit code 2.</summary>
 83internal sealed class ToolException : Exception
 84{
 85    public ToolException( string message ) : base( message ) { }
 86}