Skip to content

Commit

Permalink
Added --use-project-assets-json (#82)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpeirson authored Jul 13, 2021
1 parent 5f8e211 commit 57c4f5c
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Usage: dotnet-project-licenses [options]
| `--help` | Display this help screen. |
| `--version` | Display version information. |
| `--ignore-ssl-certificate-errors` | Ignores SSL certificate errors in HttpClient. |
| `--use-project-assets-json` | Use the resolved project.assets.json file for each project as the source of package information. Requires the `-t` option since this always includes transitive references. Requires `nuget restore` or `dotnet restore` to be run first. |

## Example tool commands

Expand Down
59 changes: 57 additions & 2 deletions src/Methods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
Expand Down Expand Up @@ -277,8 +278,27 @@ public IEnumerable<string> GetProjectReferences(string projectPath)
throw new FileNotFoundException();
}

// First try to get references from new project file format
var references = GetProjectReferencesFromNewProjectFile(projectPath);
IEnumerable<string> references = Array.Empty<string>();

// First use project.assets.json, if this option is enabled.
if (_packageOptions.UseProjectAssetsJson)
{
var assetsFile = Path.Combine(Path.GetDirectoryName(projectPath) ?? ".", "obj", "project.assets.json");
if (!File.Exists(assetsFile))
{
WriteOutput(() => $"Cannot find {assetsFile}", logLevel: LogLevel.Warning);
}
else
{
references = GetProjectReferencesFromAssetsFile(assetsFile);
}
}

// Then try to get references from new project file format
if (!references.Any())
{
references = GetProjectReferencesFromNewProjectFile(projectPath);
}

// Then if needed from old packages.config
if (!references.Any())
Expand Down Expand Up @@ -617,6 +637,41 @@ private IEnumerable<string> GetProjectReferencesFromPackagesConfig(string projec
return Array.Empty<string>();
}

/// <summary>
/// Gets project references from a project.assets.json file.
/// </summary>
/// <param name="assetsPath">The assets file</param>
/// <returns></returns>
private IEnumerable<string> GetProjectReferencesFromAssetsFile(string assetsPath)
{
WriteOutput(() => $"Reading assets file {assetsPath}", logLevel: LogLevel.Verbose);
using var assetsFileStream = File.OpenRead(assetsPath);
var doc = JsonDocument.Parse(assetsFileStream);
assetsFileStream.Dispose();

if (!doc.RootElement.TryGetProperty("targets", out var targets))
{
WriteOutput(() => $"No \"targets\" property found in {assetsPath}", logLevel: LogLevel.Warning);
yield break;
}

foreach (var target in targets.EnumerateObject())
{
WriteOutput(() => $"Reading dependencies for target {target.Name}", logLevel: LogLevel.Verbose);
foreach (var dep in target.Value.EnumerateObject())
{
var depName = dep.Name.Split('/');
if (depName.Length != 2)
{
WriteOutput(() => $"Unexpected package name: {dep.Name}", logLevel: LogLevel.Warning);
continue;
}

yield return string.Join(",", depName);
}
}
}

private async Task<IEnumerable<string>> GetValidProjects(string projectPath)
{
var pathInfo = new FileInfo(projectPath);
Expand Down
3 changes: 3 additions & 0 deletions src/PackageOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ public class PackageOptions
[Option("ignore-ssl-certificate-errors", Default = false, HelpText = "Ignore SSL certificate errors in HttpClient.")]
public bool IgnoreSslCertificateErrors { get; set; }

[Option("use-project-assets-json", Default = false, HelpText = "Use the resolved project.assets.json file for each project as the source of package information. Requires the -t option. Requires `nuget restore` or `dotnet restore` to be run first.")]
public bool UseProjectAssetsJson { get; set; }

[Usage(ApplicationAlias = "dotnet-project-licenses")]
public static IEnumerable<Example> Examples
{
Expand Down
8 changes: 8 additions & 0 deletions src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ private static async Task<int> Execute(PackageOptions options)
return 1;
}

if (options.UseProjectAssetsJson && !options.IncludeTransitive)
{
Console.WriteLine("ERROR(S):");
Console.WriteLine("--use-project-assets-json\tThis option always includes transitive references, so you must also provide the -t option.");

return 1;
}

try
{
Methods methods = new Methods(options);
Expand Down
28 changes: 28 additions & 0 deletions tests/NugetUtility.Tests/MethodsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using CommandLine.Text;
using FluentAssertions;
using NUnit.Framework;

Expand Down Expand Up @@ -185,6 +187,32 @@ public async Task GetPackages_InputJson_Should_OnlyParseGivenProjects () {
validationResult.InvalidPackages.Count.Should ().Be (3);
}

[Test]
public async Task GetProjectReferencesFromAssetsFile_Should_Resolve_Transitive_Assets()
{
var methods = new Methods(new PackageOptions
{
UseProjectAssetsJson = true,
IncludeTransitive = true,
ProjectDirectory = @"../../../",
});

var packages = await methods.GetPackages();
packages.Should().ContainKey("../../../NugetUtility.Tests.csproj");
packages.Should().HaveCount(1);
var list = packages.Values.First();

// Just look for a few expected packages. First-order refs:
list.Should().ContainKey($"dotnet-project-licenses,{typeof(Methods).Assembly.GetName().Version.ToString(3)}");
list.Should().ContainKey($"NUnit,{typeof(TestAttribute).Assembly.GetName().Version.ToString(3)}");

// Some second-order refs:
list.Should().ContainKey($"CommandLineParser,{typeof(UsageAttribute).Assembly.GetName().Version.ToString(3)}");
list.Should().ContainKey("System.IO.Compression,4.3.0");

// Some third-order refs:
list.Should().ContainKey("System.Buffers,4.3.0");
}

[TestCase("BenchmarkDotNet", "0.12.1", "https://licenses.nuget.org/MIT", "MIT")]
[TestCase("BCrypt.Net-Next", "2.1.3", "https://github.com/BcryptNet/bcrypt.net/blob/master/licence.txt", "")]
Expand Down

0 comments on commit 57c4f5c

Please sign in to comment.