Skip to content

Commit

Permalink
fix: #5 "https://api.nuget.org/v3/index.json" must not be hard-coded
Browse files Browse the repository at this point in the history
  • Loading branch information
Samir Boulema committed Jun 19, 2023
1 parent 5e3d219 commit 2243d20
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 32 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ for the installed NuGet packages for the open solution.
## Installing
[Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=SamirBoulema.NuGetMonitor) [![Visual Studio Marketplace](https://img.shields.io/vscode-marketplace/v/SamirBoulema.NuGetMonitor.svg?style=flat)](https://marketplace.visualstudio.com/items?itemName=SamirBoulema.NuGetMonitor)

[Github Releases](https://github.com/sboulema/NuGetMonitor/releases)
[GitHub Releases](https://github.com/sboulema/NuGetMonitor/releases)

[Open VSIX Gallery](https://www.vsixgallery.com/extension/NuGetMonitor.2a6fbffe-f3fd-4bf8-98cc-5ae2c833a1c7)

## Screenshots
[![Screenshot](https://raw.githubusercontent.com/sboulema/NuGetMonitor/main/art/Screenshot2.png)](https://raw.githubusercontent.com/sboulema/NuGetMonitor/main/art/Screenshot2.png)

[![Screenshot](https://raw.githubusercontent.com/sboulema/NuGetMonitor/main/art/Screenshot.png)](https://raw.githubusercontent.com/sboulema/NuGetMonitor/main/art/Screenshot.png)

## Thanks
Expand All @@ -30,7 +32,7 @@ A big thanks goes to [AnushaG2201](https://github.com/AnushaG2201)!

I was playing with the idea for this extension for quite a while but never figured out how I would create this extension.

That is until I saw the [Nuget-updates-notifier](https://marketplace.visualstudio.com/items?itemName=Anusha.NugetPackageUpdateNotifier) ([Github](https://github.com/AnushaG2201/Nuget-updates-notifier)) which gave me the remaining puzzle pieces, so that I could create my own version.
That is until I saw the [Nuget-updates-notifier](https://marketplace.visualstudio.com/items?itemName=Anusha.NugetPackageUpdateNotifier) ([GitHub](https://github.com/AnushaG2201/Nuget-updates-notifier)) which gave me the remaining puzzle pieces, so that I could create my own version.

### tom-englert
A big thanks goes to [tom-englert](https://github.com/tom-englert)!
Expand Down
Binary file modified art/Screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added art/Screenshot2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/Services/InfoBarService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ private static List<IVsInfoBarTextSpan> GetTextSpans(int outdatedCount, int depr

if (outdatedCount > 0)
{
textSpans.Add(new InfoBarTextSpan($"{outdatedCount} {(outdatedCount == 1 ? "update" : "updates")} available"));
textSpans.Add(new InfoBarTextSpan($"{outdatedCount} {(outdatedCount == 1 ? "update" : "updates")}"));
}

if (deprecatedCount > 0)
Expand Down
113 changes: 84 additions & 29 deletions src/Services/NuGetService.cs
Original file line number Diff line number Diff line change
@@ -1,66 +1,77 @@
using NuGet.Common;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NuGet.Packaging.Core;
using PackageReference = NuGetMonitor.Models.PackageReference;
using NuGet.Configuration;
using System.IO;
using System;
using Community.VisualStudio.Toolkit;
using Settings = NuGet.Configuration.Settings;

namespace NuGetMonitor.Services
{
public static class NuGetService
{
public static async Task<IEnumerable<PackageReference>> CheckPackageReferences(IReadOnlyCollection<PackageIdentity> packageIdentities)
public static async Task<IEnumerable<PackageReference>> CheckPackageReferences(
IReadOnlyCollection<PackageIdentity> packageIdentities)
{
using var sourceCacheContext = new SourceCacheContext();

var identitiesById = packageIdentities.GroupBy(item => item.Id);

var sourceRepositories = await GetSourceRepositories().ConfigureAwait(false);

var result = await Task
.WhenAll(identitiesById.Select(identities => CheckPackageReference(identities, sourceCacheContext)))
.WhenAll(identitiesById.Select(identities => CheckPackageReference(identities, sourceCacheContext, sourceRepositories)))
.ConfigureAwait(false);

return result;
}

private static async Task<PackageReference> CheckPackageReference(IGrouping<string, PackageIdentity> packageIdentities, SourceCacheContext sourceCacheContext)
private static async Task<PackageReference> CheckPackageReference(
IGrouping<string, PackageIdentity> packageIdentities,
SourceCacheContext sourceCacheContext,
IEnumerable<SourceRepository> sourceRepositories)
{
// TODO: read source repositories from nuget.config in solution directory and check all repos
//var packageSourceProvider = new PackageSourceProvider(new Settings(_solutionDirectory));
//var sourceRepositoryProvider = new SourceRepositoryProvider(packageSourceProvider, Repository.Provider.GetCoreV3());
//var repositories = sourceRepositoryProvider.GetRepositories().ToArray();

var packageMetadataResource = await Repository.Factory
.GetCoreV3("https://api.nuget.org/v3/index.json")
.GetResourceAsync<PackageMetadataResource>()
.ConfigureAwait(false);

// use the oldest reference with the smallest version
var identity = packageIdentities.OrderBy(item => item.Version.Version).First();

var metadata = await packageMetadataResource
.GetMetadataAsync(identity, sourceCacheContext, NullLogger.Instance, CancellationToken.None)
.ConfigureAwait(false);

if (metadata == null)
foreach (var sourceRepository in sourceRepositories)
{
return new PackageReference(identity);
var packageMetadataResource = await sourceRepository
.GetResourceAsync<PackageMetadataResource>()
.ConfigureAwait(false);

var metadata = await packageMetadataResource
.GetMetadataAsync(identity, sourceCacheContext, NullLogger.Instance, CancellationToken.None)
.ConfigureAwait(false);

if (metadata == null)
{
continue;
}

return new PackageReference(identity)
{
IsVulnerable = metadata.Vulnerabilities != null,
IsDeprecated = await metadata.GetDeprecationMetadataAsync().ConfigureAwait(false) != null,
IsOutdated = await IsOutdated(identity, sourceCacheContext, sourceRepository).ConfigureAwait(false),
};
}

return new PackageReference(identity)
{
IsVulnerable = metadata.Vulnerabilities != null,
IsDeprecated = await metadata.GetDeprecationMetadataAsync().ConfigureAwait(false) != null,
IsOutdated = await IsOutdated(identity, sourceCacheContext).ConfigureAwait(false),
};
return new PackageReference(identity);
}

private static async Task<bool> IsOutdated(PackageIdentity packageIdentity, SourceCacheContext sourceCacheContext)
private static async Task<bool> IsOutdated(
PackageIdentity packageIdentity,
SourceCacheContext sourceCacheContext,
SourceRepository sourceRepository)
{
var packageResource = await Repository.Factory
.GetCoreV3("https://api.nuget.org/v3/index.json")
var packageResource = await sourceRepository
.GetResourceAsync<FindPackageByIdResource>()
.ConfigureAwait(false);

Expand All @@ -72,5 +83,49 @@ private static async Task<bool> IsOutdated(PackageIdentity packageIdentity, Sour

return latestVersion > packageIdentity.Version;
}

// https://learn.microsoft.com/en-us/nuget/consume-packages/configuring-nuget-behavior#config-file-locations-and-uses
private static async Task<IEnumerable<SourceRepository>> GetSourceRepositories()
{
var sourceRepositories = new List<SourceRepository>();

var solution = await VS.Solutions.GetCurrentSolutionAsync().ConfigureAwait(false);
var solutionNuGetConfigPath = Path.GetDirectoryName(solution.FullPath);

sourceRepositories.AddRange(GetSourceRepositories(solutionNuGetConfigPath));

var userNuGetConfigPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"NuGet");

sourceRepositories.AddRange(GetSourceRepositories(userNuGetConfigPath));

var computerNuGetConfigPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
"NuGet", "Config");

sourceRepositories.AddRange(
Directory
.EnumerateFiles(computerNuGetConfigPath, "*.Config")
.SelectMany(path => GetSourceRepositories(computerNuGetConfigPath, Path.GetFileName(path), true)));

return sourceRepositories
.GroupBy(repository => repository.PackageSource.SourceUri)
.Select(group => group.First());
}

private static IEnumerable<SourceRepository> GetSourceRepositories(
string path, string fileName = "NuGet.Config", bool isMachineWide = false)
{
if (!File.Exists(Path.Combine(path, fileName)))
{
return Enumerable.Empty<SourceRepository>();
}

var packageSourceProvider = new PackageSourceProvider(new Settings(path, fileName, isMachineWide));
var sourceRepositoryProvider = new SourceRepositoryProvider(packageSourceProvider, Repository.Provider.GetCoreV3());
var repositories = sourceRepositoryProvider.GetRepositories();
return repositories;
}
}
}

0 comments on commit 2243d20

Please sign in to comment.