diff --git a/src/NuGet.Core/NuGet.Build.Tasks.Pack/IPackTaskRequest.cs b/src/NuGet.Core/NuGet.Build.Tasks.Pack/IPackTaskRequest.cs index 0e79f0a40d6..c162b28084b 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks.Pack/IPackTaskRequest.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks.Pack/IPackTaskRequest.cs @@ -78,5 +78,7 @@ public interface IPackTaskRequest bool Deterministic { get; } string DeterministicTimestamp { get; } string PackageIcon { get; } + string SdkAnalysisLevel { get; } + string UsingMicrosoftNETSdk { get; } } } diff --git a/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTask.cs b/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTask.cs index b18935acb2a..7a4197ff4ad 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTask.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTask.cs @@ -94,6 +94,8 @@ internal PackTask(IEnvironmentVariableReader environmentVariableReader) public bool Deterministic { get; set; } public string DeterministicTimestamp { get; set; } public string PackageIcon { get; set; } + public string SdkAnalysisLevel { get; set; } + public string UsingMicrosoftNETSdk { get; set; } public ILogger Logger => new MSBuildLogger(Log); private IPackTaskLogic _packTaskLogic; @@ -228,6 +230,8 @@ private IPackTaskRequest GetRequest() Deterministic = Deterministic, DeterministicTimestamp = MSBuildStringUtility.TrimAndGetNullForEmpty(DeterministicTimestamp), PackageIcon = MSBuildStringUtility.TrimAndGetNullForEmpty(PackageIcon), + SdkAnalysisLevel = MSBuildStringUtility.TrimAndGetNullForEmpty(SdkAnalysisLevel), + UsingMicrosoftNETSdk = MSBuildStringUtility.TrimAndGetNullForEmpty(UsingMicrosoftNETSdk), }; } } diff --git a/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTaskLogic.cs b/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTaskLogic.cs index df302f197cf..4695159bf05 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTaskLogic.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTaskLogic.cs @@ -45,6 +45,8 @@ public PackArgs GetPackArgs(IPackTaskRequest request) Deterministic = request.Deterministic, DeterministicTimestamp = request.DeterministicTimestamp, WarningProperties = WarningProperties.GetWarningProperties(request.TreatWarningsAsErrors, request.WarningsAsErrors, request.NoWarn, request.WarningsNotAsErrors), + SdkAnalysisLevel = MSBuildRestoreUtility.GetSdkAnalysisLevel(request.SdkAnalysisLevel), + UsingMicrosoftNETSdk = MSBuildRestoreUtility.GetUsingMicrosoftNETSdk(request.UsingMicrosoftNETSdk), PackTargetArgs = new MSBuildPackTargetArgs() }; diff --git a/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTaskRequest.cs b/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTaskRequest.cs index a418b666ef6..cb868838e65 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTaskRequest.cs +++ b/src/NuGet.Core/NuGet.Build.Tasks.Pack/PackTaskRequest.cs @@ -73,5 +73,7 @@ public class PackTaskRequest : IPackTaskRequest public bool Deterministic { get; set; } public string DeterministicTimestamp { get; set; } public string PackageIcon { get; set; } + public string SdkAnalysisLevel { get; set; } + public string UsingMicrosoftNETSdk { get; set; } } } diff --git a/src/NuGet.Core/NuGet.Build.Tasks/NuGet.Build.Tasks.Pack.targets b/src/NuGet.Core/NuGet.Build.Tasks/NuGet.Build.Tasks.Pack.targets index 18c8ae815fe..286bba8f09a 100644 --- a/src/NuGet.Core/NuGet.Build.Tasks/NuGet.Build.Tasks.Pack.targets +++ b/src/NuGet.Core/NuGet.Build.Tasks/NuGet.Build.Tasks.Pack.targets @@ -285,6 +285,8 @@ Copyright (c) .NET Foundation. All rights reserved. Deterministic="$(Deterministic)" DeterministicTimestamp="$(DeterministicTimestamp)" PackageIcon="$(PackageIcon)" + SdkAnalysisLevel="$(SdkAnalysisLevel)" + UsingMicrosoftNETSdk="$(UsingMicrosoftNETSdk)" /> diff --git a/src/NuGet.Core/NuGet.Commands/CommandArgs/PackArgs.cs b/src/NuGet.Core/NuGet.Commands/CommandArgs/PackArgs.cs index 08121dcdfc8..b68f5246845 100644 --- a/src/NuGet.Core/NuGet.Commands/CommandArgs/PackArgs.cs +++ b/src/NuGet.Core/NuGet.Commands/CommandArgs/PackArgs.cs @@ -11,6 +11,7 @@ using NuGet.Configuration; using NuGet.Packaging; using NuGet.ProjectModel; +using NuGet.Versioning; namespace NuGet.Commands { @@ -47,6 +48,8 @@ public class PackArgs public bool Deterministic { get; set; } public string DeterministicTimestamp { get; set; } public WarningProperties WarningProperties { get; set; } + public NuGetVersion SdkAnalysisLevel { get; set; } + public bool UsingMicrosoftNETSdk { get; set; } public MSBuildPackTargetArgs PackTargetArgs { get; set; } public Dictionary Properties { diff --git a/src/NuGet.Core/NuGet.Commands/CommandRunners/PackCommandRunner.cs b/src/NuGet.Core/NuGet.Commands/CommandRunners/PackCommandRunner.cs index 06fe2ab03d3..4c20e260f3a 100644 --- a/src/NuGet.Core/NuGet.Commands/CommandRunners/PackCommandRunner.cs +++ b/src/NuGet.Core/NuGet.Commands/CommandRunners/PackCommandRunner.cs @@ -116,6 +116,18 @@ private bool BuildPackage(PackageBuilder builder, string outputPath = null, bool outputPath = outputPath ?? GetOutputPath(builder, _packArgs, false, builder.Version); Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); + // Warn if the package ID doesn't adhere to the restricted character set (NU5052) + if (!symbolsPackage && + _packArgs.UsingMicrosoftNETSdk && + SdkAnalysisLevelMinimums.IsEnabled(_packArgs.SdkAnalysisLevel, _packArgs.UsingMicrosoftNETSdk, SdkAnalysisLevelMinimums.V11_0_100) && + !PackageIdValidator.IsValidPackageId(builder.Id, useRestrictedCharacterSet: true)) + { + _packArgs.Logger.Log( + PackagingLogMessage.CreateWarning( + string.Format(CultureInfo.CurrentCulture, Strings.RestrictedPackageIdWarning, builder.Id), + NuGetLogCode.NU5052)); + } + // Track if the package file was already present on disk bool isExistingPackage = File.Exists(outputPath); try diff --git a/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Unshipped.txt index 786336e2d51..5104c49f60b 100644 --- a/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.Commands/PublicAPI/net472/PublicAPI.Unshipped.txt @@ -1,6 +1,10 @@ #nullable enable ~NuGet.Commands.PackArgs.DeterministicTimestamp.get -> string ~NuGet.Commands.PackArgs.DeterministicTimestamp.set -> void +~NuGet.Commands.PackArgs.SdkAnalysisLevel.get -> NuGet.Versioning.NuGetVersion +~NuGet.Commands.PackArgs.SdkAnalysisLevel.set -> void +NuGet.Commands.PackArgs.UsingMicrosoftNETSdk.get -> bool +NuGet.Commands.PackArgs.UsingMicrosoftNETSdk.set -> void const NuGet.Commands.Restore.Utility.PackageSpecFactory.EnvironmentVariableName = "NUGET_USE_NEW_PACKAGESPEC_FACTORY" -> string! NuGet.Commands.Restore.IProject.GetGlobalProperty(string! propertyName) -> string? ~static NuGet.Commands.MSBuildRestoreUtility.GetDependencySpec(System.Collections.Generic.IEnumerable items, bool readOnly, bool collectAdditionalMessages) -> (NuGet.ProjectModel.DependencyGraphSpec, System.Collections.Generic.IReadOnlyList) diff --git a/src/NuGet.Core/NuGet.Commands/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.Commands/PublicAPI/net8.0/PublicAPI.Unshipped.txt index 786336e2d51..5104c49f60b 100644 --- a/src/NuGet.Core/NuGet.Commands/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.Commands/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -1,6 +1,10 @@ #nullable enable ~NuGet.Commands.PackArgs.DeterministicTimestamp.get -> string ~NuGet.Commands.PackArgs.DeterministicTimestamp.set -> void +~NuGet.Commands.PackArgs.SdkAnalysisLevel.get -> NuGet.Versioning.NuGetVersion +~NuGet.Commands.PackArgs.SdkAnalysisLevel.set -> void +NuGet.Commands.PackArgs.UsingMicrosoftNETSdk.get -> bool +NuGet.Commands.PackArgs.UsingMicrosoftNETSdk.set -> void const NuGet.Commands.Restore.Utility.PackageSpecFactory.EnvironmentVariableName = "NUGET_USE_NEW_PACKAGESPEC_FACTORY" -> string! NuGet.Commands.Restore.IProject.GetGlobalProperty(string! propertyName) -> string? ~static NuGet.Commands.MSBuildRestoreUtility.GetDependencySpec(System.Collections.Generic.IEnumerable items, bool readOnly, bool collectAdditionalMessages) -> (NuGet.ProjectModel.DependencyGraphSpec, System.Collections.Generic.IReadOnlyList) diff --git a/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs b/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs index 03bfa2d9916..c7325d52114 100644 --- a/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs +++ b/src/NuGet.Core/NuGet.Commands/Strings.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -1241,6 +1241,15 @@ internal static string Log_AliasContainsDisallowedCharacters { } } + /// + /// Looks up a localized string similar to The package ID '{0}' does not adhere to the restricted set of characters allowed in package IDs. Package IDs must start with a letter, digit, or underscore and contain only ASCII letters, digits, dots (.), and dashes (-) with no consecutive dots or dashes. Rename the package to use only characters from the restricted set.. + /// + internal static string RestrictedPackageIdWarning { + get { + return ResourceManager.GetString("RestrictedPackageIdWarning", resourceCulture); + } + } + /// /// Looks up a localized string similar to All projects are up-to-date for restore.. /// diff --git a/src/NuGet.Core/NuGet.Commands/Strings.resx b/src/NuGet.Core/NuGet.Commands/Strings.resx index a46be8b5252..087eea15fde 100644 --- a/src/NuGet.Core/NuGet.Commands/Strings.resx +++ b/src/NuGet.Core/NuGet.Commands/Strings.resx @@ -1190,4 +1190,7 @@ Upgrade your .NET SDK or remove RestoreUseLegacyDependencyResolver to use this f The project {0} contains a TargetFramework '{1}' with disallowed characters. TargetFramework names must contain only ASCII characters and must not contain path separators. + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + diff --git a/src/NuGet.Core/NuGet.Commands/Utility/SdkAnalysisLevelMinimums.cs b/src/NuGet.Core/NuGet.Commands/Utility/SdkAnalysisLevelMinimums.cs index 1830f5f9c24..915725b9ace 100644 --- a/src/NuGet.Core/NuGet.Commands/Utility/SdkAnalysisLevelMinimums.cs +++ b/src/NuGet.Core/NuGet.Commands/Utility/SdkAnalysisLevelMinimums.cs @@ -39,6 +39,7 @@ internal static class SdkAnalysisLevelMinimums /// /// warning when packages use the deprecated MonoAndroid framework /// error when TargetFramework alias contains non-ASCII characters + /// warning when package ID does not adhere to the restricted character set (NU5052) /// /// internal static readonly NuGetVersion V11_0_100 = new("11.0.100"); diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.cs.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.cs.xlf index dcba000dc5b..00a21d58555 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.cs.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.cs.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Upgradujte svou sadu .NET SDK nebo odeberte RestoreUseLegacyDependencyResolver, Vyřazuje se balíček {0} jako závislost {1}. Maximální verze, která se dá vyřadit, je {2}. 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference Soubor certifikátu {0} se nenašel. Seznam přijatelných způsobů, jak poskytnout certifikát, najdete tady: https://docs.nuget.org/docs/reference/command-line-reference diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.de.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.de.xlf index 001771b30eb..33bd44551de 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.de.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.de.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Aktualisieren Sie Ihr .NET SDK oder entfernen Sie RestoreUseLegacyDependencyReso Das Paket „{0}“ wird als Abhängigkeit von „{1}“ gekürzt. Die maximal kürzbare Version ist „{2}“. 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference Die Zertifikatdatei "{0}" wurde nicht gefunden. Eine Liste der anerkannten Methoden zur Bereitstellung eines Zertifikats finden Sie unter https://docs.nuget.org/docs/reference/command-line-reference. diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.es.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.es.xlf index 599f169e127..087d425583a 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.es.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.es.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Actualice el SDK de .NET o quite RestoreUseLegacyDependencyResolver para usar es Eliminando el paquete '{0}' como una dependencia de '{1}'. La versión máxima que se puede eliminar es '{2}' 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference No se encontró el archivo de certificado "{0}". Para obtener una lista de las formas aceptadas de proporcionar un certificado, visite https://docs.nuget.org/docs/reference/command-line-reference diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.fr.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.fr.xlf index ba8bcd2a635..f810425ea37 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.fr.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.fr.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Mettez à niveau votre Kit de développement logiciel (SDK) .NET ou supprimez Re Nettoyage du package « {0} » en tant que dépendance de « {1} ». La version maximale pouvant être nettoyée est « {2} » 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference Le fichier de certificat '{0}' est introuvable. Pour obtenir la liste des méthodes acceptées d'émission de certificats, accédez à https://docs.nuget.org/docs/reference/command-line-reference diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.it.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.it.xlf index 1d7251d6fe0..759ddba09e5 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.it.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.it.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Per usare questa funzionalità, aggiornare .NET SDK o rimuovere RestoreUseLegacy Rimozione del pacchetto '{0}' come dipendenza di '{1}'. La versione massima rimovibile è '{2}' 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference Il file di certificato '{0}' non è stato trovato. Per un elenco dei modi accettati per specificare un certificato, vedere https://docs.nuget.org/docs/reference/command-line-reference diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.ja.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.ja.xlf index 88192b0cf42..8c1d789e2d0 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.ja.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.ja.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Upgrade your .NET SDK or remove RestoreUseLegacyDependencyResolver to use this f パッケージ '{0}' を '{1}' の依存関係として取り除いています。取り除きが可能な最大バージョンは '{2}' です 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference 証明書ファイル '{0}' は見つかりませんでした。証明書を提供する承認済みの方法のリストについて、https://docs.nuget.org/docs/reference/command-line-reference をご覧ください diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.ko.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.ko.xlf index d9804d0ebb3..a662168288f 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.ko.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.ko.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Upgrade your .NET SDK or remove RestoreUseLegacyDependencyResolver to use this f 패키지 '{0}'을(를) '{1}'의 종속성으로 잘라내는 중입니다. 잘라내기 가능한 최대 버전은 '{2}'입니다. 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference 인증서 파일 '{0}'을(를) 찾을 수 없습니다. 인증서를 제공하는 허용된 방법 목록은 https://docs.nuget.org/docs/reference/command-line-reference를 참조하세요. diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.pl.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.pl.xlf index 14c268f5ebd..db6be2a2124 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.pl.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.pl.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Uaktualnij zestaw .NET SDK lub usuń RestoreUseLegacyDependencyResolver, aby kor Oczyszczanie pakietu „{0}” jako zależności „{1}”. Maksymalna wersja możliwa do oczyszczenia to „{2}” 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference Nie odnaleziono pliku certyfikatu „{0}”. Aby uzyskać listę akceptowanych sposobów dostarczenia certyfikatu, odwiedź stronę https://docs.nuget.org/docs/reference/command-line-reference diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.pt-BR.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.pt-BR.xlf index 560055ef5c4..ec4782a5cfb 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.pt-BR.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.pt-BR.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Atualize o SDK do .NET ou remova RestoreUseLegacyDependencyResolver para usar es Podando o pacote '{0}' como dependência de '{1}'. A versão máxima que pode ser removida é '{2}' 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference O arquivo de certificado '{0}' não foi encontrado. Para obter uma lista das maneiras aceitas de fornecimento de certificado, visite https://docs.nuget.org/docs/reference/command-line-reference diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.ru.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.ru.xlf index fba35e46239..ac891760d3d 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.ru.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.ru.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Upgrade your .NET SDK or remove RestoreUseLegacyDependencyResolver to use this f Урезание пакета "{0}" как зависимости "{1}". Максимальная версия, которую можно урезать: "{2}" 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference Файл сертификата "{0}" не найден. Допустимые способы предоставления сертификатов см. на странице https://docs.nuget.org/docs/reference/command-line-reference. diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.tr.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.tr.xlf index 35d5461da00..36c6f023652 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.tr.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.tr.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Bu özelliği kullanmak için .NET SDK'nizi yükseltin veya RestoreUseLegacyDepe ‘{0}’ paketini ‘{1}’ bağımlılığı olarak ayıklama. Maksimum ayıklanabilir sürüm ‘{2}’ 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference '{0}' sertifika dosyası bulunamadı. Kabul edilen sertifika sağlama yollarının listesi için bkz. https://docs.nuget.org/docs/reference/command-line-reference diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.zh-Hans.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.zh-Hans.xlf index 94971dc34d1..a540e8482b7 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.zh-Hans.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Upgrade your .NET SDK or remove RestoreUseLegacyDependencyResolver to use this f 正在将包 "{0}" 作为 "{1}" 的依赖项进行删除。最大可删除版本为 "{2}" 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference 找不到文件“{0}”。要获取接受的证书提供方式列表,请访问 https://docs.nuget.org/docs/reference/command-line-reference diff --git a/src/NuGet.Core/NuGet.Commands/xlf/Strings.zh-Hant.xlf b/src/NuGet.Core/NuGet.Commands/xlf/Strings.zh-Hant.xlf index 913efa38769..8c35bd57622 100644 --- a/src/NuGet.Core/NuGet.Commands/xlf/Strings.zh-Hant.xlf +++ b/src/NuGet.Core/NuGet.Commands/xlf/Strings.zh-Hant.xlf @@ -1,4 +1,4 @@ - + @@ -1113,6 +1113,11 @@ Upgrade your .NET SDK or remove RestoreUseLegacyDependencyResolver to use this f 修剪套件「{0}」作為「{1}」的相依性。最大可修剪版本為「{2}」 0 - package id and version, 1 - version + + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + The package ID '{0}' is invalid. Package IDs must start with a letter, digit, or underscore, and contain only ASCII letters, digits, dots (.), dashes (-), and underscores (_), with no consecutive dots or dashes. + + Certificate file '{0}' not found. For a list of accepted ways to provide a certificate, visit https://docs.nuget.org/docs/reference/command-line-reference 找不到憑證檔案 '{0}'。如需可接受的憑證提供方法清單,請前往 https://docs.microsoft.com/zh-tw/nuget/reference/nuget-exe-cli-reference diff --git a/src/NuGet.Core/NuGet.Common/Errors/NuGetLogCode.cs b/src/NuGet.Core/NuGet.Common/Errors/NuGetLogCode.cs index c65186b59d3..ad54e97c634 100644 --- a/src/NuGet.Core/NuGet.Common/Errors/NuGetLogCode.cs +++ b/src/NuGet.Core/NuGet.Common/Errors/NuGetLogCode.cs @@ -908,6 +908,11 @@ public enum NuGetLogCode /// NU5051 = 5051, + /// + /// Package ID does not adhere to the restricted set of characters + /// + NU5052 = 5052, + /// /// AssemblyOutsideLibWarning /// diff --git a/src/NuGet.Core/NuGet.Common/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.Common/PublicAPI.Unshipped.txt index 479ec93463f..e77c59ee2ea 100644 --- a/src/NuGet.Core/NuGet.Common/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.Common/PublicAPI.Unshipped.txt @@ -1,3 +1,4 @@ #nullable enable NuGet.Common.NuGetLogCode.NU1512 = 1512 -> NuGet.Common.NuGetLogCode +NuGet.Common.NuGetLogCode.NU5052 = 5052 -> NuGet.Common.NuGetLogCode NuGet.Common.NuGetLogCode.NU5502 = 5502 -> NuGet.Common.NuGetLogCode diff --git a/src/NuGet.Core/NuGet.Packaging/PackageCreation/Utility/PackageIdValidator.cs b/src/NuGet.Core/NuGet.Packaging/PackageCreation/Utility/PackageIdValidator.cs index 486fc9b3772..86aaece2d55 100644 --- a/src/NuGet.Core/NuGet.Packaging/PackageCreation/Utility/PackageIdValidator.cs +++ b/src/NuGet.Core/NuGet.Packaging/PackageCreation/Utility/PackageIdValidator.cs @@ -28,6 +28,26 @@ public static bool IsValidPackageId(string packageId) return IdRegex.IsMatch(packageId); } + /// + /// Validates the package ID. When is true, + /// additionally checks that the ID contains only ASCII letters, digits, dots, dashes, and underscores, + /// with no consecutive dots or dashes, and is 100 characters or less. + /// + public static bool IsValidPackageId(string packageId, bool useRestrictedCharacterSet) + { + if (!IsValidPackageId(packageId)) + { + return false; + } + + if (useRestrictedCharacterSet) + { + return IsRestrictedId(packageId); + } + + return true; + } + public static void ValidatePackageId(string packageId) { if (packageId.Length > MaxPackageIdLength) @@ -40,5 +60,43 @@ public static void ValidatePackageId(string packageId) throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, NuGetResources.InvalidPackageId, packageId)); } } + + private static bool IsRestrictedId(string packageId) + { + static bool IsAsciiLetterOrDigit(char c) + { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'); + } + + if (packageId.Length == 0 || packageId.Length > MaxPackageIdLength) + { + return false; + } + + char first = packageId[0]; + if (!IsAsciiLetterOrDigit(first) && first != '_') + { + return false; + } + + char prev = first; + for (int i = 1; i < packageId.Length; i++) + { + char c = packageId[i]; + if (!IsAsciiLetterOrDigit(c) && c != '.' && c != '-' && c != '_') + { + return false; + } + + if ((c == '.' || c == '-') && (prev == '.' || prev == '-')) + { + return false; + } + + prev = c; + } + + return true; + } } } diff --git a/src/NuGet.Core/NuGet.Packaging/PublicAPI/net472/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.Packaging/PublicAPI/net472/PublicAPI.Unshipped.txt index f130df65afa..a57f2f04705 100644 --- a/src/NuGet.Core/NuGet.Packaging/PublicAPI/net472/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.Packaging/PublicAPI/net472/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ #nullable enable NuGet.Packaging.PackageBuilder.DeterministicTimestamp.init -> void +static NuGet.Packaging.PackageIdValidator.IsValidPackageId(string! packageId, bool useRestrictedCharacterSet) -> bool diff --git a/src/NuGet.Core/NuGet.Packaging/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/src/NuGet.Core/NuGet.Packaging/PublicAPI/net8.0/PublicAPI.Unshipped.txt index f130df65afa..a57f2f04705 100644 --- a/src/NuGet.Core/NuGet.Packaging/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/src/NuGet.Core/NuGet.Packaging/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -1,2 +1,3 @@ #nullable enable NuGet.Packaging.PackageBuilder.DeterministicTimestamp.init -> void +static NuGet.Packaging.PackageIdValidator.IsValidPackageId(string! packageId, bool useRestrictedCharacterSet) -> bool diff --git a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs index bce994b52ad..80954dd7523 100644 --- a/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs +++ b/test/NuGet.Core.FuncTests/Dotnet.Integration.Test/PackCommandTests.cs @@ -6663,5 +6663,32 @@ private void SetupAliasedFrameworkProject( ProjectFileUtils.WriteXmlToFile(xml, stream); } + + [PlatformFact(Platform.Windows)] + public void PackCommand_PackageIdWithNonAsciiCharacters_NU5052() + { + using var testDirectory = _dotnetFixture.CreateTestDirectory(); + var projectName = "ClassLibrary1"; + var workingDirectory = Path.Combine(testDirectory, projectName); + + _dotnetFixture.CreateDotnetNewProject(testDirectory.Path, projectName, " classlib", testOutputHelper: _testOutputHelper); + var projectFile = Path.Combine(workingDirectory, $"{projectName}.csproj"); + + using (var stream = new FileStream(projectFile, FileMode.Open, FileAccess.ReadWrite)) + { + var xml = XDocument.Load(stream); + ProjectFileUtils.AddProperty(xml, "PackageId", "Contöso.Utilities"); + ProjectFileUtils.WriteXmlToFile(xml, stream); + } + + _dotnetFixture.RestoreProjectExpectSuccess(workingDirectory, projectName, testOutputHelper: _testOutputHelper); + var result = _dotnetFixture.PackProjectExpectSuccess(workingDirectory, projectName, $"-o {workingDirectory}", testOutputHelper: _testOutputHelper); + +#if SDK_NEXT + result.AllOutput.Should().Contain("NU5052"); +#else + result.AllOutput.Should().NotContain("NU5052"); +#endif + } } } diff --git a/test/NuGet.Core.Tests/NuGet.Commands.Test/PackCommandRunnerTests.cs b/test/NuGet.Core.Tests/NuGet.Commands.Test/PackCommandRunnerTests.cs index 1bb04d2d52b..a91f639329f 100644 --- a/test/NuGet.Core.Tests/NuGet.Commands.Test/PackCommandRunnerTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Commands.Test/PackCommandRunnerTests.cs @@ -9,6 +9,7 @@ using FluentAssertions; using NuGet.Common; using NuGet.Packaging; +using NuGet.ProjectModel; using NuGet.Test.Utility; using NuGet.Versioning; using Xunit; @@ -258,5 +259,146 @@ public void Dispose() _testDirectory.Dispose(); } } + + [Theory] + [InlineData("Contöso.Utilities", "11.0.100", true, true)] // non-ASCII ö, enabled → emits + [InlineData("\u0421ontoso.Utilities", "11.0.100", true, true)] // Cyrillic С, enabled → emits + [InlineData("Contöso.Utilities", "10.0.100", true, false)] // below threshold → suppressed + [InlineData("Contöso.Utilities", null, false, false)] // non-SDK project (nuget.exe) → not emitted (SDK-only warning) + [InlineData("Contöso.Utilities", null, true, false)] // SDK project, no level (assumes 8.0.400) → suppressed + public void BuildPackage_PackageIdWithInvalidCharacters_EmitsNU5052_BasedOnSdkAnalysisLevel(string packageId, string? sdkAnalysisLevel, bool usingMicrosoftNETSdk, bool expectWarning) + { + using (var testDirectory = TestDirectory.Create()) + { + // Arrange + var nuspecPath = Path.Combine(testDirectory.Path, "test.nuspec"); + File.WriteAllText(nuspecPath, $@" + + + {packageId} + 1.0.0 + test + test + + + + +"); + + var logger = new TestLogger(); + var args = new PackArgs() + { + CurrentDirectory = testDirectory.Path, + Exclude = Enumerable.Empty(), + Logger = new PackCollectorLogger(logger, new WarningProperties()), + Path = nuspecPath, + SdkAnalysisLevel = sdkAnalysisLevel != null ? new NuGetVersion(sdkAnalysisLevel) : null, + UsingMicrosoftNETSdk = usingMicrosoftNETSdk, + }; + var runner = new PackCommandRunner(args, createProjectFactory: null); + + // Act + runner.RunPackageBuild(); + + // Assert + if (expectWarning) + { + logger.WarningMessages.Should().Contain(m => m.Contains("NU5052")); + } + else + { + logger.WarningMessages.Should().NotContain(m => m.Contains("NU5052")); + } + } + } + + [Fact] + public void BuildPackage_PackageIdWithInvalidCharacters_NoWarnSuppressesNU5052() + { + using (var testDirectory = TestDirectory.Create()) + { + // Arrange + string packageId = "Contöso.Utilities"; + var nuspecPath = Path.Combine(testDirectory.Path, "test.nuspec"); + File.WriteAllText(nuspecPath, $@" + + + {packageId} + 1.0.0 + test + test + + + + +"); + + var warningProperties = new WarningProperties(); + warningProperties.NoWarn.Add(NuGetLogCode.NU5052); + + var logger = new TestLogger(); + var args = new PackArgs() + { + CurrentDirectory = testDirectory.Path, + Exclude = Enumerable.Empty(), + Logger = new PackCollectorLogger(logger, warningProperties), + Path = nuspecPath, + SdkAnalysisLevel = new NuGetVersion("11.0.100"), + UsingMicrosoftNETSdk = true, + }; + var runner = new PackCommandRunner(args, createProjectFactory: null); + + // Act + runner.RunPackageBuild(); + + // Assert + logger.WarningMessages.Should().NotContain(m => m.Contains("NU5052")); + } + } + + [Fact] + public void BuildPackage_PackageIdWithInvalidCharacters_TreatWarningsAsErrors_RaisesNU5052AsError() + { + using (var testDirectory = TestDirectory.Create()) + { + // Arrange + string packageId = "Contöso.Utilities"; + var nuspecPath = Path.Combine(testDirectory.Path, "test.nuspec"); + File.WriteAllText(nuspecPath, $@" + + + {packageId} + 1.0.0 + test + test + + + + +"); + + var warningProperties = new WarningProperties(); + warningProperties.AllWarningsAsErrors = true; + + var logger = new TestLogger(); + var args = new PackArgs() + { + CurrentDirectory = testDirectory.Path, + Exclude = Enumerable.Empty(), + Logger = new PackCollectorLogger(logger, warningProperties), + Path = nuspecPath, + SdkAnalysisLevel = new NuGetVersion("11.0.100"), + UsingMicrosoftNETSdk = true, + }; + var runner = new PackCommandRunner(args, createProjectFactory: null); + + // Act + runner.RunPackageBuild(); + + // Assert - warning is upgraded to error + logger.ErrorMessages.Should().Contain(m => m.Contains("NU5052")); + logger.WarningMessages.Should().NotContain(m => m.Contains("NU5052")); + } + } } } diff --git a/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageIdValidatorTest.cs b/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageIdValidatorTest.cs index 8fa66e638f5..b2066c935cf 100644 --- a/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageIdValidatorTest.cs +++ b/test/NuGet.Core.Tests/NuGet.Packaging.Test/PackageIdValidatorTest.cs @@ -201,5 +201,64 @@ public void IdExceedingMaxLengthThrows(int idTestLength) () => PackageIdValidator.ValidatePackageId(packageId), "Id must not exceed 100 characters."); } + + [Theory] + [InlineData("Contoso.Utilities")] + [InlineData("My.Package-1.0")] + [InlineData("A")] + [InlineData("_internal")] + [InlineData("1.2.3")] + [InlineData("NuGet.Core")] + [InlineData("Microsoft.Extensions.Logging")] + public void IsValidPackageId_Restricted_ValidIds_ReturnsTrue(string packageId) + { + // Act + bool result = PackageIdValidator.IsValidPackageId(packageId, useRestrictedCharacterSet: true); + + // Assert + Assert.True(result, $"Expected '{packageId}' to be a valid restricted package ID."); + } + + [Theory] + [InlineData("Contöso.Utilities")] // non-ASCII ö + [InlineData("Contoso.Ütil")] // non-ASCII Ü + [InlineData("\u0421ontoso.Utilities")] // Cyrillic С homoglyph + [InlineData("Paquet.Français")] // non-ASCII ç + [InlineData("Paquete.Español")] // non-ASCII ñ + [InlineData("パッケージ")] // Japanese characters + public void IsValidPackageId_Restricted_NonAsciiIds_ReturnsFalse(string packageId) + { + // Act + bool result = PackageIdValidator.IsValidPackageId(packageId, useRestrictedCharacterSet: true); + + // Assert + Assert.False(result, $"Expected '{packageId}' to be an invalid restricted package ID."); + } + + [Fact] + public void IsValidPackageId_Restricted_ExceedsMaxLength_ReturnsFalse() + { + // Arrange + string packageId = new string('A', 101); + + // Act + bool result = PackageIdValidator.IsValidPackageId(packageId, useRestrictedCharacterSet: true); + + // Assert + Assert.False(result); + } + + [Fact] + public void IsValidPackageId_Restricted_ExactMaxLength_ReturnsTrue() + { + // Arrange + string packageId = "A" + new string('b', 99); + + // Act + bool result = PackageIdValidator.IsValidPackageId(packageId, useRestrictedCharacterSet: true); + + // Assert + Assert.True(result); + } } }