Skip to content

Commit 9640ade

Browse files
authored
Merge pull request #60 from ErikApption/main
Upgrade to dotnet8, and new plugin to list project dependencies
2 parents b9ee476 + 1f854bf commit 9640ade

26 files changed

Lines changed: 316 additions & 41 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
- name: Setup .NET
1818
uses: actions/setup-dotnet@v2
1919
with:
20-
dotnet-version: 6.0.x
20+
dotnet-version: 8.0.x
2121
- name: Restore dependencies
2222
run: dotnet restore
2323
- name: Build

Microsoft.NugetNinja.sln

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NugetNinja.MissingPropertyP
2929
EndProject
3030
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NugetNinja.PrBot", "src\NugetNinja.PrBot\NugetNinja.PrBot.csproj", "{FF24D161-7796-4CA2-A652-061DBEE89626}"
3131
EndProject
32+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NugetNinja.PackageListerPlugin", "NugetNinja.PackageListerPlugin\NugetNinja.PackageListerPlugin.csproj", "{73804BAD-88F7-4283-9AFF-394AA8CC7C6F}"
33+
EndProject
34+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{6C1940FB-3AD9-4952-AB03-A06F7B99B6A7}"
35+
ProjectSection(SolutionItems) = preProject
36+
.github\workflows\build.yml = .github\workflows\build.yml
37+
EndProjectSection
38+
EndProject
3239
Global
3340
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3441
Debug|Any CPU = Debug|Any CPU
@@ -75,6 +82,10 @@ Global
7582
{FF24D161-7796-4CA2-A652-061DBEE89626}.Debug|Any CPU.Build.0 = Debug|Any CPU
7683
{FF24D161-7796-4CA2-A652-061DBEE89626}.Release|Any CPU.ActiveCfg = Release|Any CPU
7784
{FF24D161-7796-4CA2-A652-061DBEE89626}.Release|Any CPU.Build.0 = Release|Any CPU
85+
{73804BAD-88F7-4283-9AFF-394AA8CC7C6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
86+
{73804BAD-88F7-4283-9AFF-394AA8CC7C6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
87+
{73804BAD-88F7-4283-9AFF-394AA8CC7C6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
88+
{73804BAD-88F7-4283-9AFF-394AA8CC7C6F}.Release|Any CPU.Build.0 = Release|Any CPU
7889
EndGlobalSection
7990
GlobalSection(SolutionProperties) = preSolution
8091
HideSolutionNode = FALSE
@@ -91,6 +102,7 @@ Global
91102
{D2D68A5F-3283-4001-840F-3E14A9B372E8} = {0EEF3C9A-9684-4642-9A66-8CD819EC6235}
92103
{335BE82E-E650-4E62-8107-B6BBD34E3107} = {0EEF3C9A-9684-4642-9A66-8CD819EC6235}
93104
{FF24D161-7796-4CA2-A652-061DBEE89626} = {EE324A7A-86D4-4B7D-ADC5-3E6504738413}
105+
{73804BAD-88F7-4283-9AFF-394AA8CC7C6F} = {0EEF3C9A-9684-4642-9A66-8CD819EC6235}
94106
EndGlobalSection
95107
GlobalSection(ExtensibilityGlobals) = postSolution
96108
SolutionGuid = {2352F460-4B23-4215-951C-A3E923145148}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.NugetNinja.Core;
5+
6+
namespace Microsoft.NugetNinja.PackageListerPlugin;
7+
8+
public class PackageListingHandler : DetectorBasedCommandHandler<PackageListerDetector, StartUp>
9+
{
10+
public override string Name => "list-packages";
11+
12+
public override string Description => "The command to generate a csv file with all direct packages and nuget.org descriptions. Dry run will only list the packages on the console.";
13+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Globalization;
5+
using System.Text;
6+
using CsvHelper;
7+
using CsvHelper.Configuration.Attributes;
8+
using Microsoft.Extensions.Logging;
9+
using Microsoft.NugetNinja.Core;
10+
using NuGet.Common;
11+
using NuGet.Configuration;
12+
using NuGet.Protocol.Core.Types;
13+
using NugetNinja.PackageListerPlugin.Models;
14+
15+
namespace Microsoft.NugetNinja.PackageListerPlugin;
16+
17+
public class PackageList : IAction
18+
{
19+
20+
private List<(string project, List<Package> packages)> _allPackages;
21+
private readonly ILogger<PackageListerDetector> _logger;
22+
23+
public PackageList(List<(string, List<Package>)> allPackages1, Extensions.Logging.ILogger<PackageListerDetector> logger)
24+
{
25+
_allPackages = allPackages1;
26+
_logger = logger;
27+
}
28+
29+
public string BuildMessage()
30+
{
31+
var sb = new StringBuilder();
32+
foreach (var package in _allPackages)
33+
{
34+
sb.AppendLine($"Project: {package.project}\n");
35+
foreach (var p in package.packages)
36+
{
37+
sb.AppendLine($" {p.Name} {p.Version}\n");
38+
}
39+
}
40+
return sb.ToString();
41+
}
42+
43+
public async Task TakeActionAsync()
44+
{
45+
_logger.LogInformation($"Preparing summary file");
46+
var flatList = _allPackages.SelectMany(p => p.packages.Select(package => (p.project, package))).ToList();
47+
var byPackage = flatList.GroupBy(p => p.package.Name).ToList();
48+
var allLines = new List<PackageListLine>();
49+
foreach (var el in byPackage)
50+
{
51+
try
52+
{
53+
var description = SanitizeNugetDescription(await GetNugetDescriptionAsync(el.Key));
54+
allLines.Add(new PackageListLine(el.Key, GetAllVersions(el), description, null, GetAllProjects(el)));
55+
}
56+
catch (Exception e)
57+
{
58+
_logger.LogError(e, $"Error processing package {el.Key}");
59+
}
60+
}
61+
allLines = allLines.OrderBy(p => p.PackageId).ToList();
62+
var outFile = "all_packages.csv";
63+
_logger.LogInformation($"Writing package list to {Path.GetFullPath(outFile)}");
64+
using (var writer = new StreamWriter("all_packages.csv"))
65+
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
66+
{
67+
csv.WriteRecords(allLines);
68+
}
69+
await Task.CompletedTask;
70+
}
71+
72+
public async Task<string> GetNugetDescriptionAsync(string packageId)
73+
{
74+
_logger.LogInformation($"Getting description from nuget.org for {packageId}");
75+
var providers = NuGet.Protocol.Core.Types.Repository.Provider.GetCoreV3();
76+
var source = new PackageSource("https://api.nuget.org/v3/index.json");
77+
var repository = new SourceRepository(source, providers);
78+
var resource = await repository.GetResourceAsync<PackageMetadataResource>();
79+
var metadata = await resource.GetMetadataAsync(packageId, includePrerelease: false, includeUnlisted: false, new SourceCacheContext(), NullLogger.Instance, CancellationToken.None);
80+
81+
var packageMetadata = metadata.FirstOrDefault();
82+
return packageMetadata?.Description ?? "Description not found";
83+
}
84+
85+
private static string SanitizeNugetDescription(string desc)
86+
{
87+
const string marker = "Commonly used types:";
88+
int index = desc.IndexOf(marker, StringComparison.OrdinalIgnoreCase);
89+
if (index >= 0)
90+
{
91+
desc = desc.Substring(0, index);
92+
}
93+
return desc.Replace("\n", " ").Replace("\r", " ").Trim();
94+
}
95+
96+
public string GetAllVersions(IEnumerable<(string project, Package package)> packages)
97+
{
98+
var allVersions = packages.Select(p => p.package.SourceVersionText).Distinct().ToList();
99+
return string.Join(", ", allVersions);
100+
}
101+
102+
public string GetAllProjects(IEnumerable<(string project, Package package)> packages)
103+
{
104+
var allProjects = packages.Select(p => p.project).Distinct().ToList();
105+
return string.Join(", ", allProjects);
106+
}
107+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
10+
namespace NugetNinja.PackageListerPlugin.Models
11+
{
12+
public record PackageListLine(string PackageId, string Versions, string NugetDescription, string? TargetFramework, string Projects);
13+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="CsvHelper" Version="33.0.1" />
11+
<PackageReference Include="NuGet.Protocol" Version="6.11.1" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<ProjectReference Include="..\src\NugetNinja.Core\NugetNinja.Core.csproj" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.NugetNinja.Core;
5+
6+
namespace Microsoft.NugetNinja.PackageListerPlugin;
7+
8+
public class PackageListerPlugin : INinjaPlugin
9+
{
10+
public CommandHandler[] Install() => new CommandHandler[] { new PackageListingHandler() };
11+
}
12+
13+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.Extensions.Logging;
5+
using Microsoft.NugetNinja.Core;
6+
7+
namespace Microsoft.NugetNinja.PackageListerPlugin;
8+
9+
public class PackageListerDetector : IActionDetector
10+
{
11+
private readonly ILogger<PackageListerDetector> _logger;
12+
private readonly bool _fillInOutputType = false;
13+
private readonly bool _enforceNullable = false;
14+
private readonly bool _enforceImplicitUsings = false;
15+
private readonly string[] _notSupportedRuntimes = {
16+
"net5.0",
17+
"netcoreapp3.0",
18+
"netcoreapp2.2",
19+
"netcoreapp2.1",
20+
"netcoreapp1.1",
21+
"netcoreapp1.0",
22+
};
23+
24+
private readonly string _suggestedRuntime = "net8.0";
25+
26+
public PackageListerDetector(
27+
ILogger<PackageListerDetector> logger)
28+
{
29+
_logger = logger;
30+
}
31+
32+
public async IAsyncEnumerable<IAction> AnalyzeAsync(Model context)
33+
{
34+
_logger.LogInformation("Analyzing package list");
35+
await Task.CompletedTask;
36+
var allPackages = new List<(string,List<Package>)>();
37+
foreach (var project in context.AllProjects)
38+
{
39+
allPackages.Add((project.PathOnDisk,project.PackageReferences));
40+
}
41+
yield return new PackageList(allPackages, _logger);
42+
}
43+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.NugetNinja.Core;
6+
7+
namespace Microsoft.NugetNinja.PackageListerPlugin;
8+
9+
public class StartUp : IStartUp
10+
{
11+
public void ConfigureServices(IServiceCollection services)
12+
{
13+
services.AddTransient<PackageListerDetector>();
14+
}
15+
}

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
Nuget Ninjia is a tool for detecting dependencies of .NET projects. It analyzes the dependency structure of .NET projects in a directory and builds a directed acyclic graph. And will give some modification suggestions for Nuget packages, so that the dependencies of the project are as concise and up-to-date as possible.
1111

12+
The tool can also generate a list of all top level dependencies into a CSV file. This CSV includes the nuget description and avoids issues with `shproj` and `dotnet list packages`.
13+
1214
## Usage
1315

1416
After getting the binary, run it directly in the terminal.
@@ -36,13 +38,14 @@ Commands:
3638
upgrade-pkg The command to upgrade all package references to possible latest and avoid conflicts.
3739
clean-pkg The command to clean up possible useless package references.
3840
clean-prj The command to clean up possible useless project references.
41+
list-packages The command to generate a csv file with all direct packages and nuget.org descriptions. Dry run will only list the packages on the console.
3942
```
4043

4144
## How to build and run locally
4245

4346
Requirements about how to develop.
4447

45-
* [.NET SDK 6.0](https://github.com/dotnet/core/tree/master/release-notes)
48+
* [.NET SDK 8.0](https://github.com/dotnet/core/tree/master/release-notes)
4649

4750
1. Execute `dotnet restore` to restore all .NET dependencies.
4851
2. Execute the following command to build the app:

0 commit comments

Comments
 (0)