Skip to content

Commit

Permalink
Record NuGet PackageDownloads (#1296)
Browse files Browse the repository at this point in the history
* Record NuGet PackageDownloads

Read PackageDownloads from the assets file and record them as top-level development dependencies.
  • Loading branch information
ericstj authored Nov 14, 2024
1 parent a55475d commit 60c6b90
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ protected override Task OnFileFoundAsync(ProcessRequest processRequest, IDiction
this.NavigateAndRegister(target, explicitlyReferencedComponentIds, singleFileComponentRecorder, library, null, frameworkPackages);
}
}

// Register PackageDownload
this.RegisterPackageDownloads(singleFileComponentRecorder, lockFile);
}
catch (Exception e)
{
Expand Down Expand Up @@ -141,6 +144,30 @@ private void NavigateAndRegister(
bool IsADevelopmentDependency(LockFileTargetLibrary library) => library.RuntimeAssemblies.Concat(library.RuntimeTargets).All(IsAPlaceholderItem);
}

private void RegisterPackageDownloads(ISingleFileComponentRecorder singleFileComponentRecorder, LockFile lockFile)
{
foreach (var framework in lockFile.PackageSpec.TargetFrameworks)
{
foreach (var packageDownload in framework.DownloadDependencies)
{
if (packageDownload?.Name is null || packageDownload?.VersionRange?.MinVersion is null)
{
continue;
}

var libraryComponent = new DetectedComponent(new NuGetComponent(packageDownload.Name, packageDownload.VersionRange.MinVersion.ToNormalizedString()));

// PackageDownload is always a development dependency since it's usage does not make it part of the application
singleFileComponentRecorder.RegisterUsage(
libraryComponent,
isExplicitReferencedDependency: true,
parentComponentId: null,
isDevelopmentDependency: true,
targetFramework: framework.FrameworkName?.GetShortFolderName());
}
}
}

private List<(string Name, Version Version, VersionRange VersionRange)> GetTopLevelLibraries(LockFile lockFile)
{
// First, populate libraries from the TargetFrameworks section -- This is the base level authoritative list of nuget packages a project has dependencies on.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,7 @@
<data name="project_assets_3_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\project_assets_3_1.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
<data name="project_assets_packageDownload" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\project_assets_packageDownload.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
</data>
</root>
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"version": 3,
"targets": {
".NETFramework,Version=v4.7.2": {},
"net8.0": {}
},
"libraries": {},
"projectFileDependencyGroups": {
".NETFramework,Version=v4.7.2": [],
"net8.0": []
},
"packageFolders": {
"C:\\Users\\username\\.nuget\\packages\\": {},
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
},
"project": {
"version": "1.0.0",
"restore": {
"projectUniqueName": "C:\\src\\packageDownloadSample\\packageDownloadSample.csproj",
"projectName": "packageDownloadSample",
"projectPath": "C:\\src\\packageDownloadSample\\packageDownloadSample.csproj",
"packagesPath": "C:\\Users\\username\\.nuget\\packages\\",
"outputPath": "C:\\src\\packageDownloadSample\\obj\\",
"projectStyle": "PackageReference",
"crossTargeting": true,
"fallbackFolders": [
"C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
],
"configFilePaths": [
"C:\\Users\\username\\AppData\\Roaming\\NuGet\\NuGet.Config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
"C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
],
"originalTargetFrameworks": [
"net472",
"net8.0"
],
"sources": {
"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
"C:\\Program Files\\dotnet\\library-packs": {},
"https://api.nuget.org/v3/index.json": {}
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"projectReferences": {}
},
"net472": {
"targetAlias": "net472",
"projectReferences": {}
}
},
"warningProperties": {
"warnAsError": [
"NU1605"
]
},
"restoreAuditProperties": {
"enableAudit": "true",
"auditLevel": "low",
"auditMode": "all"
},
"SdkAnalysisLevel": "9.0.100"
},
"frameworks": {
"net8.0": {
"targetAlias": "net8.0",
"imports": [
"net461",
"net462",
"net47",
"net471",
"net472",
"net48",
"net481"
],
"assetTargetFallback": true,
"warn": true,
"downloadDependencies": [
{
"name": "Microsoft.Build",
"version": "[17.8.3, 17.8.3]"
},
{
"name": "Microsoft.Build.Framework",
"version": "[17.8.3, 17.8.3]"
},
{
"name": "Microsoft.Build.Utilities.Core",
"version": "[17.8.3, 17.8.3]"
}
],
"frameworkReferences": {
"Microsoft.NETCore.App": {
"privateAssets": "all"
}
},
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.100/PortableRuntimeIdentifierGraph.json"
},
"net472": {
"targetAlias": "net472",
"runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.100\\RuntimeIdentifierGraph.json"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,19 @@ public async Task ScanDirectoryAsync_DependencyGraph_3_1_VerificationAsync()
}
}

[TestMethod]
public async Task ScanDirectoryAsync_PackageDownload_VerificationAsync()
{
var (scanResult, componentRecorder) = await this.DetectorTestUtility
.WithFile(this.projectAssetsJsonFileName, TestResources.project_assets_packageDownload)
.ExecuteDetectorAsync();

var developmentDependencies = componentRecorder.GetDetectedComponents().Where(c => componentRecorder.GetEffectiveDevDependencyValue(c.Component.Id).GetValueOrDefault());
developmentDependencies.Should().HaveCount(3, "PackageDownload dev dependencies should exist.");
developmentDependencies.Select(c => c.Component).Should().AllBeOfType<NuGetComponent>();
developmentDependencies.Select(c => c.TargetFrameworks).Should().AllSatisfy(tfms => tfms.Should().BeEquivalentTo(["net8.0"]));
}

[TestMethod]
public async Task ScanDirectory_NoPackageSpecAsync()
{
Expand Down

0 comments on commit 60c6b90

Please sign in to comment.