Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/instructions/nuget-projects.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
applyTo: "nuget/helpers/lib/NuGetUpdater/NuGetProjects/**"
---

# NuGetProjects Maintenance

## Submodule Update Checklist

When the `NuGet.Client` submodule is updated, all `*.cs` files under `NuGetProjects/` must be re-checked against their original files in the submodule to ensure they remain largely in line with the upstream content.

## Rules for modified files

1. **No references to `NuGet.Core`.** Remove all `extern alias CoreV2` usages and any other references to the legacy `NuGet.Core` (v2) package.
2. **No .NET Framework-only APIs.** Remove or stub any APIs not compatible with .NET Core (e.g., `System.Data.Services`, WCF types, CoreV2's `PhysicalFileSystem`).
3. **Preserve behavior where possible.** When removing or stubbing, keep surrounding logic intact so the project compiles and packages.config tests pass.
4. **Document deviations.** If a file significantly diverges from upstream, add a comment at the top explaining what changed and why.
8 changes: 8 additions & 0 deletions nuget/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,12 @@ Open the solution file at `helpers/lib/NuGetUpdater/NuGetUpdater.slnx` in your p
[dependabot-core-dev] ~ $ cd nuget && rspec
```

### Known limitations

#### Projects suppressing `NU1701`

If a project explicitly includes `NU1701` in its `<NoWarn>` property, Dependabot will likely be unable to process updates for that project. The `NU1701` warning indicates that a package's target framework may not be compatible with the project's target framework, and suppressing it allows NuGet to restore packages that would otherwise be rejected.

Dependabot cannot determine why or under what circumstances ignoring target framework compatibility is safe for a given project. As a result, the final package compatibility check will fail and Dependabot will err on the side of caution and not submit a pull request.

[core-repo]: https://github.com/dependabot/dependabot-core
1 change: 0 additions & 1 deletion nuget/helpers/lib/NuGetUpdater/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

<PropertyGroup>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<NoWarn>$(NoWarn);NU1701</NoWarn>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
Expand Down
1 change: 0 additions & 1 deletion nuget/helpers/lib/NuGetUpdater/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
<PackageVersion Include="Microsoft.Web.Xdt" Version="3.2.3" />
<PackageVersion Include="MSBuild.StructuredLogger" Version="2.3.17" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="NuGet.Core" Version="2.14.0" Aliases="CoreV2" />
<PackageVersion Include="OpenTelemetry" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.15.3" />
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.15.3" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<NoWarn>$(NoWarn);CA1305</NoWarn><!-- behavior of StringBuilder could vary based on user's locale -->
<NoWarn>$(NoWarn);CA2022</NoWarn><!-- avoid inexact Stream.Read() -->
<NoWarn>$(NoWarn);NU1701</NoWarn><!-- package target framework may not be compatible -->
<NoWarn>$(NoWarn);NU1903</NoWarn><!-- package has a known high severity vulnerability -->
<NoWarn>$(NoWarn);SYSLIB0014</NoWarn><!-- obsolete -->
<NuGetSourceLocation>$(MSBuildThisFileDirectory)..\..\NuGet.Client</NuGetSourceLocation>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#nullable disable

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using NuGet.Common;
using NuGet.Credentials;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;
using NuGet.Protocol.Plugins;

namespace NuGet.CommandLine
{
public abstract class Command : ICommand
{
private const string CommandSuffix = "Command";
private CommandAttribute _commandAttribute;
private string _currentDirectory;

protected Command()
{
Arguments = new List<string>();
}

public IList<string> Arguments { get; private set; }

[Import]
public IConsole Console { get; set; }

[Import]
public HelpCommand HelpCommand { get; set; }

[Import]
public ICommandManager Manager { get; set; }

[Import]
public Configuration.IMachineWideSettings MachineWideSettings { get; set; }

[Option(typeof(NuGetCommand), "Option_Help", AltName = "?")]
public bool Help { get; set; }

[Option(typeof(NuGetCommand), "Option_Verbosity")]
public Verbosity Verbosity { get; set; }

[Option(typeof(NuGetCommand), "Option_NonInteractive")]
public bool NonInteractive { get; set; }

[Option(typeof(NuGetCommand), "Option_ConfigFile")]
public string ConfigFile { get; set; }

[Option(typeof(NuGetCommand), "Option_ForceEnglishOutput")]
public bool ForceEnglishOutput { get; set; }

protected Configuration.ICredentialService CredentialService { get; private set; }

public DeprecatedCommandAttribute DeprecatedCommandAttribute
{
get
{
var deprecatedAttrs = GetType().GetCustomAttributes(typeof(DeprecatedCommandAttribute), false);

if (deprecatedAttrs.Length > 0)
{
return deprecatedAttrs[0] as DeprecatedCommandAttribute;
}

return null;
}
}

public string CurrentDirectory
{
get
{
return _currentDirectory ?? Directory.GetCurrentDirectory();
}
set
{
_currentDirectory = value;
}
}

protected internal Configuration.ISettings Settings { get; set; }

protected internal Configuration.IPackageSourceProvider SourceProvider { get; set; }

private Lazy<MsBuildToolset> MsBuildToolset
{
get
{
if (_defaultMsBuildToolset == null)
{
_defaultMsBuildToolset = MsBuildUtility.GetMsBuildDirectoryFromMsBuildPath(null, null, Console);

}
return _defaultMsBuildToolset;
}
}

private Lazy<MsBuildToolset> _defaultMsBuildToolset;

public CommandAttribute CommandAttribute
{
get
{
if (_commandAttribute == null)
{
_commandAttribute = GetCommandAttribute();
}
return _commandAttribute;
}
}

public virtual bool IncludedInHelp(string optionName)
{
return true;
}

public void Execute()
{
if (Help)
{
if (DeprecatedCommandAttribute != null)
{
var deprecationMessage = DeprecatedCommandAttribute.GetDeprecationMessage(CommandAttribute.CommandName);
Console.WriteWarning(deprecationMessage);
}

HelpCommand.ViewHelpForCommand(CommandAttribute.CommandName);
}
else
{
if (string.IsNullOrEmpty(ConfigFile))
{
string configFileName = null;

var packCommand = this as PackCommand;
if (packCommand != null && !string.IsNullOrEmpty(packCommand.ConfigFile))
{
configFileName = packCommand.ConfigFile;
}

Settings = Configuration.Settings.LoadDefaultSettings(
CurrentDirectory,
configFileName: configFileName,
machineWideSettings: MachineWideSettings);
}
else
{
var configFileFullPath = Path.GetFullPath(ConfigFile);
var directory = Path.GetDirectoryName(configFileFullPath);
var configFileName = Path.GetFileName(configFileFullPath);
Settings = Configuration.Settings.LoadDefaultSettings(
directory,
configFileName,
MachineWideSettings);
}

SourceProvider = PackageSourceBuilder.CreateSourceProvider(Settings);

SetDefaultCredentialProvider();

UserAgent.SetUserAgentString(new UserAgentStringBuilder(CommandLineConstants.UserAgent));

if (DeprecatedCommandAttribute != null)
{
var deprecationMessage = DeprecatedCommandAttribute.GetDeprecationMessage(CommandAttribute.CommandName);
Console.WriteWarning(deprecationMessage);
}

OutputNuGetVersion();
ExecuteCommandAsync().GetAwaiter().GetResult();
}
}

/// <summary>
/// Outputs the current NuGet version (by default, only when vebosity is detailed).
/// </summary>
private void OutputNuGetVersion()
{
if (ShouldOutputNuGetVersion)
{
var assemblyName = typeof(Command).Assembly.GetName();
var assemblyLocation = typeof(Command).Assembly.Location;
var version = System.Diagnostics.FileVersionInfo.GetVersionInfo(assemblyLocation).FileVersion;
var message = string.Format(
CultureInfo.CurrentCulture,
LocalizedResourceManager.GetString("OutputNuGetVersion"),
assemblyName.Name,
version);
Console.WriteLine(message);
}
}

protected virtual bool ShouldOutputNuGetVersion
{
get { return Console.Verbosity == Verbosity.Detailed; }
}

protected virtual void SetDefaultCredentialProvider()
{
SetDefaultCredentialProvider(MsBuildToolset);
}

/// <summary>
/// Set default credential provider for the HttpClient, which is used by V2 sources.
/// Also set up authenticated proxy handling for V3 sources.
/// </summary>
protected void SetDefaultCredentialProvider(Lazy<MsBuildToolset> msbuildDirectory)
{
PluginDiscoveryUtility.InternalPluginDiscoveryRoot = new Lazy<string>(() => PluginDiscoveryUtility.GetInternalPluginRelativeToMSBuildDirectory(msbuildDirectory.Value.Path));
CredentialService = new CredentialService(new AsyncLazy<IEnumerable<ICredentialProvider>>(() => GetCredentialProvidersAsync()), NonInteractive, handlesDefaultCredentials: PreviewFeatureSettings.DefaultCredentialsAfterCredentialProviders);

HttpHandlerResourceV3.CredentialService = new Lazy<Configuration.ICredentialService>(() => CredentialService);

HttpHandlerResourceV3.CredentialsSuccessfullyUsed = (uri, credentials) =>
{
};
}

private async Task<IEnumerable<ICredentialProvider>> GetCredentialProvidersAsync()
{
var extensionLocator = new ExtensionLocator();
var providers = new List<ICredentialProvider>();
var pluginProviders = new PluginCredentialProviderBuilder(extensionLocator, Settings, Console)
.BuildAll(Verbosity.ToString())
.ToList();
var securePluginProviders = await (new SecurePluginCredentialProviderBuilder(PluginManager.Instance, canShowDialog: true, logger: Console)).BuildAllAsync();

providers.Add(new SettingsCredentialProvider(SourceProvider, Console));
providers.AddRange(securePluginProviders);
providers.AddRange(pluginProviders);

if (pluginProviders.Any() || securePluginProviders.Any())
{
if (PreviewFeatureSettings.DefaultCredentialsAfterCredentialProviders)
{
providers.Add(new DefaultNetworkCredentialsCredentialProvider());
}
}
providers.Add(new ConsoleCredentialProvider(Console));

return providers;
}

public virtual Task ExecuteCommandAsync()
{
ExecuteCommand();
return Task.CompletedTask;
}

public virtual void ExecuteCommand()
{
}

[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This method does quite a bit of processing.")]
public virtual CommandAttribute GetCommandAttribute()
{
var type = GetType();
var attributes = type.GetCustomAttributes(typeof(CommandAttribute), true);
var attribute = attributes.FirstOrDefault();
if (attribute != null)
{
return (CommandAttribute)attribute;
}

// Use the command name minus the suffix if present and default description
var name = type.Name;
var idx = name.LastIndexOf(CommandSuffix, StringComparison.OrdinalIgnoreCase);
if (idx >= 0)
{
name = name.Substring(0, idx);
}
if (!string.IsNullOrEmpty(name))
{
return new CommandAttribute(name, LocalizedResourceManager.GetString("DefaultCommandDescription"));
}
return null;
}
}
}
Loading
Loading